View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.config;
20  
21  import org.apache.myfaces.config.annotation.AnnotationConfigurator;
22  import org.apache.myfaces.config.element.FacesConfig;
23  import org.apache.myfaces.config.impl.digester.DigesterFacesConfigUnmarshallerImpl;
24  import org.apache.myfaces.shared.config.MyfacesConfig;
25  import org.apache.myfaces.shared.util.ClassUtils;
26  import org.apache.myfaces.spi.FacesConfigResourceProvider;
27  import org.apache.myfaces.spi.FacesConfigResourceProviderFactory;
28  import org.apache.myfaces.spi.FacesConfigurationProvider;
29  import org.apache.myfaces.spi.ServiceProviderFinderFactory;
30  import org.xml.sax.SAXException;
31  
32  import javax.faces.FacesException;
33  import javax.faces.FactoryFinder;
34  import javax.faces.context.ExternalContext;
35  import javax.faces.webapp.FacesServlet;
36  import java.io.IOException;
37  import java.io.InputStream;
38  import java.net.URL;
39  import java.net.URLConnection;
40  import java.util.ArrayList;
41  import java.util.Collection;
42  import java.util.HashSet;
43  import java.util.List;
44  import java.util.Set;
45  import java.util.StringTokenizer;
46  import java.util.logging.Level;
47  import java.util.logging.Logger;
48  
49  /**
50   * 
51   * @author Leonardo Uribe
52   * @since 2.0.3
53   */
54  public class DefaultFacesConfigurationProvider extends FacesConfigurationProvider
55  {
56  
57      private static final String STANDARD_FACES_CONFIG_RESOURCE = "META-INF/standard-faces-config.xml";
58      
59      //private static final String META_INF_SERVICES_RESOURCE_PREFIX = "META-INF/services/";
60  
61      private static final String DEFAULT_FACES_CONFIG = "/WEB-INF/faces-config.xml";
62  
63      private static final Set<String> FACTORY_NAMES = new HashSet<String>();
64      {
65          FACTORY_NAMES.add(FactoryFinder.APPLICATION_FACTORY);
66          FACTORY_NAMES.add(FactoryFinder.EXCEPTION_HANDLER_FACTORY);
67          FACTORY_NAMES.add(FactoryFinder.EXTERNAL_CONTEXT_FACTORY);
68          FACTORY_NAMES.add(FactoryFinder.FACES_CONTEXT_FACTORY);
69          FACTORY_NAMES.add(FactoryFinder.LIFECYCLE_FACTORY);
70          FACTORY_NAMES.add(FactoryFinder.RENDER_KIT_FACTORY);
71          FACTORY_NAMES.add(FactoryFinder.TAG_HANDLER_DELEGATE_FACTORY);
72          FACTORY_NAMES.add(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY);
73          FACTORY_NAMES.add(FactoryFinder.VISIT_CONTEXT_FACTORY);
74          FACTORY_NAMES.add(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY);
75      }
76  
77      private static final Logger log = Logger.getLogger(DefaultFacesConfigurationProvider.class.getName());
78  
79      private FacesConfigUnmarshaller<? extends FacesConfig> _unmarshaller;
80      
81      private AnnotationConfigurator _annotationConfigurator;
82  
83      protected void setUnmarshaller(ExternalContext ectx, FacesConfigUnmarshaller<? extends FacesConfig> unmarshaller)
84      {
85          _unmarshaller = unmarshaller;
86      }
87  
88      @SuppressWarnings("unchecked")
89      protected FacesConfigUnmarshaller<? extends FacesConfig> getUnmarshaller(ExternalContext ectx)
90      {
91          if (_unmarshaller == null)
92          {
93              _unmarshaller = new DigesterFacesConfigUnmarshallerImpl(ectx);
94          }
95          return _unmarshaller;
96      }
97      
98      protected void setAnnotationConfigurator(AnnotationConfigurator configurator)
99      {
100         _annotationConfigurator = configurator;
101     }
102     
103     protected AnnotationConfigurator getAnnotationConfigurator()
104     {
105         if (_annotationConfigurator == null)
106         {
107             _annotationConfigurator = new AnnotationConfigurator();
108         }
109         return _annotationConfigurator;
110     }
111 
112     @Override
113     public FacesConfig getStandardFacesConfig(ExternalContext ectx)
114     {
115         try
116         {
117             if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
118             {
119                 URL url = ClassUtils.getResource(STANDARD_FACES_CONFIG_RESOURCE);
120                 if (url != null)
121                 {
122                     validateFacesConfig(ectx, url);
123                 }
124             }
125             InputStream stream = ClassUtils.getResourceAsStream(STANDARD_FACES_CONFIG_RESOURCE);
126             if (stream == null)
127             {
128                 throw new FacesException("Standard faces config " + STANDARD_FACES_CONFIG_RESOURCE + " not found");
129             }
130             if (log.isLoggable(Level.INFO))
131             {
132                 log.info("Reading standard config " + STANDARD_FACES_CONFIG_RESOURCE);
133             }
134             
135             FacesConfig facesConfig = getUnmarshaller(ectx).getFacesConfig(stream, STANDARD_FACES_CONFIG_RESOURCE);
136             stream.close();
137             return facesConfig;
138         }
139         catch (IOException e)
140         {
141             throw new FacesException(e);
142         }
143         catch (SAXException e)
144         {
145             throw new FacesException(e);
146         }
147     }
148 
149     @Override
150     public FacesConfig getAnnotationsFacesConfig(ExternalContext ectx, boolean metadataComplete)
151     {
152         return getAnnotationConfigurator().createFacesConfig(ectx, metadataComplete);
153     }
154 
155     /**
156      * This method performs part of the factory search outlined in section 10.2.6.1.
157      */
158     @Override
159     public FacesConfig getMetaInfServicesFacesConfig(ExternalContext ectx)
160     {
161         try
162         {
163             org.apache.myfaces.config.impl.digester.elements.FacesConfig facesConfig
164                     = new org.apache.myfaces.config.impl.digester.elements.FacesConfig();
165             org.apache.myfaces.config.impl.digester.elements.Factory factory
166                     = new org.apache.myfaces.config.impl.digester.elements.Factory();
167             
168             facesConfig.addFactory(factory);
169             
170             for (String factoryName : FACTORY_NAMES)
171             {
172                 List<String> classList = ServiceProviderFinderFactory.getServiceProviderFinder(ectx)
173                         .getServiceProviderList(factoryName);
174                 
175                 for (String className : classList)
176                 {
177                     if (log.isLoggable(Level.INFO))
178                     {
179                         log.info("Found " + factoryName + " factory implementation: " + className);
180                     }
181 
182                     if (factoryName.equals(FactoryFinder.APPLICATION_FACTORY))
183                     {
184                         factory.addApplicationFactory(className);
185                     } 
186                     else if(factoryName.equals(FactoryFinder.EXCEPTION_HANDLER_FACTORY)) 
187                     {
188                         factory.addExceptionHandlerFactory(className);
189                     } 
190                     else if (factoryName.equals(FactoryFinder.EXTERNAL_CONTEXT_FACTORY))
191                     {
192                         factory.addExternalContextFactory(className);
193                     } 
194                     else if (factoryName.equals(FactoryFinder.FACES_CONTEXT_FACTORY))
195                     {
196                         factory.addFacesContextFactory(className);
197                     } 
198                     else if (factoryName.equals(FactoryFinder.LIFECYCLE_FACTORY))
199                     {
200                         factory.addLifecycleFactory(className);
201                     } 
202                     else if (factoryName.equals(FactoryFinder.RENDER_KIT_FACTORY))
203                     {
204                         factory.addRenderkitFactory(className);
205                     } 
206                     else if(factoryName.equals(FactoryFinder.TAG_HANDLER_DELEGATE_FACTORY)) 
207                     {
208                         factory.addTagHandlerDelegateFactory(className);
209                     } 
210                     else if (factoryName.equals(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY))
211                     {
212                         factory.addPartialViewContextFactory(className);
213                     } 
214                     else if(factoryName.equals(FactoryFinder.VISIT_CONTEXT_FACTORY)) 
215                     {
216                         factory.addVisitContextFactory(className);
217                     } 
218                     else if(factoryName.equals(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY)) 
219                     {
220                         factory.addViewDeclarationLanguageFactory(className);
221                     }
222                     
223                     else
224                     {
225                         throw new IllegalStateException("Unexpected factory name " + factoryName);
226                     }
227                 }
228             }
229             return facesConfig;
230         }
231         catch (Throwable e)
232         {
233             throw new FacesException(e);
234         }
235     }
236 
237     /**
238      * This method fixes MYFACES-208
239      */
240     @Override
241     public List<FacesConfig> getClassloaderFacesConfig(ExternalContext ectx)
242     {
243         List<FacesConfig> appConfigResources = new ArrayList<FacesConfig>();
244         try
245         {
246             FacesConfigResourceProvider provider = FacesConfigResourceProviderFactory.
247                 getFacesConfigResourceProviderFactory(ectx).createFacesConfigResourceProvider(ectx);
248             
249             Collection<URL> facesConfigs = provider.getMetaInfConfigurationResources(ectx);
250             
251             for (URL url : facesConfigs)
252             {
253                 if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
254                 {
255                     validateFacesConfig(ectx, url);
256                 }
257                 InputStream stream = null;
258                 try
259                 {
260                     stream = openStreamWithoutCache(url);
261                     if (log.isLoggable(Level.INFO))
262                     {
263                         log.info("Reading config : " + url.toExternalForm());
264                     }
265                     appConfigResources.add(getUnmarshaller(ectx).getFacesConfig(stream, url.toExternalForm()));
266                     //getDispenser().feed(getUnmarshaller().getFacesConfig(stream, entry.getKey()));
267                 }
268                 finally
269                 {
270                     if (stream != null)
271                     {
272                         stream.close();
273                     }
274                 }
275             }
276         }
277         catch (Throwable e)
278         {
279             throw new FacesException(e);
280         }
281         return appConfigResources;
282     }
283 
284     @Override
285     public List<FacesConfig> getContextSpecifiedFacesConfig(ExternalContext ectx)
286     {
287         List<FacesConfig> appConfigResources = new ArrayList<FacesConfig>();
288         try
289         {
290             for (String systemId : getConfigFilesList(ectx))
291             {
292                 if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
293                 {
294                     URL url = ectx.getResource(systemId);
295                     if (url != null)
296                     {
297                         validateFacesConfig(ectx, url);
298                     }
299                 }            
300                 InputStream stream = ectx.getResourceAsStream(systemId);
301                 if (stream == null)
302                 {
303                     log.severe("Faces config resource " + systemId + " not found");
304                     continue;
305                 }
306     
307                 if (log.isLoggable(Level.INFO))
308                 {
309                     log.info("Reading config " + systemId);
310                 }
311                 appConfigResources.add(getUnmarshaller(ectx).getFacesConfig(stream, systemId));
312                 //getDispenser().feed(getUnmarshaller().getFacesConfig(stream, systemId));
313                 stream.close();
314             }
315         }
316         catch (Throwable e)
317         {
318             throw new FacesException(e);
319         }
320         return appConfigResources;
321     }
322     
323     @Override
324     public FacesConfig getWebAppFacesConfig(ExternalContext ectx)
325     {
326         try
327         {
328             FacesConfig webAppConfig = null;
329             // web application config
330             if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
331             {
332                 URL url = ectx.getResource(DEFAULT_FACES_CONFIG);
333                 if (url != null)
334                 {
335                     validateFacesConfig(ectx, url);
336                 }
337             }
338             InputStream stream = ectx.getResourceAsStream(DEFAULT_FACES_CONFIG);
339             if (stream != null)
340             {
341                 if (log.isLoggable(Level.INFO))
342                 {
343                     log.info("Reading config /WEB-INF/faces-config.xml");
344                 }
345                 webAppConfig = getUnmarshaller(ectx).getFacesConfig(stream, DEFAULT_FACES_CONFIG);
346                 //getDispenser().feed(getUnmarshaller().getFacesConfig(stream, DEFAULT_FACES_CONFIG));
347                 stream.close();
348             }
349             return webAppConfig;
350         }
351         catch (IOException e)
352         {
353             throw new FacesException(e);
354         }
355         catch (SAXException e)
356         {
357             throw new FacesException(e);
358         }
359 
360     }
361 
362     private InputStream openStreamWithoutCache(URL url) throws IOException
363     {
364         URLConnection connection = url.openConnection();
365         connection.setUseCaches(false);
366         return connection.getInputStream();
367     }
368 
369     private List<String> getConfigFilesList(ExternalContext ectx)
370     {
371         String configFiles = ectx.getInitParameter(FacesServlet.CONFIG_FILES_ATTR);
372         List<String> configFilesList = new ArrayList<String>();
373         if (configFiles != null)
374         {
375             StringTokenizer st = new StringTokenizer(configFiles, ",", false);
376             while (st.hasMoreTokens())
377             {
378                 String systemId = st.nextToken().trim();
379 
380                 if (DEFAULT_FACES_CONFIG.equals(systemId))
381                 {
382                     if (log.isLoggable(Level.WARNING))
383                     {
384                         log.warning(DEFAULT_FACES_CONFIG + " has been specified in the "
385                                 + FacesServlet.CONFIG_FILES_ATTR
386                                 + " context parameter of "
387                                 + "the deployment descriptor. This will automatically be removed, "
388                                 + "if we wouldn't do this, it would be loaded twice.  See JSF spec 1.1, 10.3.2");
389                     }
390                 }
391                 else
392                 {
393                     configFilesList.add(systemId);
394                 }
395             }
396         }
397         return configFilesList;
398     }
399     
400     private void validateFacesConfig(ExternalContext ectx, URL url) throws IOException, SAXException
401     {
402         String version = ConfigFilesXmlValidationUtils.getFacesConfigVersion(url);
403         if ("1.2".equals(version) || "2.0".equals(version) || "2.1".equals(version))
404         {
405             ConfigFilesXmlValidationUtils.validateFacesConfigFile(url, ectx, version);
406         }
407     }
408 
409 }