View Javadoc

1   /*
2    * $Id: WebappMuleXmlConfigurationBuilder.java 11600 2008-04-18 18:13:47Z dfeist $
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.config.builders;
12  
13  import org.mule.api.MuleContext;
14  import org.mule.api.config.ConfigurationException;
15  import org.mule.api.registry.Registry;
16  import org.mule.config.ConfigResource;
17  import org.mule.config.spring.MuleApplicationContext;
18  import org.mule.config.spring.SpringXmlConfigurationBuilder;
19  
20  import java.io.FileNotFoundException;
21  import java.io.IOException;
22  import java.io.InputStream;
23  
24  import javax.servlet.ServletContext;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.springframework.beans.BeansException;
29  import org.springframework.beans.factory.access.BeanFactoryLocator;
30  import org.springframework.context.ApplicationContext;
31  import org.springframework.context.ApplicationContextException;
32  import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
33  import org.springframework.core.io.AbstractResource;
34  import org.springframework.core.io.ClassPathResource;
35  import org.springframework.core.io.Resource;
36  import org.springframework.util.Assert;
37  import org.springframework.util.ClassUtils;
38  import org.springframework.util.StringUtils;
39  import org.springframework.web.context.ContextLoader;
40  import org.springframework.web.context.support.ServletContextResource;
41  
42  /**
43   * <code>WebappMuleXmlConfigurationBuilder</code> will first try and load config
44   * resources using the ServletContext and if this fails then it will attempt to load
45   * config resource from the classpath.
46   * <li> ServletContext resources should be relative to the webapp root directory and
47   * start with '/'.
48   * <li> Classpath resources should be in the webapp classpath and should not start
49   * with '/'.
50   * 
51   * @see org.mule.config.builders.SpringXmlConfigurationBuilder
52   */
53  public class WebappMuleXmlConfigurationBuilder extends SpringXmlConfigurationBuilder
54  {
55  
56      /**
57       * Logger used by this class
58       */
59      protected transient final Log logger = LogFactory.getLog(getClass());
60  
61      private ServletContext context;
62  
63      public WebappMuleXmlConfigurationBuilder(ServletContext servletContext, String configResources)
64          throws ConfigurationException
65      {
66          super(configResources);
67          context = servletContext;
68      }
69  
70      public WebappMuleXmlConfigurationBuilder(ServletContext servletContext, String[] configResources)
71          throws ConfigurationException
72      {
73          super(configResources);
74          context = servletContext;
75      }
76  
77      protected ConfigResource[] loadConfigResources(String[] configs) throws ConfigurationException
78      {
79          try
80          {
81              configResources = new ConfigResource[configs.length];
82              for (int i = 0; i < configs.length; i++)
83              {
84                  configResources[i] = new ServletContextOrClassPathConfigResource(configs[i]);
85              }
86              return configResources;
87          }
88          catch (IOException e)
89          {
90              throw new ConfigurationException(e);
91          }
92      }
93  
94      protected void createSpringParentRegistry(MuleContext muleContext, Registry registry, ConfigResource[] all)
95      {
96          Resource[] servletContextResources = new Resource[all.length];
97          for (int i = 0; i < all.length; i++)
98          {
99              servletContextResources[i] = new ServletContextOrClassPathResource(context, all[i].getResourceName());
100         }
101 
102         parentContext = loadParentContext(context);
103 
104         try
105         {
106             if (parentContext != null)
107             {
108                 new MuleApplicationContext(muleContext, registry, servletContextResources, parentContext);
109             }
110             else
111             {
112                 new MuleApplicationContext(muleContext, registry, servletContextResources);
113             }
114         }
115         catch (BeansException e)
116         {
117             // If creation of MuleApplicationContext fails, remove
118             // TransientRegistry->SpringRegistry parent relationship
119             registry.setParent(null);
120             throw e;
121         }
122         catch (IOException e)
123         {
124             registry.setParent(null);
125             throw new ApplicationContextException("Failed to load config resource", e);
126         }
127     }
128 
129     /**
130      * Used to lookup parent spring ApplicationContext. This allows a parent spring
131      * ApplicatonContet to be provided in the same way you would configure a parent
132      * ApplicationContext for a spring WebAppplicationContext
133      * 
134      * @param servletContext
135      * @return
136      * @throws BeansException
137      */
138     protected ApplicationContext loadParentContext(ServletContext servletContext) throws BeansException
139     {
140 
141         ApplicationContext parentContext = null;
142         String locatorFactorySelector = servletContext.getInitParameter(ContextLoader.LOCATOR_FACTORY_SELECTOR_PARAM);
143         String parentContextKey = servletContext.getInitParameter(ContextLoader.LOCATOR_FACTORY_KEY_PARAM);
144 
145         if (parentContextKey != null)
146         {
147             // locatorFactorySelector may be null, indicating the default
148             // "classpath*:beanRefContext.xml"
149             BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
150             if (logger.isDebugEnabled())
151             {
152                 logger.debug("Getting parent context definition: using parent context key of '" + parentContextKey
153                              + "' with BeanFactoryLocator");
154             }
155             parentContext = (ApplicationContext) locator.useBeanFactory(parentContextKey).getFactory();
156         }
157 
158         return parentContext;
159     }
160 
161     class ServletContextOrClassPathConfigResource extends ConfigResource
162     {
163         public ServletContextOrClassPathConfigResource(String resourceName) throws IOException
164         {
165             super(resourceName, null);
166         }
167 
168     }
169 
170     /**
171      * Combines {@link ServletContextResource} and {@link ClassPathResource} to
172      * create a {@link Resource} implementation that first tries to load a resource
173      * using the {@link ServletContext} and then fails back to use try to load the
174      * resource from the classpath.
175      */
176     class ServletContextOrClassPathResource extends AbstractResource
177     {
178 
179         private final ServletContext servletContext;
180 
181         private final String path;
182 
183         public ServletContextOrClassPathResource(ServletContext servletContext, String path)
184         {
185             Assert.notNull(servletContext, "Cannot resolve ServletContextResource without ServletContext");
186             this.servletContext = servletContext;
187             // check path
188             Assert.notNull(path, "path is required");
189             this.path = StringUtils.cleanPath(path);
190         }
191 
192         public InputStream getInputStream() throws IOException
193         {
194             InputStream is = getServletContextInputStream();
195             if (is == null)
196             {
197                 is = getClasspathInputStream();
198             }
199             if (is == null)
200             {
201                 throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
202             }
203             return is;
204         }
205 
206         protected InputStream getServletContextInputStream()
207         {
208             String servletContextPath = path;
209             if (!servletContextPath.startsWith("/"))
210             {
211                 servletContextPath = "/" + servletContextPath;
212             }
213             return servletContext.getResourceAsStream(servletContextPath);
214         }
215 
216         protected InputStream getClasspathInputStream()
217         {
218             String classpathPath = path;
219             if (classpathPath.startsWith("/"))
220             {
221                 classpathPath = classpathPath.substring(1);
222             }
223             return ClassUtils.getDefaultClassLoader().getResourceAsStream(classpathPath);
224         }
225 
226         public String getDescription()
227         {
228             return path;
229         }
230     }
231 }