View Javadoc

1   /*
2    * $Id: AbstractMuleNamespaceHandler.java 23047 2011-09-29 22:40:05Z mike.schilling $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  package org.mule.config.spring.handlers;
11  
12  import org.mule.config.spring.MuleHierarchicalBeanDefinitionParserDelegate;
13  import org.mule.config.spring.factories.InboundEndpointFactoryBean;
14  import org.mule.config.spring.factories.OutboundEndpointFactoryBean;
15  import org.mule.config.spring.parsers.AbstractChildDefinitionParser;
16  import org.mule.config.spring.parsers.MuleDefinitionParser;
17  import org.mule.config.spring.parsers.MuleDefinitionParserConfiguration;
18  import org.mule.config.spring.parsers.PostProcessor;
19  import org.mule.config.spring.parsers.PreProcessor;
20  import org.mule.config.spring.parsers.assembly.BeanAssembler;
21  import org.mule.config.spring.parsers.assembly.DefaultBeanAssembler;
22  import org.mule.config.spring.parsers.assembly.configuration.ValueMap;
23  import org.mule.config.spring.parsers.generic.MuleOrphanDefinitionParser;
24  import org.mule.config.spring.parsers.specific.endpoint.TransportEndpointDefinitionParser;
25  import org.mule.config.spring.parsers.specific.endpoint.TransportGlobalEndpointDefinitionParser;
26  import org.mule.config.spring.parsers.specific.endpoint.support.AddressedEndpointDefinitionParser;
27  import org.mule.endpoint.EndpointURIEndpointBuilder;
28  
29  import javax.xml.namespace.QName;
30  import java.io.InputStream;
31  import java.util.HashSet;
32  import java.util.Iterator;
33  import java.util.Map;
34  import java.util.Properties;
35  import java.util.Set;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.mule.util.IOUtils;
40  import org.springframework.beans.factory.config.BeanDefinition;
41  import org.springframework.beans.factory.support.AbstractBeanDefinition;
42  import org.springframework.beans.factory.xml.BeanDefinitionParser;
43  import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
44  import org.springframework.beans.factory.xml.ParserContext;
45  import org.w3c.dom.Element;
46  import org.w3c.dom.Node;
47  
48  
49  /**
50   * This Namespace handler extends the default Spring {@link org.springframework.beans.factory.xml.NamespaceHandlerSupport}
51   * to allow certain elements in document to be ignored by the handler.
52   */
53  public abstract class AbstractMuleNamespaceHandler extends NamespaceHandlerSupport
54  {
55      public static final String GLOBAL_ENDPOINT = "endpoint";
56      public static final String INBOUND_ENDPOINT = "inbound-endpoint";
57      public static final String OUTBOUND_ENDPOINT = "outbound-endpoint"; 
58  
59      protected transient final Log logger = LogFactory.getLog(getClass());
60  
61      protected AbstractMuleNamespaceHandler()
62      {
63          registerBeanDefinitionParser("annotations", new AnnotationsBeanDefintionParser());
64      }
65  
66      /**
67       * @param name The name of the element to be ignored.
68       */
69      protected final void registerIgnoredElement(String name)
70      {
71          registerBeanDefinitionParser(name, new IgnoredDefinitionParser());
72      }
73  
74      protected MuleDefinitionParserConfiguration registerConnectorDefinitionParser(Class connectorClass, String transportName)
75      {
76          return registerConnectorDefinitionParser(findConnectorClass(connectorClass, transportName));
77      }
78  
79      protected MuleDefinitionParserConfiguration registerConnectorDefinitionParser(Class connectorClass)
80      {
81          return registerConnectorDefinitionParser( new MuleOrphanDefinitionParser(connectorClass, true));
82      }
83  
84      protected MuleDefinitionParserConfiguration registerConnectorDefinitionParser(MuleDefinitionParser parser)
85      {
86          registerBeanDefinitionParser("connector", parser);
87          return parser;
88      }
89  
90      protected MuleDefinitionParserConfiguration registerMuleBeanDefinitionParser(String name, MuleDefinitionParser parser)
91      {
92          registerBeanDefinitionParser(name, parser);
93          return parser;
94      }
95  
96      protected MuleDefinitionParserConfiguration registerStandardTransportEndpoints(String protocol, String[] requiredAttributes)
97      {
98          return new RegisteredMdps(protocol, AddressedEndpointDefinitionParser.PROTOCOL, requiredAttributes);
99      }
100 
101     protected MuleDefinitionParserConfiguration registerMetaTransportEndpoints(String protocol)
102     {
103         return new RegisteredMdps(protocol, AddressedEndpointDefinitionParser.META, new String[]{});
104     }
105 
106     private static class IgnoredDefinitionParser implements BeanDefinitionParser
107     {
108         public IgnoredDefinitionParser()
109         {
110             super();
111         }
112         
113         public BeanDefinition parse(Element element, ParserContext parserContext)
114         {
115             return null;
116         }
117     }
118 
119     protected Class getInboundEndpointFactoryBeanClass()
120     {
121         return InboundEndpointFactoryBean.class;
122     }
123 
124     protected Class getOutboundEndpointFactoryBeanClass()
125     {
126         return OutboundEndpointFactoryBean.class;
127     }
128 
129     protected Class getGlobalEndpointBuilderBeanClass()
130     {
131         return EndpointURIEndpointBuilder.class;
132     }
133 
134     private class RegisteredMdps implements MuleDefinitionParserConfiguration
135     {
136         private Set bdps = new HashSet();
137 
138         public RegisteredMdps(String protocol, boolean isMeta, String[] requiredAttributes)
139         {
140             registerBeanDefinitionParser("endpoint", add(new TransportGlobalEndpointDefinitionParser(protocol, isMeta, AbstractMuleNamespaceHandler.this.getGlobalEndpointBuilderBeanClass(), requiredAttributes, new String[]{})));
141             registerBeanDefinitionParser("inbound-endpoint", add(new TransportEndpointDefinitionParser(protocol, isMeta, AbstractMuleNamespaceHandler.this.getInboundEndpointFactoryBeanClass(), requiredAttributes, new String[]{})));
142             registerBeanDefinitionParser("outbound-endpoint", add(new TransportEndpointDefinitionParser(protocol, isMeta, AbstractMuleNamespaceHandler.this.getOutboundEndpointFactoryBeanClass(), requiredAttributes, new String[]{})));
143         }
144 
145         private MuleDefinitionParser add(MuleDefinitionParser bdp)
146         {
147             bdps.add(bdp);
148             return bdp;
149         }
150 
151         public MuleDefinitionParserConfiguration registerPreProcessor(PreProcessor preProcessor)
152         {
153             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
154             {
155                 ((MuleDefinitionParserConfiguration) bdp.next()).registerPreProcessor(preProcessor);
156             }
157             return this;
158         }
159 
160         public MuleDefinitionParserConfiguration registerPostProcessor(PostProcessor postProcessor)
161         {
162             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
163             {
164                 ((MuleDefinitionParserConfiguration) bdp.next()).registerPostProcessor(postProcessor);
165             }
166             return this;
167         }
168 
169         public MuleDefinitionParserConfiguration addReference(String propertyName)
170         {
171             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
172             {
173                 ((MuleDefinitionParserConfiguration) bdp.next()).addReference(propertyName);
174             }
175             return this;
176         }
177 
178         public MuleDefinitionParserConfiguration addMapping(String propertyName, Map mappings)
179         {
180             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
181             {
182                 ((MuleDefinitionParserConfiguration) bdp.next()).addMapping(propertyName, mappings);
183             }
184             return this;
185         }
186 
187         public MuleDefinitionParserConfiguration addMapping(String propertyName, String mappings)
188         {
189             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
190             {
191                 ((MuleDefinitionParserConfiguration) bdp.next()).addMapping(propertyName, mappings);
192             }
193             return this;
194         }
195 
196         public MuleDefinitionParserConfiguration addMapping(String propertyName, ValueMap mappings)
197         {
198             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
199             {
200                 ((MuleDefinitionParserConfiguration) bdp.next()).addMapping(propertyName, mappings);
201             }
202             return this;
203         }
204 
205         public MuleDefinitionParserConfiguration addAlias(String alias, String propertyName)
206         {
207             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
208             {
209                 ((MuleDefinitionParserConfiguration) bdp.next()).addAlias(alias, propertyName);
210             }
211             return this;
212         }
213 
214         public MuleDefinitionParserConfiguration addCollection(String propertyName)
215         {
216             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
217             {
218                 ((MuleDefinitionParserConfiguration) bdp.next()).addCollection(propertyName);
219             }
220             return this;
221         }
222 
223         public MuleDefinitionParserConfiguration addIgnored(String propertyName)
224         {
225             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
226             {
227                 ((MuleDefinitionParserConfiguration) bdp.next()).addIgnored(propertyName);
228             }
229             return this;
230         }
231 
232         public MuleDefinitionParserConfiguration removeIgnored(String propertyName)
233         {
234             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
235             {
236                 ((MuleDefinitionParserConfiguration) bdp.next()).removeIgnored(propertyName);
237             }
238             return this;
239         }
240 
241         public MuleDefinitionParserConfiguration setIgnoredDefault(boolean ignoreAll)
242         {
243             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
244             {
245                 ((MuleDefinitionParserConfiguration) bdp.next()).setIgnoredDefault(ignoreAll);
246             }
247             return this;
248         }
249 
250         public MuleDefinitionParserConfiguration addBeanFlag(String flag)
251         {
252             for (Iterator bdp = bdps.iterator(); bdp.hasNext();)
253             {
254                 ((MuleDefinitionParserConfiguration) bdp.next()).addBeanFlag(flag);
255             }
256             return this;
257         }
258     }
259     
260     /**
261      * Subclasses can call this to register the supplied {@link BeanDefinitionParser} to
262      * handle the specified element. The element name is the local (non-namespace qualified)
263      * name.
264      */
265     protected void registerDeprecatedBeanDefinitionParser(String elementName, BeanDefinitionParser parser, String deprecationWarning) 
266     {
267         if (parser instanceof MuleDefinitionParserConfiguration)
268         {
269             ((MuleDefinitionParser) parser).setDeprecationWarning(deprecationWarning);
270         }
271         registerBeanDefinitionParser(elementName, parser);
272     }
273 
274     static class AnnotationsBeanDefintionParser extends AbstractChildDefinitionParser
275     {
276         AnnotationsBeanDefintionParser()
277         {
278             ;
279         }
280 
281         @Override
282         protected AbstractBeanDefinition parseInternal(Element element, ParserContext context)
283         {
284             AbstractBeanDefinition beanDef = super.parseInternal(element, context);
285             beanDef.setAttribute(MuleHierarchicalBeanDefinitionParserDelegate.MULE_NO_RECURSE, true);
286             beanDef.setAttribute(MuleHierarchicalBeanDefinitionParserDelegate.MULE_NO_REGISTRATION, true);
287             return beanDef;
288         }
289 
290         @Override
291         public String getPropertyName(Element element)
292         {
293             return "annotation";
294         }
295 
296         @Override
297         protected Class<?> getBeanClass(Element element)
298         {
299             return Map.class;
300         }
301 
302         @Override
303         protected void postProcess(ParserContext context, BeanAssembler beanAssembler, Element element)
304         {
305             if (beanAssembler instanceof DefaultBeanAssembler)
306             {
307                 DefaultBeanAssembler assembler = (DefaultBeanAssembler) beanAssembler;
308 
309                 if (assembler.isAnnotationsPropertyAvailable(assembler.getTarget().getBeanClassName()))
310                 {
311                     for (Node node = element.getFirstChild(); node != null; node = node.getNextSibling())
312                     {
313                         if (node.getNodeType() == Node.ELEMENT_NODE)
314                         {
315                             StringBuilder builder = new StringBuilder();
316                             for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling())
317                             {
318                                 switch (child.getNodeType())
319                                 {
320                                     case Node.TEXT_NODE:
321                                     case Node.CDATA_SECTION_NODE:
322                                         builder.append(child.getNodeValue());
323                                 }
324                             }
325                             assembler.addAnnotationValue(context.getContainingBeanDefinition().getPropertyValues(),
326                                                          new QName(node.getNamespaceURI(), node.getLocalName()),
327                                                          builder.toString());
328                         }
329                     }
330                 }
331             }
332         }
333     }
334 
335     /**
336      * See if there's a preferred connector class
337      */
338     protected Class findConnectorClass(Class basicConnector, String transportName)
339     {
340         String preferredPropertiesURL = "META-INF/services/org/mule/transport/preferred-" +transportName + ".properties";
341         InputStream stream = AbstractMuleNamespaceHandler.class.getClassLoader().getResourceAsStream(preferredPropertiesURL);
342         if (stream != null)
343         {
344             try
345             {
346                 Properties preferredProperties = new Properties();
347                 preferredProperties.load(stream);
348                 String preferredConnectorName = preferredProperties.getProperty("connector");
349                 if (preferredConnectorName != null)
350                 {
351                     logger.debug("Found preferred connector class " + preferredConnectorName);
352                     return Class.forName(preferredConnectorName);
353                 }
354             }
355             catch (Exception e)
356             {
357                 logger.debug("Error processing preferred properties", e);
358             }
359             finally
360             {
361                 IOUtils.closeQuietly(stream);
362             }
363         }
364         return basicConnector;
365     }
366 }