View Javadoc

1   /*
2    * $Id: MuleBeanDefinitionReader.java 8676 2007-09-27 18:22:00Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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  
11  package org.mule.extras.spring.config;
12  
13  import java.io.IOException;
14  
15  import javax.xml.transform.Source;
16  import javax.xml.transform.Transformer;
17  import javax.xml.transform.TransformerConfigurationException;
18  import javax.xml.transform.TransformerException;
19  import javax.xml.transform.TransformerFactory;
20  import javax.xml.transform.dom.DOMResult;
21  import javax.xml.transform.dom.DOMSource;
22  import javax.xml.transform.stream.StreamSource;
23  
24  import org.dom4j.io.DOMReader;
25  import org.mule.config.MuleDtdResolver;
26  import org.mule.umo.transformer.UMOTransformer;
27  import org.springframework.beans.BeansException;
28  import org.springframework.beans.FatalBeanException;
29  import org.springframework.beans.factory.support.BeanDefinitionRegistry;
30  import org.springframework.beans.factory.support.DefaultListableBeanFactory;
31  import org.springframework.beans.factory.xml.DelegatingEntityResolver;
32  import org.springframework.beans.factory.xml.ResourceEntityResolver;
33  import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
34  import org.springframework.core.io.ClassPathResource;
35  import org.springframework.core.io.Resource;
36  import org.springframework.util.ClassUtils;
37  import org.springframework.util.xml.XmlValidationModeDetector;
38  import org.w3c.dom.Document;
39  import org.xml.sax.EntityResolver;
40  
41  /**
42   * <code>MuleBeanDefinitionReader</code> Is a custom Spring Bean reader that will
43   * apply a transformation to Mule Xml configuration files before loading bean
44   * definitions allowing Mule Xml config to be parsed as Spring configuration.
45   */
46  public class MuleBeanDefinitionReader extends XmlBeanDefinitionReader
47  {
48      private int contextCount = 0;
49      private int configCount = 0;
50      private MuleDtdResolver dtdResolver = null;
51  
52      public MuleBeanDefinitionReader(BeanDefinitionRegistry beanDefinitionRegistry, int configCount)
53      {
54          super(beanDefinitionRegistry);
55  
56          setDocumentReaderClass(MuleBeanDefinitionDocumentReader.class);
57          setResourceLoader(new MuleResourceLoader());
58          // use spring 2.x's capability to autodetect whether DTD or XSD is used in the config files
59          setValidationMode(XmlValidationModeDetector.VALIDATION_AUTO);
60          setEntityResolver(createEntityResolver());
61          this.configCount = configCount;
62          
63          // TransformerEditor is used to convert Transformer names into transformer Objects.
64          ((DefaultListableBeanFactory)beanDefinitionRegistry).registerCustomEditor(UMOTransformer.class,
65              new TransformerEditor());
66      }
67  
68      public int registerBeanDefinitions(Document document, Resource resource) throws BeansException
69      {
70          try
71          {
72              Document newDocument = transformDocument(document);
73              return super.registerBeanDefinitions(newDocument, resource);
74          }
75          catch (Exception e)
76          {
77              throw new FatalBeanException("Failed to read config resource: " + resource, e);
78          }
79          finally
80          {
81              incConfigCount();
82          }
83      }
84  
85      public static Transformer createTransformer(Source source) throws TransformerConfigurationException
86      {
87          TransformerFactory factory = TransformerFactory.newInstance();
88          Transformer transformer = factory.newTransformer(source);
89          return transformer;
90      }
91  
92      protected Document transformDocument(Document document) throws IOException, TransformerException
93      {
94          if (getXslResource() != null)
95          {
96              Transformer transformer = createTransformer(createXslSource());
97              DOMResult result = new DOMResult();
98              transformer.setParameter("firstContext", Boolean.valueOf(isFirstContext()));
99              transformer.transform(new DOMSource(document), result);
100             if (logger.isDebugEnabled())
101             {
102                 try
103                 {
104                     String xml = new DOMReader().read((Document)result.getNode()).asXML();
105                     if (logger.isDebugEnabled())
106                     {
107                         logger.debug("Transformed document is:\n" + xml);
108                     }
109                 }
110                 catch (Exception e)
111                 {
112                     e.printStackTrace();
113                 }
114             }
115             return (Document)result.getNode();
116         }
117         else
118         {
119             return document;
120         }
121 
122     }
123 
124     protected Source createXslSource() throws IOException
125     {
126         return new StreamSource(getXslResource().getInputStream(), getXslResource().getURL().toString());
127     }
128 
129     protected ClassPathResource getXslResource()
130     {
131         String xsl = dtdResolver.getXslForDtd();
132         if (xsl != null)
133         {
134             return new ClassPathResource(xsl);
135         }
136         else
137         {
138             return null;
139         }
140     }
141 
142     protected EntityResolver createEntityResolver()
143     {
144         if (dtdResolver == null)
145         {
146             MuleDtdResolver muleSpringResolver = new MuleDtdResolver("mule-spring-configuration.dtd",
147                 "mule-to-spring.xsl", this.createSpringEntityResolver());
148             dtdResolver = new MuleDtdResolver("mule-configuration.dtd", "mule-to-spring.xsl",
149                 muleSpringResolver);
150         }
151         return dtdResolver;
152     }
153 
154     /**
155 	 * Creates an {@link EntityResolver} the same way Spring's
156 	 * {@link XmlBeanDefinitionReader} would create it. It has to be created
157 	 * here because the {@link EntityResolver} created by
158 	 * {@link XmlBeanDefinitionReader} is not accessible from this class.
159 	 * 
160 	 * @return
161 	 * @see XmlBeanDefinitionReader#XmlBeanDefinitionReader(BeanDefinitionRegistry)
162 	 */
163     protected EntityResolver createSpringEntityResolver()
164     {
165         EntityResolver springEntityResolver = null;
166         // Determine EntityResolver to use.
167         if (getResourceLoader() != null) 
168         {
169             springEntityResolver = new ResourceEntityResolver(getResourceLoader());
170         }
171         else 
172         {
173             springEntityResolver = new DelegatingEntityResolver(ClassUtils.getDefaultClassLoader());
174         }
175         return springEntityResolver;
176     }
177 
178     public boolean isFirstContext()
179     {
180         return contextCount == 0;
181     }
182 
183     private void incConfigCount()
184     {
185         contextCount++;
186         if (contextCount >= configCount)
187         {
188             contextCount = 0;
189         }
190     }
191 }