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 }