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 java.io.FileNotFoundException;
22  import org.apache.myfaces.config.annotation.AnnotationConfigurator;
23  import org.apache.myfaces.config.element.FacesConfig;
24  import org.apache.myfaces.config.impl.digester.DigesterFacesConfigUnmarshallerImpl;
25  import org.apache.myfaces.shared.config.MyfacesConfig;
26  import org.apache.myfaces.shared.util.ClassUtils;
27  import org.apache.myfaces.spi.FacesConfigResourceProvider;
28  import org.apache.myfaces.spi.FacesConfigResourceProviderFactory;
29  import org.apache.myfaces.spi.FacesConfigurationProvider;
30  import org.apache.myfaces.spi.ServiceProviderFinderFactory;
31  import org.xml.sax.SAXException;
32  
33  import javax.faces.FacesException;
34  import javax.faces.FactoryFinder;
35  import javax.faces.context.ExternalContext;
36  import javax.faces.webapp.FacesServlet;
37  import java.io.IOException;
38  import java.io.InputStream;
39  import java.io.PushbackInputStream;
40  import java.io.StringReader;
41  import java.net.MalformedURLException;
42  import java.net.URL;
43  import java.net.URLConnection;
44  import java.util.ArrayList;
45  import java.util.Collection;
46  import java.util.Collections;
47  import java.util.HashSet;
48  import java.util.List;
49  import java.util.ServiceLoader;
50  import java.util.Set;
51  import java.util.StringTokenizer;
52  import java.util.logging.Level;
53  import java.util.logging.Logger;
54  import javax.faces.application.ApplicationConfigurationPopulator;
55  import javax.faces.application.ViewHandler;
56  import javax.xml.parsers.DocumentBuilder;
57  import javax.xml.parsers.DocumentBuilderFactory;
58  import javax.xml.parsers.ParserConfigurationException;
59  import javax.xml.transform.OutputKeys;
60  import javax.xml.transform.Transformer;
61  import javax.xml.transform.TransformerConfigurationException;
62  import javax.xml.transform.TransformerException;
63  import javax.xml.transform.TransformerFactory;
64  import javax.xml.transform.dom.DOMSource;
65  import javax.xml.transform.stream.StreamResult;
66  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
67  import org.apache.myfaces.config.element.FacesFlowDefinition;
68  import org.apache.myfaces.config.element.facelets.FaceletTagLibrary;
69  import org.apache.myfaces.config.impl.digester.elements.FacesConfigImpl;
70  import org.apache.myfaces.config.impl.digester.elements.FacesFlowDefinitionImpl;
71  import org.apache.myfaces.config.impl.digester.elements.FacesFlowReturnImpl;
72  import org.apache.myfaces.config.impl.digester.elements.NavigationCaseImpl;
73  import org.apache.myfaces.shared.util.FastWriter;
74  import org.apache.myfaces.shared.util.WebConfigParamUtils;
75  import org.apache.myfaces.spi.FaceletConfigResourceProvider;
76  import org.apache.myfaces.spi.FaceletConfigResourceProviderFactory;
77  import org.apache.myfaces.spi.ServiceProviderFinder;
78  import org.apache.myfaces.view.facelets.compiler.TagLibraryConfigUnmarshallerImpl;
79  import org.w3c.dom.DOMImplementation;
80  import org.w3c.dom.Document;
81  
82  /**
83   * 
84   * @author Leonardo Uribe
85   * @since 2.0.3
86   */
87  public class DefaultFacesConfigurationProvider extends FacesConfigurationProvider
88  {
89  
90      private static final String STANDARD_FACES_CONFIG_RESOURCE = "META-INF/standard-faces-config.xml";
91      
92      //private static final String META_INF_SERVICES_RESOURCE_PREFIX = "META-INF/services/";
93  
94      private static final String DEFAULT_FACES_CONFIG = "/WEB-INF/faces-config.xml";
95  
96      private static final Set<String> FACTORY_NAMES = new HashSet<String>();
97      static
98      {
99          FACTORY_NAMES.add(FactoryFinder.APPLICATION_FACTORY);
100         FACTORY_NAMES.add(FactoryFinder.CLIENT_WINDOW_FACTORY);
101         FACTORY_NAMES.add(FactoryFinder.EXCEPTION_HANDLER_FACTORY);
102         FACTORY_NAMES.add(FactoryFinder.EXTERNAL_CONTEXT_FACTORY);
103         FACTORY_NAMES.add(FactoryFinder.FACELET_CACHE_FACTORY);
104         FACTORY_NAMES.add(FactoryFinder.FACES_CONTEXT_FACTORY);
105         FACTORY_NAMES.add(FactoryFinder.FLASH_FACTORY);
106         FACTORY_NAMES.add(FactoryFinder.FLOW_HANDLER_FACTORY);
107         FACTORY_NAMES.add(FactoryFinder.LIFECYCLE_FACTORY);
108         FACTORY_NAMES.add(FactoryFinder.RENDER_KIT_FACTORY);
109         FACTORY_NAMES.add(FactoryFinder.TAG_HANDLER_DELEGATE_FACTORY);
110         FACTORY_NAMES.add(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY);
111         FACTORY_NAMES.add(FactoryFinder.VISIT_CONTEXT_FACTORY);
112         FACTORY_NAMES.add(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY);
113     }
114     
115     /**
116      * Set of .taglib.xml files, separated by ';' that should be loaded by facelet engine.
117      */
118     @JSFWebConfigParam(since = "2.0",
119             desc = "Set of .taglib.xml files, separated by ';' that should be loaded by facelet engine.",
120             deprecated = true)
121     private final static String PARAM_LIBRARIES_DEPRECATED = "facelets.LIBRARIES";
122 
123     private final static String[] PARAMS_LIBRARIES = {ViewHandler.FACELETS_LIBRARIES_PARAM_NAME,
124         PARAM_LIBRARIES_DEPRECATED};
125 
126     private static final Logger log = Logger.getLogger(DefaultFacesConfigurationProvider.class.getName());
127 
128     private FacesConfigUnmarshaller<? extends FacesConfig> _unmarshaller;
129     
130     private AnnotationConfigurator _annotationConfigurator;
131 
132     protected void setUnmarshaller(ExternalContext ectx, FacesConfigUnmarshaller<? extends FacesConfig> unmarshaller)
133     {
134         _unmarshaller = unmarshaller;
135     }
136 
137     @SuppressWarnings("unchecked")
138     protected FacesConfigUnmarshaller<? extends FacesConfig> getUnmarshaller(ExternalContext ectx)
139     {
140         if (_unmarshaller == null)
141         {
142             _unmarshaller = new DigesterFacesConfigUnmarshallerImpl(ectx);
143         }
144         return _unmarshaller;
145     }
146     
147     protected void setAnnotationConfigurator(AnnotationConfigurator configurator)
148     {
149         _annotationConfigurator = configurator;
150     }
151     
152     protected AnnotationConfigurator getAnnotationConfigurator()
153     {
154         if (_annotationConfigurator == null)
155         {
156             _annotationConfigurator = new AnnotationConfigurator();
157         }
158         return _annotationConfigurator;
159     }
160 
161     @Override
162     public FacesConfig getStandardFacesConfig(ExternalContext ectx)
163     {
164         try
165         {
166             if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
167             {
168                 URL url = ClassUtils.getResource(STANDARD_FACES_CONFIG_RESOURCE);
169                 if (url != null)
170                 {
171                     validateFacesConfig(ectx, url);
172                 }
173             }
174             InputStream stream = ClassUtils.getResourceAsStream(STANDARD_FACES_CONFIG_RESOURCE);
175             if (stream == null)
176             {
177                 throw new FacesException("Standard faces config " + STANDARD_FACES_CONFIG_RESOURCE + " not found");
178             }
179             if (log.isLoggable(Level.INFO))
180             {
181                 log.info("Reading standard config " + STANDARD_FACES_CONFIG_RESOURCE);
182             }
183             
184             FacesConfig facesConfig = getUnmarshaller(ectx).getFacesConfig(stream, STANDARD_FACES_CONFIG_RESOURCE);
185             stream.close();
186             return facesConfig;
187         }
188         catch (IOException e)
189         {
190             throw new FacesException(e);
191         }
192         catch (SAXException e)
193         {
194             throw new FacesException(e);
195         }
196     }
197 
198     @Override
199     public FacesConfig getAnnotationsFacesConfig(ExternalContext ectx, boolean metadataComplete)
200     {
201         return getAnnotationConfigurator().createFacesConfig(ectx, metadataComplete);
202     }
203 
204     /**
205      * This method performs part of the factory search outlined in section 10.2.6.1.
206      */
207     @Override
208     public FacesConfig getMetaInfServicesFacesConfig(ExternalContext ectx)
209     {
210         try
211         {
212             org.apache.myfaces.config.impl.digester.elements.FacesConfigImpl facesConfig
213                     = new org.apache.myfaces.config.impl.digester.elements.FacesConfigImpl();
214             org.apache.myfaces.config.impl.digester.elements.FactoryImpl factory
215                     = new org.apache.myfaces.config.impl.digester.elements.FactoryImpl();
216             
217             facesConfig.addFactory(factory);
218             
219             for (String factoryName : FACTORY_NAMES)
220             {
221                 List<String> classList = ServiceProviderFinderFactory.getServiceProviderFinder(ectx)
222                         .getServiceProviderList(factoryName);
223                 
224                 for (String className : classList)
225                 {
226                     if (log.isLoggable(Level.INFO))
227                     {
228                         log.info("Found " + factoryName + " factory implementation: " + className);
229                     }
230 
231                     if (factoryName.equals(FactoryFinder.APPLICATION_FACTORY))
232                     {
233                         factory.addApplicationFactory(className);
234                     } 
235                     else if(factoryName.equals(FactoryFinder.EXCEPTION_HANDLER_FACTORY)) 
236                     {
237                         factory.addExceptionHandlerFactory(className);
238                     } 
239                     else if (factoryName.equals(FactoryFinder.EXTERNAL_CONTEXT_FACTORY))
240                     {
241                         factory.addExternalContextFactory(className);
242                     } 
243                     else if (factoryName.equals(FactoryFinder.FACES_CONTEXT_FACTORY))
244                     {
245                         factory.addFacesContextFactory(className);
246                     } 
247                     else if (factoryName.equals(FactoryFinder.LIFECYCLE_FACTORY))
248                     {
249                         factory.addLifecycleFactory(className);
250                     } 
251                     else if (factoryName.equals(FactoryFinder.RENDER_KIT_FACTORY))
252                     {
253                         factory.addRenderkitFactory(className);
254                     } 
255                     else if(factoryName.equals(FactoryFinder.TAG_HANDLER_DELEGATE_FACTORY)) 
256                     {
257                         factory.addTagHandlerDelegateFactory(className);
258                     } 
259                     else if (factoryName.equals(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY))
260                     {
261                         factory.addPartialViewContextFactory(className);
262                     } 
263                     else if(factoryName.equals(FactoryFinder.VISIT_CONTEXT_FACTORY)) 
264                     {
265                         factory.addVisitContextFactory(className);
266                     } 
267                     else if(factoryName.equals(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY)) 
268                     {
269                         factory.addViewDeclarationLanguageFactory(className);
270                     }
271                     else if(factoryName.equals(FactoryFinder.FLASH_FACTORY)) 
272                     {
273                         factory.addFlashFactory(className);
274                     }
275                     else if(factoryName.equals(FactoryFinder.FLOW_HANDLER_FACTORY)) 
276                     {
277                         factory.addFlowHandlerFactory(className);
278                     }
279                     else if(factoryName.equals(FactoryFinder.CLIENT_WINDOW_FACTORY)) 
280                     {
281                         factory.addClientWindowFactory(className);
282                     }
283                     else if(factoryName.equals(FactoryFinder.FACELET_CACHE_FACTORY)) 
284                     {
285                         factory.addFaceletCacheFactory(className);
286                     }
287                     else
288                     {
289                         throw new IllegalStateException("Unexpected factory name " + factoryName);
290                     }
291                 }
292             }
293             return facesConfig;
294         }
295         catch (Throwable e)
296         {
297             throw new FacesException(e);
298         }
299     }
300 
301     /**
302      * This method fixes MYFACES-208
303      */
304     @Override
305     public List<FacesConfig> getClassloaderFacesConfig(ExternalContext ectx)
306     {
307         List<FacesConfig> appConfigResources = new ArrayList<FacesConfig>();
308         try
309         {
310             FacesConfigResourceProvider provider = FacesConfigResourceProviderFactory.
311                 getFacesConfigResourceProviderFactory(ectx).createFacesConfigResourceProvider(ectx);
312             
313             Collection<URL> facesConfigs = provider.getMetaInfConfigurationResources(ectx);
314             
315             for (URL url : facesConfigs)
316             {
317                 if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
318                 {
319                     validateFacesConfig(ectx, url);
320                 }
321                 InputStream stream = null;
322                 try
323                 {
324                     stream = openStreamWithoutCache(url);
325                     if (log.isLoggable(Level.INFO))
326                     {
327                         log.info("Reading config : " + url.toExternalForm());
328                     }
329                     appConfigResources.add(getUnmarshaller(ectx).getFacesConfig(stream, url.toExternalForm()));
330                     //getDispenser().feed(getUnmarshaller().getFacesConfig(stream, entry.getKey()));
331                 }
332                 finally
333                 {
334                     if (stream != null)
335                     {
336                         stream.close();
337                     }
338                 }
339             }
340         }
341         catch (Throwable e)
342         {
343             throw new FacesException(e);
344         }
345         return appConfigResources;
346     }
347 
348     @Override
349     public List<FacesConfig> getContextSpecifiedFacesConfig(ExternalContext ectx)
350     {
351         List<FacesConfig> appConfigResources = new ArrayList<FacesConfig>();
352         try
353         {
354             for (String systemId : getConfigFilesList(ectx))
355             {
356                 if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
357                 {
358                     URL url = ectx.getResource(systemId);
359                     if (url != null)
360                     {
361                         validateFacesConfig(ectx, url);
362                     }
363                 }            
364                 InputStream stream = ectx.getResourceAsStream(systemId);
365                 if (stream == null)
366                 {
367                     log.severe("Faces config resource " + systemId + " not found");
368                     continue;
369                 }
370     
371                 if (log.isLoggable(Level.INFO))
372                 {
373                     log.info("Reading config " + systemId);
374                 }
375                 appConfigResources.add(getUnmarshaller(ectx).getFacesConfig(stream, systemId));
376                 //getDispenser().feed(getUnmarshaller().getFacesConfig(stream, systemId));
377                 stream.close();
378             }
379         }
380         catch (Throwable e)
381         {
382             throw new FacesException(e);
383         }
384         return appConfigResources;
385     }
386     
387     @Override
388     public FacesConfig getWebAppFacesConfig(ExternalContext ectx)
389     {
390         try
391         {
392             FacesConfig webAppConfig = null;
393             // web application config
394             if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
395             {
396                 URL url = ectx.getResource(DEFAULT_FACES_CONFIG);
397                 if (url != null)
398                 {
399                     validateFacesConfig(ectx, url);
400                 }
401             }
402             InputStream stream = ectx.getResourceAsStream(DEFAULT_FACES_CONFIG);
403             if (stream != null)
404             {
405                 if (log.isLoggable(Level.INFO))
406                 {
407                     log.info("Reading config /WEB-INF/faces-config.xml");
408                 }
409                 webAppConfig = getUnmarshaller(ectx).getFacesConfig(stream, DEFAULT_FACES_CONFIG);
410                 //getDispenser().feed(getUnmarshaller().getFacesConfig(stream, DEFAULT_FACES_CONFIG));
411                 stream.close();
412             }
413             return webAppConfig;
414         }
415         catch (IOException e)
416         {
417             throw new FacesException(e);
418         }
419         catch (SAXException e)
420         {
421             throw new FacesException(e);
422         }
423 
424     }
425 
426     private InputStream openStreamWithoutCache(URL url) throws IOException
427     {
428         URLConnection connection = url.openConnection();
429         connection.setUseCaches(false);
430         return connection.getInputStream();
431     }
432 
433     private List<String> getConfigFilesList(ExternalContext ectx)
434     {
435         String configFiles = ectx.getInitParameter(FacesServlet.CONFIG_FILES_ATTR);
436         List<String> configFilesList = new ArrayList<String>();
437         if (configFiles != null)
438         {
439             StringTokenizer st = new StringTokenizer(configFiles, ",", false);
440             while (st.hasMoreTokens())
441             {
442                 String systemId = st.nextToken().trim();
443 
444                 if (DEFAULT_FACES_CONFIG.equals(systemId))
445                 {
446                     if (log.isLoggable(Level.WARNING))
447                     {
448                         log.warning(DEFAULT_FACES_CONFIG + " has been specified in the "
449                                 + FacesServlet.CONFIG_FILES_ATTR
450                                 + " context parameter of "
451                                 + "the deployment descriptor. This will automatically be removed, "
452                                 + "if we wouldn't do this, it would be loaded twice.  See JSF spec 1.1, 10.3.2");
453                     }
454                 }
455                 else
456                 {
457                     configFilesList.add(systemId);
458                 }
459             }
460         }
461         return configFilesList;
462     }
463     
464     private void validateFacesConfig(ExternalContext ectx, URL url) throws IOException, SAXException
465     {
466         String version = ConfigFilesXmlValidationUtils.getFacesConfigVersion(url);
467         if ("1.2".equals(version) || "2.0".equals(version) || "2.1".equals(version))
468         {
469             ConfigFilesXmlValidationUtils.validateFacesConfigFile(url, ectx, version);
470         }
471     }
472 
473     @Override
474     public List<FacesConfig> getApplicationConfigurationResourceDocumentPopulatorFacesConfig(ExternalContext ectx)
475     {
476         ServiceProviderFinder spff = ServiceProviderFinderFactory.getServiceProviderFinder(ectx);
477         ServiceLoader<ApplicationConfigurationPopulator> instances = 
478             spff.load(ApplicationConfigurationPopulator.class);
479         if (instances != null)
480         {
481             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
482             // namespace aware
483             factory.setNamespaceAware(true);
484             // no validation
485             factory.setValidating(false);
486             
487             DocumentBuilder builder = null;
488             DOMImplementation domImpl = null;
489             try
490             {
491                 builder = factory.newDocumentBuilder();
492                 domImpl = builder.getDOMImplementation();
493             }
494             catch (ParserConfigurationException ex)
495             {
496                 log.log(Level.SEVERE, "Cannot create dom document builder, skipping it", ex);
497             }
498             
499             if (builder != null)
500             {
501                 List<FacesConfig> facesConfigList = new ArrayList<FacesConfig>();
502                 List<Document> documentList = new ArrayList<Document>();
503                 for (ApplicationConfigurationPopulator populator : instances)
504                 {
505                     // Spec says "... For each implementation, create a fresh org.w3c.dom.Document 
506                     // instance, configured to be in the XML namespace of the
507                     // application configuration resource format. ..."
508                     Document document = domImpl.createDocument(
509                         "http://java.sun.com/xml/ns/javaee", "faces-config", null);
510                     //Document document = builder.newDocument();
511                     populator.populateApplicationConfiguration(document);
512                     documentList.add(document);
513                 }
514                 
515                 // Parse document. This strategy construct the faces-config.xml in a
516                 // memory buffer and then loads it using commons digester.
517                 // TODO: Find a better way without write the DOM and read it again and without
518                 // rewrite commons-digester parser!.
519                 Transformer trans = null;
520                 try
521                 {
522                     trans = TransformerFactory.newInstance().newTransformer();
523                     trans.setOutputProperty(OutputKeys.INDENT, "no");
524                     trans.setOutputProperty(OutputKeys.METHOD, "xml");
525                     trans.setOutputProperty(OutputKeys.VERSION, "1.0");
526                     trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
527                 }
528                 catch (TransformerConfigurationException ex)
529                 {
530                     Logger.getLogger(DefaultFacesConfigurationProvider.class.getName()).log(Level.SEVERE, null, ex);
531                 }
532 
533                 if (trans != null)
534                 {
535                     FastWriter xmlAsWriter = new FastWriter();
536                     for (int i = 0; i < documentList.size(); i++)
537                     {
538                         Document document = documentList.get(i);
539                         xmlAsWriter.reset();
540                         try
541                         {
542                             DOMSource source = new DOMSource(document);
543                             StreamResult result = new StreamResult(xmlAsWriter);
544 
545                             trans.transform(source, result);
546 
547                             StringReader xmlReader = new StringReader(xmlAsWriter.toString());
548                             FacesConfig facesConfig = getUnmarshaller(ectx).getFacesConfig(
549                                 xmlReader);
550                             facesConfigList.add(facesConfig);
551                         }
552                         catch (IOException ex)
553                         {
554                             log.log(Level.SEVERE, "Error while reading faces-config from populator", ex);
555                         }
556                         catch (SAXException ex)
557                         {
558                             log.log(Level.SEVERE, "Error while reading faces-config from populator", ex);
559                         }
560                         catch (TransformerConfigurationException ex)
561                         {
562                             log.log(Level.SEVERE, "Error while reading faces-config from populator", ex);
563                         }
564                         catch (TransformerException ex)
565                         {
566                             log.log(Level.SEVERE, "Error while reading faces-config from populator", ex);
567                         }
568                     }
569                     return facesConfigList;
570                 }
571                 else
572                 {
573                     log.log(Level.SEVERE, "Cannot create xml transformer, skipping it");
574                 }
575             }
576         }
577         return Collections.emptyList();
578     }
579 
580     @Override
581     public List<FacesConfig> getFacesFlowFacesConfig(ExternalContext ectx)
582     {
583         List<FacesConfig> configFilesList;
584         Set<String> directoryPaths = ectx.getResourcePaths("/");
585         if (directoryPaths == null)
586         {
587             return Collections.emptyList();
588         }
589         configFilesList = new ArrayList<FacesConfig>();
590         
591         List<String> contextSpecifiedList = getConfigFilesList(ectx);
592         
593         for (String dirPath : directoryPaths)
594         {
595             if (dirPath.equals("/WEB-INF/"))
596             {
597                 // Look on /WEB-INF/<flow-Name>/<flowName>-flow.xml
598                 Set<String> webDirectoryPaths = ectx.getResourcePaths(dirPath);
599                 for (String webDirPath : webDirectoryPaths)
600                 {
601                     if (webDirPath.endsWith("/") && 
602                         !webDirPath.equals("/WEB-INF/classes/"))
603                     {
604                         String flowName = webDirPath.substring(9, webDirPath.length() - 1);
605                         String filePath = webDirPath+flowName+"-flow.xml";
606                         if (!contextSpecifiedList.contains(filePath))
607                         {
608                             try
609                             {
610                                 URL url = ectx.getResource(filePath);
611                                 if (url != null)
612                                 {
613                                     FacesConfig fc = parseFacesConfig(ectx, filePath, url);
614                                     if (fc != null)
615                                     {
616                                         configFilesList.add(fc);
617                                     }
618                                 }
619                             }
620                             catch (MalformedURLException ex)
621                             {
622                             }
623                         }
624                     }
625                 }
626             }
627             else if (!dirPath.startsWith("/META-INF") && dirPath.endsWith("/"))
628             {
629                 // Look on /<flowName>/<flowName>-flow.xml
630                 String flowName = dirPath.substring(1, dirPath.length() - 1);
631                 String filePath = dirPath+flowName+"-flow.xml";
632                 if (!contextSpecifiedList.contains(filePath))
633                 {
634                     try
635                     {
636                         URL url = ectx.getResource(filePath);
637                         if (url != null)
638                         {
639                             FacesConfig fc = parseFacesConfig(ectx, filePath, url);
640                             if (fc != null)
641                             {
642                                 configFilesList.add(fc);
643                             }
644                         }
645                     }
646                     catch (MalformedURLException ex)
647                     {
648                     }
649                 }
650             }
651         }
652         
653         return configFilesList;
654     }
655     
656     private FacesConfig parseFacesConfig(ExternalContext ectx, String systemId, URL url)
657     {
658         try
659         {
660             if (MyfacesConfig.getCurrentInstance(ectx).isValidateXML())
661             {
662                 //URL url = ectx.getResource(systemId);
663                 //if (url != null)
664                 //{
665                     validateFacesConfig(ectx, url);
666                 //}
667             }            
668         }
669         catch (IOException e)
670         {
671             throw new FacesException(e);
672         }
673         catch (SAXException e)
674         {
675             throw new FacesException(e);
676         }
677         InputStream stream = ectx.getResourceAsStream(systemId);
678         PushbackInputStream pbstream = new PushbackInputStream(stream, 10);
679         try
680         {
681             if (stream == null)
682             {
683                 log.severe("Faces config resource " + systemId + " not found");
684                 return null;
685             }
686             String flowName = systemId.substring(systemId.lastIndexOf('/')+1, systemId.lastIndexOf("-flow.xml"));
687             int c = pbstream.read();
688             if (c != -1)
689             {
690                 pbstream.unread(c);
691             }
692             else
693             {
694                 // Zero lenght, if that so the flow definition must be implicitly derived. 
695                 // See JSF 2.2 section 11.4.3.3
696                 // 
697                 FacesConfigImpl facesConfig = new FacesConfigImpl();
698                 FacesFlowDefinitionImpl flow = new FacesFlowDefinitionImpl();
699                 flow.setId(flowName);
700                 // In this case the defining document id is implicit associated
701                 flow.setDefiningDocumentId(systemId);
702                 
703                 String startNodePath = systemId.substring(0, systemId.lastIndexOf('/')+1)+flowName+".xhtml";
704                 //URL startNodeUrl = ectx.getResource(startNodePath);
705                 //if (startNodeUrl != null)
706                 //{
707                 flow.setStartNode(startNodePath);
708                 //}
709                 
710                 // There is a default return node with name [flow-name]-return and 
711                 // that by default points to an outer /[flow-name]-return outcome
712                 FacesFlowReturnImpl returnNode = new FacesFlowReturnImpl();
713                 returnNode.setId(flowName+"-return");
714                 NavigationCaseImpl returnNavCase = new NavigationCaseImpl();
715                 returnNavCase.setFromOutcome("/"+flowName+"-return");
716                 returnNode.setNavigationCase(returnNavCase);
717                 flow.addReturn(returnNode);
718                 
719                 facesConfig.addFacesFlowDefinition(flow);
720                 return facesConfig;
721             }
722 
723             if (log.isLoggable(Level.INFO))
724             {
725                 log.info("Reading config " + systemId);
726             }
727             
728             FacesConfigImpl facesConfig = (FacesConfigImpl) 
729                 getUnmarshaller(ectx).getFacesConfig(pbstream, systemId);
730             
731             // Set default start node when it is not present.
732             for (FacesFlowDefinition definition : facesConfig.getFacesFlowDefinitions())
733             {
734                 if (flowName.equals(definition.getId()))
735                 {
736                     FacesFlowDefinitionImpl flow = (FacesFlowDefinitionImpl) definition;
737                     if (flow.getStartNode() == null)
738                     {
739                         String startNodePath = systemId.substring(0, 
740                             systemId.lastIndexOf('/')+1)+flowName+".xhtml";
741                         flow.setStartNode(startNodePath);
742                     }
743                 }
744             }
745             return facesConfig;
746             //getDispenser().feed(getUnmarshaller().getFacesConfig(stream, systemId));
747         }
748         catch (IOException e)
749         {
750             throw new FacesException(e);
751         }
752         catch (SAXException e)
753         {
754             throw new FacesException(e);
755         }
756         finally
757         {
758             if (stream != null)
759             {
760                 try
761                 {
762                     stream.close();
763                 }
764                 catch (IOException ex)
765                 {
766                     // No op
767                 }
768             }
769         }
770     }
771 
772     @Override
773     public List<FacesConfig> getFaceletTaglibFacesConfig(ExternalContext externalContext)
774     {
775         List<FacesConfig> facesConfigFilesList = new ArrayList<FacesConfig>();
776         
777         String param = WebConfigParamUtils.getStringInitParameter(externalContext, PARAMS_LIBRARIES);
778         if (param != null)
779         {
780             for (String library : param.split(";"))
781             {
782                 try
783                 {
784                     URL src = externalContext.getResource(library.trim());
785                     if (src == null)
786                     {
787                         throw new FileNotFoundException(library);
788                     }
789                     
790                     FaceletTagLibrary tl = TagLibraryConfigUnmarshallerImpl.create(externalContext, src);
791                     if (tl != null)
792                     {
793                         org.apache.myfaces.config.impl.digester.elements.FacesConfigImpl config = 
794                             new org.apache.myfaces.config.impl.digester.elements.FacesConfigImpl();
795                         config.addFaceletTagLibrary(tl);
796                         facesConfigFilesList.add(config);
797                     }
798                     if (log.isLoggable(Level.FINE))
799                     {
800                         log.fine("Successfully loaded library: " + library);
801                     }
802                 }
803                 catch (IOException e)
804                 {
805                     log.log(Level.SEVERE, "Error Loading library: " + library, e);
806                 }
807             }
808         }
809         
810         try
811         {
812             FaceletConfigResourceProvider provider = FaceletConfigResourceProviderFactory.
813                 getFacesConfigResourceProviderFactory(externalContext).
814                     createFaceletConfigResourceProvider(externalContext);
815             Collection<URL> urls = provider.getFaceletTagLibConfigurationResources(externalContext);
816             for (URL url : urls)
817             {
818                 try
819                 {
820                     FaceletTagLibrary tl = TagLibraryConfigUnmarshallerImpl.create(externalContext, url);
821                     if (tl != null)
822                     {
823                         org.apache.myfaces.config.impl.digester.elements.FacesConfigImpl config = 
824                             new org.apache.myfaces.config.impl.digester.elements.FacesConfigImpl();
825                         config.addFaceletTagLibrary(tl);
826                         facesConfigFilesList.add(config);
827                     }
828                     if (log.isLoggable(Level.FINE))
829                     {
830                         //log.fine("Added Library from: " + urls[i]);
831                         log.fine("Added Library from: " + url);
832                     }
833                 }
834                 catch (Exception e)
835                 {
836                     //log.log(Level.SEVERE, "Error Loading Library: " + urls[i], e);
837                     log.log(Level.SEVERE, "Error Loading Library: " + url, e);
838                 }
839             }
840         }
841         catch (IOException e)
842         {
843             log.log(Level.SEVERE, "Compiler Initialization Error", e);
844         }
845         return facesConfigFilesList;
846     }
847 }