001 /**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements. See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.camel.spring.xml;
019
020 import org.apache.camel.builder.xml.XPathBuilder;
021 import org.apache.camel.spring.CamelBeanPostProcessor;
022 import org.apache.camel.spring.CamelContextFactoryBean;
023 import org.apache.camel.spring.EndpointFactoryBean;
024 import org.apache.camel.util.ObjectHelper;
025 import static org.apache.camel.util.ObjectHelper.isNotNullAndNonEmpty;
026 import org.springframework.beans.factory.config.BeanDefinition;
027 import org.springframework.beans.factory.config.RuntimeBeanReference;
028 import org.springframework.beans.factory.parsing.BeanComponentDefinition;
029 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
030 import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
031 import org.springframework.beans.factory.xml.ParserContext;
032 import org.springframework.util.xml.DomUtils;
033 import org.w3c.dom.Element;
034 import org.w3c.dom.Node;
035 import org.w3c.dom.NodeList;
036
037 import java.util.HashSet;
038 import java.util.Set;
039
040 public class CamelNamespaceHandler extends NamespaceHandlerSupport {
041 protected CamelBeanDefinitionParser routesParser = new CamelBeanDefinitionParser(this);
042 protected BeanDefinitionParser endpointParser = new BeanDefinitionParser(EndpointFactoryBean.class);
043 protected BeanDefinitionParser beanPostProcessorParser = new BeanDefinitionParser(CamelBeanPostProcessor.class);
044 protected Set<String> parserElementNames = new HashSet<String>();
045
046 public void init() {
047 registerParser("routes", routesParser);
048 registerParser("routeBuilder", routesParser);
049 registerParser("endpoint", endpointParser);
050
051 registerParser("camelContext", new BeanDefinitionParser(CamelContextFactoryBean.class) {
052 @Override
053 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
054 super.doParse(element, parserContext, builder);
055
056 String contextId = element.getAttribute("id");
057
058 // lets avoid folks having to explicitly give an ID to a camel context
059 if (ObjectHelper.isNullOrBlank(contextId)) {
060 contextId = "camelContext";
061 element.setAttribute("id", contextId);
062 }
063
064 Element routes = element.getOwnerDocument().createElement("routes");
065 // now lets move all the content there...
066 NodeList list = element.getChildNodes();
067 for (int size = list.getLength(), i = 0; i < size; i++) {
068 Node child = list.item(i);
069 if (child instanceof Element) {
070 Element childElement = (Element) child;
071 if (child.getLocalName().equals("beanPostProcessor")) {
072 String beanPostProcessorId = contextId + ":beanPostProcessor";
073 childElement.setAttribute("id", beanPostProcessorId);
074 BeanDefinition definition = beanPostProcessorParser.parse(childElement, parserContext);
075 definition.getPropertyValues().addPropertyValue("camelContext", new RuntimeBeanReference(contextId));
076 }
077 else {
078 element.removeChild(child);
079 routes.appendChild(child);
080 }
081 }
082 }
083 String routeId = contextId + ":routes";
084 routes.setAttribute("id", routeId);
085
086 BeanDefinition definition = routesParser.parse(routes, parserContext);
087 definition.getPropertyValues().addPropertyValue("context", new RuntimeBeanReference(contextId));
088 parserContext.registerComponent(new BeanComponentDefinition(definition, routeId));
089
090 list = routes.getElementsByTagName("endpoint");
091 for (int size = list.getLength(), i = 0; i < size; i++) {
092 Element node = (Element) list.item(i);
093 definition = endpointParser.parse(node, parserContext);
094 String id = node.getAttribute("id");
095 if (isNotNullAndNonEmpty(id)) {
096 definition.getPropertyValues().addPropertyValue("context", new RuntimeBeanReference(contextId));
097 //definition.getPropertyValues().addPropertyValue("context", builder.getBeanDefinition());
098 parserContext.registerComponent(new BeanComponentDefinition(definition, id));
099 }
100 }
101 }
102 });
103
104 registerParser("xpath", new BeanDefinitionParser(XPathBuilder.class) {
105 @Override
106 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
107 // lets create a child context
108 String xpath = DomUtils.getTextValue(element);
109 builder.addConstructorArg(xpath);
110 super.doParse(element, parserContext, builder);
111 builder.addPropertyValue("namespacesFromDom", element);
112 }
113 });
114
115 // scripting expressions
116 registerScriptParser("script", null);
117 registerScriptParser("groovy", "groovy");
118 registerScriptParser("ruby", "jruby");
119 registerScriptParser("javaScript", "js");
120 registerScriptParser("python", "python");
121 registerScriptParser("php", "php");
122 }
123
124 protected void registerScriptParser(String elementName, String engineName) {
125 registerParser(elementName, new ScriptDefinitionParser(engineName));
126 }
127
128 protected void registerParser(String name, org.springframework.beans.factory.xml.BeanDefinitionParser parser) {
129 parserElementNames.add(name);
130 registerBeanDefinitionParser(name, parser);
131 }
132
133 public Set<String> getParserElementNames() {
134 return parserElementNames;
135 }
136 }