View Javadoc

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