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