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