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                 throw new FacesException("Standard faces config " + STANDARD_FACES_CONFIG_RESOURCE + " not found");
128             if (log.isLoggable(Level.INFO))
129                 log.info("Reading standard config " + STANDARD_FACES_CONFIG_RESOURCE);
130             
131             FacesConfig facesConfig = getUnmarshaller(ectx).getFacesConfig(stream, STANDARD_FACES_CONFIG_RESOURCE);
132             stream.close();
133             return facesConfig;
134         }
135         catch (IOException e)
136         {
137             throw new FacesException(e);
138         }
139         catch (SAXException e)
140         {
141             throw new FacesException(e);
142         }
143     }
144 
145     @Override
146     public FacesConfig getAnnotationsFacesConfig(ExternalContext ectx, boolean metadataComplete)
147     {
148         return getAnnotationConfigurator().createFacesConfig(ectx, metadataComplete);
149     }
150 
151     /**
152      * This method performs part of the factory search outlined in section 10.2.6.1.
153      */
154     @Override
155     public FacesConfig getMetaInfServicesFacesConfig(ExternalContext ectx)
156     {
157         try
158         {
159             org.apache.myfaces.config.impl.digester.elements.FacesConfig facesConfig
160                     = new org.apache.myfaces.config.impl.digester.elements.FacesConfig();
161             org.apache.myfaces.config.impl.digester.elements.Factory factory
162                     = new org.apache.myfaces.config.impl.digester.elements.Factory();
163             
164             facesConfig.addFactory(factory);
165             
166             for (String factoryName : FACTORY_NAMES)
167             {
168                 List<String> classList = ServiceProviderFinderFactory.getServiceProviderFinder(ectx)
169                         .getServiceProviderList(factoryName);
170                 
171                 for (String className : classList)
172                 {
173                     if (log.isLoggable(Level.INFO))
174                     {
175                         log.info("Found " + factoryName + " factory implementation: " + className);
176                     }
177 
178                     if (factoryName.equals(FactoryFinder.APPLICATION_FACTORY))
179                     {
180                         factory.addApplicationFactory(className);
181                     } 
182                     else if(factoryName.equals(FactoryFinder.EXCEPTION_HANDLER_FACTORY)) 
183                     {
184                         factory.addExceptionHandlerFactory(className);
185                     } 
186                     else if (factoryName.equals(FactoryFinder.EXTERNAL_CONTEXT_FACTORY))
187                     {
188                         factory.addExternalContextFactory(className);
189                     } 
190                     else if (factoryName.equals(FactoryFinder.FACES_CONTEXT_FACTORY))
191                     {
192                         factory.addFacesContextFactory(className);
193                     } 
194                     else if (factoryName.equals(FactoryFinder.LIFECYCLE_FACTORY))
195                     {
196                         factory.addLifecycleFactory(className);
197                     } 
198                     else if (factoryName.equals(FactoryFinder.RENDER_KIT_FACTORY))
199                     {
200                         factory.addRenderkitFactory(className);
201                     } 
202                     else if(factoryName.equals(FactoryFinder.TAG_HANDLER_DELEGATE_FACTORY)) 
203                     {
204                         factory.addTagHandlerDelegateFactory(className);
205                     } 
206                     else if (factoryName.equals(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY))
207                     {
208                         factory.addPartialViewContextFactory(className);
209                     } 
210                     else if(factoryName.equals(FactoryFinder.VISIT_CONTEXT_FACTORY)) 
211                     {
212                         factory.addVisitContextFactory(className);
213                     } 
214                     else if(factoryName.equals(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY)) 
215                     {
216                         factory.addViewDeclarationLanguageFactory(className);
217                     }
218                     
219                     else
220                     {
221                         throw new IllegalStateException("Unexpected factory name " + factoryName);
222                     }
223                 }
224             }
225             return facesConfig;
226         }
227         catch (Throwable e)
228         {
229             throw new FacesException(e);
230         }
231     }
232 
233     /**
234      * This method fixes MYFACES-208
235      */
236     @Override
237     public List<FacesConfig> getClassloaderFacesConfig(ExternalContext ectx)
238     {
239         List<FacesConfig> appConfigResources = new ArrayList<FacesConfig>();
240         try
241         {
242             FacesConfigResourceProvider provider = FacesConfigResourceProviderFactory.
243                 getFacesConfigResourceProviderFactory(ectx).createFacesConfigResourceProvider(ectx);
244             
245             Collection<URL> facesConfigs = provider.getMetaInfConfigurationResources(ectx);
246             
247             for (URL url : facesConfigs)
248             {
249                 if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
250                 {
251                     validateFacesConfig(ectx, url);
252                 }
253                 InputStream stream = null;
254                 try
255                 {
256                     stream = openStreamWithoutCache(url);
257                     if (log.isLoggable(Level.INFO))
258                     {
259                         log.info("Reading config : " + url.toExternalForm());
260                     }
261                     appConfigResources.add(getUnmarshaller(ectx).getFacesConfig(stream, url.toExternalForm()));
262                     //getDispenser().feed(getUnmarshaller().getFacesConfig(stream, entry.getKey()));
263                 }
264                 finally
265                 {
266                     if (stream != null)
267                     {
268                         stream.close();
269                     }
270                 }
271             }
272         }
273         catch (Throwable e)
274         {
275             throw new FacesException(e);
276         }
277         return appConfigResources;
278     }
279 
280     @Override
281     public List<FacesConfig> getContextSpecifiedFacesConfig(ExternalContext ectx)
282     {
283         List<FacesConfig> appConfigResources = new ArrayList<FacesConfig>();
284         try
285         {
286             for (String systemId : getConfigFilesList(ectx))
287             {
288                 if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
289                 {
290                     URL url = ectx.getResource(systemId);
291                     if (url != null)
292                     {
293                         validateFacesConfig(ectx, url);
294                     }
295                 }            
296                 InputStream stream = ectx.getResourceAsStream(systemId);
297                 if (stream == null)
298                 {
299                     log.severe("Faces config resource " + systemId + " not found");
300                     continue;
301                 }
302     
303                 if (log.isLoggable(Level.INFO))
304                 {
305                     log.info("Reading config " + systemId);
306                 }
307                 appConfigResources.add(getUnmarshaller(ectx).getFacesConfig(stream, systemId));
308                 //getDispenser().feed(getUnmarshaller().getFacesConfig(stream, systemId));
309                 stream.close();
310             }
311         }
312         catch (Throwable e)
313         {
314             throw new FacesException(e);
315         }
316         return appConfigResources;
317     }
318     
319     @Override
320     public FacesConfig getWebAppFacesConfig(ExternalContext ectx)
321     {
322         try
323         {
324             FacesConfig webAppConfig = null;
325             // web application config
326             if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
327             {
328                 URL url = ectx.getResource(DEFAULT_FACES_CONFIG);
329                 if (url != null)
330                 {
331                     validateFacesConfig(ectx, url);
332                 }
333             }
334             InputStream stream = ectx.getResourceAsStream(DEFAULT_FACES_CONFIG);
335             if (stream != null)
336             {
337                 if (log.isLoggable(Level.INFO))
338                     log.info("Reading config /WEB-INF/faces-config.xml");
339                 webAppConfig = getUnmarshaller(ectx).getFacesConfig(stream, DEFAULT_FACES_CONFIG);
340                 //getDispenser().feed(getUnmarshaller().getFacesConfig(stream, DEFAULT_FACES_CONFIG));
341                 stream.close();
342             }
343             return webAppConfig;
344         }
345         catch (IOException e)
346         {
347             throw new FacesException(e);
348         }
349         catch (SAXException e)
350         {
351             throw new FacesException(e);
352         }
353 
354     }
355 
356     private InputStream openStreamWithoutCache(URL url) throws IOException
357     {
358         URLConnection connection = url.openConnection();
359         connection.setUseCaches(false);
360         return connection.getInputStream();
361     }
362 
363     private List<String> getConfigFilesList(ExternalContext ectx) {
364         String configFiles = ectx.getInitParameter(FacesServlet.CONFIG_FILES_ATTR);
365         List<String> configFilesList = new ArrayList<String>();
366         if (configFiles != null)
367         {
368             StringTokenizer st = new StringTokenizer(configFiles, ",", false);
369             while (st.hasMoreTokens())
370             {
371                 String systemId = st.nextToken().trim();
372 
373                 if (DEFAULT_FACES_CONFIG.equals(systemId))
374                 {
375                     if (log.isLoggable(Level.WARNING))
376                     {
377                         log.warning(DEFAULT_FACES_CONFIG + " has been specified in the " + FacesServlet.CONFIG_FILES_ATTR
378                                 + " context parameter of "
379                                 + "the deployment descriptor. This will automatically be removed, "
380                                 + "if we wouldn't do this, it would be loaded twice.  See JSF spec 1.1, 10.3.2");
381                     }
382                 }
383                 else
384                 {
385                     configFilesList.add(systemId);
386                 }
387             }
388         }
389         return configFilesList;
390     }
391     
392     private void validateFacesConfig(ExternalContext ectx, URL url) throws IOException, SAXException
393     {
394         String version = ConfigFilesXmlValidationUtils.getFacesConfigVersion(url);
395         if ("1.2".equals(version) || "2.0".equals(version))
396         {
397             ConfigFilesXmlValidationUtils.validateFacesConfigFile(url, ectx, version);
398         }
399     }
400 
401 }