001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.spring.handler;
018
019 import java.lang.reflect.Method;
020 import java.util.HashMap;
021 import java.util.HashSet;
022 import java.util.Map;
023 import java.util.Set;
024
025 import javax.xml.bind.Binder;
026 import javax.xml.bind.JAXBContext;
027 import javax.xml.bind.JAXBException;
028
029 import org.w3c.dom.Document;
030 import org.w3c.dom.Element;
031 import org.w3c.dom.Node;
032 import org.w3c.dom.NodeList;
033
034 import org.apache.camel.builder.xml.Namespaces;
035 import org.apache.camel.core.xml.CamelJMXAgentDefinition;
036 import org.apache.camel.core.xml.CamelPropertyPlaceholderDefinition;
037 import org.apache.camel.impl.DefaultCamelContextNameStrategy;
038 import org.apache.camel.model.FromDefinition;
039 import org.apache.camel.model.SendDefinition;
040 import org.apache.camel.spi.CamelContextNameStrategy;
041 import org.apache.camel.spi.NamespaceAware;
042 import org.apache.camel.spring.CamelBeanPostProcessor;
043 import org.apache.camel.spring.CamelConsumerTemplateFactoryBean;
044 import org.apache.camel.spring.CamelContextFactoryBean;
045 import org.apache.camel.spring.CamelEndpointFactoryBean;
046 import org.apache.camel.spring.CamelProducerTemplateFactoryBean;
047 import org.apache.camel.spring.CamelRedeliveryPolicyFactoryBean;
048 import org.apache.camel.spring.CamelRouteContextFactoryBean;
049 import org.apache.camel.spring.CamelThreadPoolFactoryBean;
050 import org.apache.camel.spring.remoting.CamelProxyFactoryBean;
051 import org.apache.camel.spring.remoting.CamelServiceExporter;
052 import org.apache.camel.util.ObjectHelper;
053 import org.apache.camel.util.spring.KeyStoreParametersFactoryBean;
054 import org.apache.camel.util.spring.SSLContextParametersFactoryBean;
055 import org.apache.camel.util.spring.SecureRandomParametersFactoryBean;
056 import org.apache.camel.view.ModelFileGenerator;
057 import org.slf4j.Logger;
058 import org.slf4j.LoggerFactory;
059 import org.springframework.beans.factory.BeanCreationException;
060 import org.springframework.beans.factory.BeanDefinitionStoreException;
061 import org.springframework.beans.factory.config.BeanDefinition;
062 import org.springframework.beans.factory.config.RuntimeBeanReference;
063 import org.springframework.beans.factory.parsing.BeanComponentDefinition;
064 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
065 import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
066 import org.springframework.beans.factory.xml.ParserContext;
067
068
069 /**
070 * Camel namespace for the spring XML configuration file.
071 */
072 public class CamelNamespaceHandler extends NamespaceHandlerSupport {
073 private static final String SPRING_NS = "http://camel.apache.org/schema/spring";
074 private static final Logger LOG = LoggerFactory.getLogger(CamelNamespaceHandler.class);
075 protected BeanDefinitionParser endpointParser = new BeanDefinitionParser(CamelEndpointFactoryBean.class, false);
076 protected BeanDefinitionParser beanPostProcessorParser = new BeanDefinitionParser(CamelBeanPostProcessor.class, false);
077 protected Set<String> parserElementNames = new HashSet<String>();
078 protected Map<String, BeanDefinitionParser> parserMap = new HashMap<String, BeanDefinitionParser>();
079
080 private JAXBContext jaxbContext;
081 private Map<String, BeanDefinition> autoRegisterMap = new HashMap<String, BeanDefinition>();
082
083 public static void renameNamespaceRecursive(Node node) {
084 if (node.getNodeType() == Node.ELEMENT_NODE) {
085 Document doc = node.getOwnerDocument();
086 if (node.getNamespaceURI().startsWith(SPRING_NS + "/v")) {
087 doc.renameNode(node, SPRING_NS, node.getNodeName());
088 }
089 }
090 NodeList list = node.getChildNodes();
091 for (int i = 0; i < list.getLength(); ++i) {
092 renameNamespaceRecursive(list.item(i));
093 }
094 }
095
096 public ModelFileGenerator createModelFileGenerator() throws JAXBException {
097 return new ModelFileGenerator(getJaxbContext());
098 }
099
100 public void init() {
101 // register routeContext parser
102 registerParser("routeContext", new RouteContextDefinitionParser());
103
104 addBeanDefinitionParser("keyStoreParameters", KeyStoreParametersFactoryBean.class, true, true);
105 addBeanDefinitionParser("secureRandomParameters", SecureRandomParametersFactoryBean.class, true, true);
106 registerBeanDefinitionParser("sslContextParameters", new SSLContextParametersFactoryBeanBeanDefinitionParser());
107
108 addBeanDefinitionParser("proxy", CamelProxyFactoryBean.class, true, false);
109 addBeanDefinitionParser("template", CamelProducerTemplateFactoryBean.class, true, false);
110 addBeanDefinitionParser("consumerTemplate", CamelConsumerTemplateFactoryBean.class, true, false);
111 addBeanDefinitionParser("export", CamelServiceExporter.class, true, false);
112 addBeanDefinitionParser("endpoint", CamelEndpointFactoryBean.class, true, false);
113 addBeanDefinitionParser("threadPool", CamelThreadPoolFactoryBean.class, true, true);
114 addBeanDefinitionParser("redeliveryPolicyProfile", CamelRedeliveryPolicyFactoryBean.class, true, true);
115
116 // jmx agent and property placeholder cannot be used outside of the camel context
117 addBeanDefinitionParser("jmxAgent", CamelJMXAgentDefinition.class, false, false);
118 addBeanDefinitionParser("propertyPlaceholder", CamelPropertyPlaceholderDefinition.class, false, false);
119
120 // errorhandler could be the sub element of camelContext or defined outside camelContext
121 BeanDefinitionParser errorHandlerParser = new ErrorHandlerDefinitionParser();
122 registerParser("errorHandler", errorHandlerParser);
123 parserMap.put("errorHandler", errorHandlerParser);
124
125 // camel context
126 boolean osgi = false;
127 Class cl = CamelContextFactoryBean.class;
128 try {
129 Class<?> c = Class.forName("org.apache.camel.osgi.Activator");
130 Method mth = c.getDeclaredMethod("getBundle");
131 Object bundle = mth.invoke(null);
132 if (bundle != null) {
133 cl = Class.forName("org.apache.camel.osgi.CamelContextFactoryBean");
134 osgi = true;
135 }
136 } catch (Throwable t) {
137 // not running with camel-osgi so we fallback to the regular factory bean
138 LOG.trace("Cannot find class so assuming not running in OSGi container: " + t.getMessage());
139 }
140 if (osgi) {
141 LOG.info("OSGi environment detected.");
142 } else {
143 LOG.info("OSGi environment not detected.");
144 }
145 LOG.debug("Using {} as CamelContextBeanDefinitionParser", cl.getCanonicalName());
146 registerParser("camelContext", new CamelContextBeanDefinitionParser(cl));
147 }
148
149 protected void addBeanDefinitionParser(String elementName, Class<?> type, boolean register, boolean assignId) {
150 BeanDefinitionParser parser = new BeanDefinitionParser(type, assignId);
151 if (register) {
152 registerParser(elementName, parser);
153 }
154 parserMap.put(elementName, parser);
155 }
156
157 protected void registerParser(String name, org.springframework.beans.factory.xml.BeanDefinitionParser parser) {
158 parserElementNames.add(name);
159 registerBeanDefinitionParser(name, parser);
160 }
161
162 protected Object parseUsingJaxb(Element element, ParserContext parserContext, Binder<Node> binder) {
163 try {
164 return binder.unmarshal(element);
165 } catch (JAXBException e) {
166 throw new BeanDefinitionStoreException("Failed to parse JAXB element", e);
167 }
168 }
169
170 public JAXBContext getJaxbContext() throws JAXBException {
171 if (jaxbContext == null) {
172 jaxbContext = createJaxbContext();
173 }
174 return jaxbContext;
175 }
176
177 protected JAXBContext createJaxbContext() throws JAXBException {
178 StringBuilder packages = new StringBuilder();
179 for (Class cl : getJaxbPackages()) {
180 if (packages.length() > 0) {
181 packages.append(":");
182 }
183 packages.append(cl.getName().substring(0, cl.getName().lastIndexOf('.')));
184 }
185 return JAXBContext.newInstance(packages.toString(), getClass().getClassLoader());
186 }
187
188 protected Set<Class> getJaxbPackages() {
189 Set<Class> classes = new HashSet<Class>();
190 classes.add(org.apache.camel.spring.CamelContextFactoryBean.class);
191 classes.add(CamelJMXAgentDefinition.class);
192 classes.add(org.apache.camel.ExchangePattern.class);
193 classes.add(org.apache.camel.model.RouteDefinition.class);
194 classes.add(org.apache.camel.model.config.StreamResequencerConfig.class);
195 classes.add(org.apache.camel.model.dataformat.DataFormatsDefinition.class);
196 classes.add(org.apache.camel.model.language.ExpressionDefinition.class);
197 classes.add(org.apache.camel.model.loadbalancer.RoundRobinLoadBalancerDefinition.class);
198 classes.add(org.apache.camel.util.spring.SSLContextParametersFactoryBean.class);
199 return classes;
200 }
201
202 protected class SSLContextParametersFactoryBeanBeanDefinitionParser extends BeanDefinitionParser {
203
204 public SSLContextParametersFactoryBeanBeanDefinitionParser() {
205 super(SSLContextParametersFactoryBean.class, true);
206 }
207
208 @Override
209 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
210 super.doParse(element, builder);
211
212 // Note: prefer to use doParse from parent and postProcess; however, parseUsingJaxb requires
213 // parserContext for no apparent reason.
214 Binder<Node> binder;
215 try {
216 binder = getJaxbContext().createBinder();
217 } catch (JAXBException e) {
218 throw new BeanDefinitionStoreException("Failed to create the JAXB binder", e);
219 }
220
221 Object value = parseUsingJaxb(element, parserContext, binder);
222
223 if (value instanceof SSLContextParametersFactoryBean) {
224 SSLContextParametersFactoryBean bean = (SSLContextParametersFactoryBean)value;
225
226 builder.addPropertyValue("cipherSuites", bean.getCipherSuites());
227 builder.addPropertyValue("cipherSuitesFilter", bean.getCipherSuitesFilter());
228 builder.addPropertyValue("secureSocketProtocols", bean.getSecureSocketProtocols());
229 builder.addPropertyValue("secureSocketProtocolsFilter", bean.getSecureSocketProtocolsFilter());
230 builder.addPropertyValue("keyManagers", bean.getKeyManagers());
231 builder.addPropertyValue("trustManagers", bean.getTrustManagers());
232 builder.addPropertyValue("secureRandom", bean.getSecureRandom());
233
234 builder.addPropertyValue("clientParameters", bean.getClientParameters());
235 builder.addPropertyValue("serverParameters", bean.getServerParameters());
236 } else {
237 throw new BeanDefinitionStoreException("Parsed type is not of the expected type. Expected "
238 + SSLContextParametersFactoryBean.class.getName() + " but found "
239 + value.getClass().getName());
240 }
241 }
242 }
243
244 protected class RouteContextDefinitionParser extends BeanDefinitionParser {
245
246 public RouteContextDefinitionParser() {
247 super(CamelRouteContextFactoryBean.class, false);
248 }
249
250 @Override
251 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
252 renameNamespaceRecursive(element);
253 super.doParse(element, parserContext, builder);
254
255 // now lets parse the routes with JAXB
256 Binder<Node> binder;
257 try {
258 binder = getJaxbContext().createBinder();
259 } catch (JAXBException e) {
260 throw new BeanDefinitionStoreException("Failed to create the JAXB binder", e);
261 }
262 Object value = parseUsingJaxb(element, parserContext, binder);
263
264 if (value instanceof CamelRouteContextFactoryBean) {
265 CamelRouteContextFactoryBean factoryBean = (CamelRouteContextFactoryBean) value;
266 builder.addPropertyValue("routes", factoryBean.getRoutes());
267 }
268
269 // lets inject the namespaces into any namespace aware POJOs
270 injectNamespaces(element, binder);
271 }
272 }
273
274 protected class CamelContextBeanDefinitionParser extends BeanDefinitionParser {
275
276 public CamelContextBeanDefinitionParser(Class type) {
277 super(type, false);
278 }
279
280 @Override
281 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
282 renameNamespaceRecursive(element);
283 super.doParse(element, parserContext, builder);
284
285 String contextId = element.getAttribute("id");
286 boolean implicitId = false;
287
288 // lets avoid folks having to explicitly give an ID to a camel context
289 if (ObjectHelper.isEmpty(contextId)) {
290 // if no explicit id was set then use a default auto generated name
291 CamelContextNameStrategy strategy = new DefaultCamelContextNameStrategy();
292 contextId = strategy.getName();
293 element.setAttribute("id", contextId);
294 implicitId = true;
295 }
296
297 // now lets parse the routes with JAXB
298 Binder<Node> binder;
299 try {
300 binder = getJaxbContext().createBinder();
301 } catch (JAXBException e) {
302 throw new BeanDefinitionStoreException("Failed to create the JAXB binder", e);
303 }
304 Object value = parseUsingJaxb(element, parserContext, binder);
305
306 if (value instanceof CamelContextFactoryBean) {
307 // set the property value with the JAXB parsed value
308 CamelContextFactoryBean factoryBean = (CamelContextFactoryBean) value;
309 builder.addPropertyValue("id", contextId);
310 builder.addPropertyValue("implicitId", implicitId);
311 builder.addPropertyValue("routes", factoryBean.getRoutes());
312 builder.addPropertyValue("intercepts", factoryBean.getIntercepts());
313 builder.addPropertyValue("interceptFroms", factoryBean.getInterceptFroms());
314 builder.addPropertyValue("interceptSendToEndpoints", factoryBean.getInterceptSendToEndpoints());
315 builder.addPropertyValue("dataFormats", factoryBean.getDataFormats());
316 builder.addPropertyValue("onCompletions", factoryBean.getOnCompletions());
317 builder.addPropertyValue("onExceptions", factoryBean.getOnExceptions());
318 builder.addPropertyValue("builderRefs", factoryBean.getBuilderRefs());
319 builder.addPropertyValue("routeRefs", factoryBean.getRouteRefs());
320 builder.addPropertyValue("properties", factoryBean.getProperties());
321 builder.addPropertyValue("packageScan", factoryBean.getPackageScan());
322 builder.addPropertyValue("contextScan", factoryBean.getContextScan());
323 if (factoryBean.getPackages().length > 0) {
324 builder.addPropertyValue("packages", factoryBean.getPackages());
325 }
326 builder.addPropertyValue("camelPropertyPlaceholder", factoryBean.getCamelPropertyPlaceholder());
327 builder.addPropertyValue("camelJMXAgent", factoryBean.getCamelJMXAgent());
328 builder.addPropertyValue("threadPoolProfiles", factoryBean.getThreadPoolProfiles());
329 // add any depends-on
330 addDependsOn(factoryBean, builder);
331 }
332
333 NodeList list = element.getChildNodes();
334 int size = list.getLength();
335 for (int i = 0; i < size; i++) {
336 Node child = list.item(i);
337 if (child instanceof Element) {
338 Element childElement = (Element) child;
339 String localName = child.getLocalName();
340 if (localName.equals("endpoint")) {
341 registerEndpoint(childElement, parserContext, contextId);
342 } else if (localName.equals("routeBuilder")) {
343 addDependsOnToRouteBuilder(childElement, parserContext, contextId);
344 } else {
345 BeanDefinitionParser parser = parserMap.get(localName);
346 if (parser != null) {
347 BeanDefinition definition = parser.parse(childElement, parserContext);
348 String id = childElement.getAttribute("id");
349 if (ObjectHelper.isNotEmpty(id)) {
350 parserContext.registerComponent(new BeanComponentDefinition(definition, id));
351 // set the templates with the camel context
352 if (localName.equals("template") || localName.equals("consumerTemplate")
353 || localName.equals("proxy") || localName.equals("export")) {
354 // set the camel context
355 definition.getPropertyValues().addPropertyValue("camelContext", new RuntimeBeanReference(contextId));
356 }
357 }
358 }
359 }
360 }
361 }
362
363 // register as endpoint defined indirectly in the routes by from/to types having id explicit set
364 registerEndpointsWithIdsDefinedInFromOrToTypes(element, parserContext, contextId, binder);
365
366 // register templates if not already defined
367 registerTemplates(element, parserContext, contextId);
368
369 // lets inject the namespaces into any namespace aware POJOs
370 injectNamespaces(element, binder);
371
372 // inject bean post processor so we can support @Produce etc.
373 // no bean processor element so lets create it by our self
374 injectBeanPostProcessor(element, parserContext, contextId, builder);
375 }
376 }
377
378 protected void addDependsOn(CamelContextFactoryBean factoryBean, BeanDefinitionBuilder builder) {
379 String dependsOn = factoryBean.getDependsOn();
380 if (ObjectHelper.isNotEmpty(dependsOn)) {
381 // comma, whitespace and semi colon is valid separators in Spring depends-on
382 String[] depends = dependsOn.split(",|;|\\s");
383 if (depends == null) {
384 throw new IllegalArgumentException("Cannot separate depends-on, was: " + dependsOn);
385 } else {
386 for (String depend : depends) {
387 depend = depend.trim();
388 LOG.debug("Adding dependsOn {} to CamelContext({})", depend, factoryBean.getId());
389 builder.addDependsOn(depend);
390 }
391 }
392 }
393 }
394
395 private void addDependsOnToRouteBuilder(Element childElement, ParserContext parserContext, String contextId) {
396 // setting the depends-on explicitly is required since Spring 3.0
397 String routeBuilderName = childElement.getAttribute("ref");
398 if (ObjectHelper.isNotEmpty(routeBuilderName)) {
399 // set depends-on to the context for a routeBuilder bean
400 try {
401 BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(routeBuilderName);
402 Method getDependsOn = definition.getClass().getMethod("getDependsOn", new Class[]{});
403 String[] dependsOn = (String[])getDependsOn.invoke(definition);
404 if (dependsOn == null || dependsOn.length == 0) {
405 dependsOn = new String[]{contextId};
406 } else {
407 String[] temp = new String[dependsOn.length + 1];
408 System.arraycopy(dependsOn, 0, temp, 0, dependsOn.length);
409 temp[dependsOn.length] = contextId;
410 dependsOn = temp;
411 }
412 Method method = definition.getClass().getMethod("setDependsOn", String[].class);
413 method.invoke(definition, (Object)dependsOn);
414 } catch (Exception e) {
415 // Do nothing here
416 }
417 }
418 }
419
420 protected void injectNamespaces(Element element, Binder<Node> binder) {
421 NodeList list = element.getChildNodes();
422 Namespaces namespaces = null;
423 int size = list.getLength();
424 for (int i = 0; i < size; i++) {
425 Node child = list.item(i);
426 if (child instanceof Element) {
427 Element childElement = (Element) child;
428 Object object = binder.getJAXBNode(child);
429 if (object instanceof NamespaceAware) {
430 NamespaceAware namespaceAware = (NamespaceAware) object;
431 if (namespaces == null) {
432 namespaces = new Namespaces(element);
433 }
434 namespaces.configure(namespaceAware);
435 }
436 injectNamespaces(childElement, binder);
437 }
438 }
439 }
440
441 protected void injectBeanPostProcessor(Element element, ParserContext parserContext, String contextId, BeanDefinitionBuilder builder) {
442 Element childElement = element.getOwnerDocument().createElement("beanPostProcessor");
443 element.appendChild(childElement);
444
445 String beanPostProcessorId = contextId + ":beanPostProcessor";
446 childElement.setAttribute("id", beanPostProcessorId);
447 BeanDefinition definition = beanPostProcessorParser.parse(childElement, parserContext);
448 // only register to camel context id as a String. Then we can look it up later
449 // otherwise we get a circular reference in spring and it will not allow custom bean post processing
450 // see more at CAMEL-1663
451 definition.getPropertyValues().addPropertyValue("camelId", contextId);
452 builder.addPropertyReference("beanPostProcessor", beanPostProcessorId);
453 }
454
455 /**
456 * Used for auto registering endpoints from the <tt>from</tt> or <tt>to</tt> DSL if they have an id attribute set
457 */
458 protected void registerEndpointsWithIdsDefinedInFromOrToTypes(Element element, ParserContext parserContext, String contextId, Binder<Node> binder) {
459 NodeList list = element.getChildNodes();
460 int size = list.getLength();
461 for (int i = 0; i < size; i++) {
462 Node child = list.item(i);
463 if (child instanceof Element) {
464 Element childElement = (Element) child;
465 Object object = binder.getJAXBNode(child);
466 // we only want from/to types to be registered as endpoints
467 if (object instanceof FromDefinition || object instanceof SendDefinition) {
468 registerEndpoint(childElement, parserContext, contextId);
469 }
470 // recursive
471 registerEndpointsWithIdsDefinedInFromOrToTypes(childElement, parserContext, contextId, binder);
472 }
473 }
474 }
475
476 /**
477 * Used for auto registering producer and consumer templates if not already defined in XML.
478 */
479 protected void registerTemplates(Element element, ParserContext parserContext, String contextId) {
480 boolean template = false;
481 boolean consumerTemplate = false;
482
483 NodeList list = element.getChildNodes();
484 int size = list.getLength();
485 for (int i = 0; i < size; i++) {
486 Node child = list.item(i);
487 if (child instanceof Element) {
488 Element childElement = (Element) child;
489 String localName = childElement.getLocalName();
490 if ("template".equals(localName)) {
491 template = true;
492 } else if ("consumerTemplate".equals(localName)) {
493 consumerTemplate = true;
494 }
495 }
496 }
497
498 if (!template) {
499 // either we have not used template before or we have auto registered it already and therefore we
500 // need it to allow to do it so it can remove the existing auto registered as there is now a clash id
501 // since we have multiple camel contexts
502 boolean existing = autoRegisterMap.get("template") != null;
503 boolean inUse = false;
504 try {
505 inUse = parserContext.getRegistry().isBeanNameInUse("template");
506 } catch (BeanCreationException e) {
507 // Spring Eclipse Tooling may throw an exception when you edit the Spring XML online in Eclipse
508 // when the isBeanNameInUse method is invoked, so ignore this and continue (CAMEL-2739)
509 LOG.debug("Error checking isBeanNameInUse(template). This exception will be ignored", e);
510 }
511 if (!inUse || existing) {
512 String id = "template";
513 // auto create a template
514 Element templateElement = element.getOwnerDocument().createElement("template");
515 templateElement.setAttribute("id", id);
516 BeanDefinitionParser parser = parserMap.get("template");
517 BeanDefinition definition = parser.parse(templateElement, parserContext);
518
519 // auto register it
520 autoRegisterBeanDefinition(id, definition, parserContext, contextId);
521 }
522 }
523
524 if (!consumerTemplate) {
525 // either we have not used template before or we have auto registered it already and therefore we
526 // need it to allow to do it so it can remove the existing auto registered as there is now a clash id
527 // since we have multiple camel contexts
528 boolean existing = autoRegisterMap.get("consumerTemplate") != null;
529 boolean inUse = false;
530 try {
531 inUse = parserContext.getRegistry().isBeanNameInUse("consumerTemplate");
532 } catch (BeanCreationException e) {
533 // Spring Eclipse Tooling may throw an exception when you edit the Spring XML online in Eclipse
534 // when the isBeanNameInUse method is invoked, so ignore this and continue (CAMEL-2739)
535 LOG.debug("Error checking isBeanNameInUse(consumerTemplate). This exception will be ignored", e);
536 }
537 if (!inUse || existing) {
538 String id = "consumerTemplate";
539 // auto create a template
540 Element templateElement = element.getOwnerDocument().createElement("consumerTemplate");
541 templateElement.setAttribute("id", id);
542 BeanDefinitionParser parser = parserMap.get("consumerTemplate");
543 BeanDefinition definition = parser.parse(templateElement, parserContext);
544
545 // auto register it
546 autoRegisterBeanDefinition(id, definition, parserContext, contextId);
547 }
548 }
549
550 }
551
552 private void autoRegisterBeanDefinition(String id, BeanDefinition definition, ParserContext parserContext, String contextId) {
553 // it is a bit cumbersome to work with the spring bean definition parser
554 // as we kinda need to eagerly register the bean definition on the parser context
555 // and then later we might find out that we should not have done that in case we have multiple camel contexts
556 // that would have a id clash by auto registering the same bean definition with the same id such as a producer template
557
558 // see if we have already auto registered this id
559 BeanDefinition existing = autoRegisterMap.get(id);
560 if (existing == null) {
561 // no then add it to the map and register it
562 autoRegisterMap.put(id, definition);
563 parserContext.registerComponent(new BeanComponentDefinition(definition, id));
564 if (LOG.isDebugEnabled()) {
565 LOG.debug("Registered default: {} with id: {} on camel context: {}", new Object[]{definition.getBeanClassName(), id, contextId});
566 }
567 } else {
568 // ups we have already registered it before with same id, but on another camel context
569 // this is not good so we need to remove all traces of this auto registering.
570 // end user must manually add the needed XML elements and provide unique ids access all camel context himself.
571 LOG.debug("Unregistered default: {} with id: {} as we have multiple camel contexts and they must use unique ids."
572 + " You must define the definition in the XML file manually to avoid id clashes when using multiple camel contexts",
573 definition.getBeanClassName(), id);
574
575 parserContext.getRegistry().removeBeanDefinition(id);
576 }
577 }
578
579 private void registerEndpoint(Element childElement, ParserContext parserContext, String contextId) {
580 String id = childElement.getAttribute("id");
581 // must have an id to be registered
582 if (ObjectHelper.isNotEmpty(id)) {
583 BeanDefinition definition = endpointParser.parse(childElement, parserContext);
584 definition.getPropertyValues().addPropertyValue("camelContext", new RuntimeBeanReference(contextId));
585 // Need to add this dependency of CamelContext for Spring 3.0
586 try {
587 Method method = definition.getClass().getMethod("setDependsOn", String[].class);
588 method.invoke(definition, (Object) new String[]{contextId});
589 } catch (Exception e) {
590 // Do nothing here
591 }
592 parserContext.registerBeanComponent(new BeanComponentDefinition(definition, id));
593 }
594 }
595
596 }