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