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.element.ConfigOthersSlot;
22  import org.apache.myfaces.config.element.FacesConfig;
23  import org.apache.myfaces.config.element.FacesConfigData;
24  import org.apache.myfaces.config.element.FacesConfigNameSlot;
25  import org.apache.myfaces.config.element.OrderSlot;
26  import org.apache.myfaces.config.element.Ordering;
27  import org.apache.myfaces.config.impl.digester.DigesterFacesConfigDispenserImpl;
28  import org.apache.myfaces.config.util.CyclicDependencyException;
29  import org.apache.myfaces.config.util.DirectedAcyclicGraphVerifier;
30  import org.apache.myfaces.config.util.Vertex;
31  import org.apache.myfaces.spi.FacesConfigurationMerger;
32  import org.apache.myfaces.spi.FacesConfigurationProvider;
33  import org.apache.myfaces.spi.FacesConfigurationProviderFactory;
34  
35  import javax.faces.FacesException;
36  import javax.faces.context.ExternalContext;
37  import java.util.ArrayList;
38  import java.util.Collections;
39  import java.util.Comparator;
40  import java.util.Iterator;
41  import java.util.LinkedList;
42  import java.util.List;
43  import java.util.logging.Level;
44  import java.util.logging.Logger;
45  
46  /**
47   * Default impl of the FacesConfigurationMerger-SPI.
48   *
49   * This impl gets all FacesConfig data from the current FacesConfigurationProvider SPI impl and merges
50   * it into one FacesConfigData object using the ordering and sorting rules of the JSF spec.
51   *
52   * @author Jakob Korherr
53   */
54  public class DefaultFacesConfigurationMerger extends FacesConfigurationMerger
55  {
56  
57      private static final Logger log = Logger.getLogger(DefaultFacesConfigurationMerger.class.getName());
58  
59      @Override
60      public FacesConfigData getFacesConfigData(ExternalContext externalContext)
61      {
62          // get the FacesConfigProvider SPI impl in order to get the faces-config data for the merging process
63          FacesConfigurationProvider facesConfigProvider = FacesConfigurationProviderFactory
64                  .getFacesConfigurationProviderFactory(externalContext).getFacesConfigurationProvider(externalContext);
65  
66          FacesConfigDispenser dispenser = new DigesterFacesConfigDispenserImpl();
67  
68          // standard-faces-config.xml
69          dispenser.feed(facesConfigProvider.getStandardFacesConfig(externalContext));
70  
71          // META-INF/services/[factory name] factory definitions
72          dispenser.feed(facesConfigProvider.getMetaInfServicesFacesConfig(externalContext));
73  
74          // WEB-INF/faces-config.xml
75          FacesConfig webAppFacesConfig = facesConfigProvider.getWebAppFacesConfig(externalContext);
76  
77          //read metadata-complete attribute on WEB-INF/faces-config.xml
78          boolean metadataComplete = false;
79          if(webAppFacesConfig != null)
80          {
81              metadataComplete = Boolean.valueOf(webAppFacesConfig.getMetadataComplete());
82          }
83          else
84          {
85              //assume false if no faces-config.xml was found
86              //metadata-complete can only be specified in faces-config.xml per the JSF 2.0 schema
87              metadataComplete = false;
88          }
89  
90          // faces-config data from Annotations
91          FacesConfig annotationFacesConfig = facesConfigProvider
92                  .getAnnotationsFacesConfig(externalContext, metadataComplete);
93          if (annotationFacesConfig != null)
94          {
95              dispenser.feed(annotationFacesConfig);
96          }
97  
98          List<FacesConfig> appConfigResources = new ArrayList<FacesConfig>();
99  
100         // META-INF/faces-config.xml files
101         appConfigResources.addAll(facesConfigProvider.getClassloaderFacesConfig(externalContext));
102         
103         // faces-config.xml files from javax.faces.CONFIG_FILES
104         appConfigResources.addAll(facesConfigProvider.getContextSpecifiedFacesConfig(externalContext));
105 
106 
107         // apply the ordering and sorting algorithm 
108         orderAndFeedArtifacts(dispenser, appConfigResources, webAppFacesConfig);
109 
110         LogMetaInfUtils.logMetaInf();
111 
112         return dispenser;
113     }
114 
115     protected void orderAndFeedArtifacts(FacesConfigDispenser dispenser,
116                                          List<FacesConfig> appConfigResources,
117                                          FacesConfig webAppConfig)
118         throws FacesException
119     {
120         if (webAppConfig != null && webAppConfig.getAbsoluteOrdering() != null)
121         {
122             if (webAppConfig.getOrdering() != null)
123             {
124                 if (log.isLoggable(Level.WARNING))
125                 {
126                     log.warning("<ordering> element found in application faces config. " +
127                             "This description will be ignored and the actions described " +
128                             "in <absolute-ordering> element will be taken into account instead.");
129                 }
130             }
131             //Absolute ordering
132 
133             //1. Scan all appConfigResources and create a list
134             //containing all resources not mentioned directly, preserving the
135             //order founded
136             List<FacesConfig> othersResources = new ArrayList<FacesConfig>();
137             List<OrderSlot> slots = webAppConfig.getAbsoluteOrdering().getOrderList();
138             for (FacesConfig resource : appConfigResources)
139             {
140                 // First condition: if faces-config.xml does not have name it is 1) pre-JSF-2.0 or 2) has no <name> element,
141                 // -> in both cases cannot be ordered
142                 // Second condition : faces-config.xml has a name but <ordering> element does not have slot with that name
143                 //  -> resource can be ordered, but will fit into <others /> element
144                 if ((resource.getName() == null) ||
145                         (resource.getName() != null && !containsResourceInSlot(slots, resource.getName())))
146                 {
147                     othersResources.add(resource);
148                 }
149             }
150 
151             //2. Scan slot by slot and merge information according
152             for (OrderSlot slot : webAppConfig.getAbsoluteOrdering().getOrderList())
153             {
154                 if (slot instanceof ConfigOthersSlot)
155                 {
156                     //Add all mentioned in othersResources
157                     for (FacesConfig resource : othersResources)
158                     {
159                         dispenser.feed(resource);
160                     }
161                 }
162                 else
163                 {
164                     //Add it to the sorted list
165                     FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
166                     // We need to check if the resource is on appConfigResources, otherwise we can
167                     // ignore it safely.
168                     FacesConfig targetFacesConfig = getFacesConfig(appConfigResources, nameSlot.getName());
169                     if (targetFacesConfig != null)
170                     {
171                         dispenser.feed(targetFacesConfig);
172                     }
173                 }
174             }
175         }
176         else if (!appConfigResources.isEmpty())
177         {
178             //Relative ordering
179             for (FacesConfig resource : appConfigResources)
180             {
181                 if (resource.getAbsoluteOrdering() != null)
182                 {
183                     if (log.isLoggable(Level.WARNING))
184                     {
185                         log.warning("<absolute-ordering> element found in application " +
186                                 "configuration resource "+resource.getName()+". " +
187                                 "This description will be ignored and the actions described " +
188                                 "in <ordering> elements will be taken into account instead.");
189                     }
190                 }
191             }
192 
193             List<FacesConfig> postOrderedList = getPostOrderedList(appConfigResources);
194 
195             List<FacesConfig> sortedList = sortRelativeOrderingList(postOrderedList);
196 
197             if (sortedList == null)
198             {
199                 //The previous algorithm can't sort correctly, try this one
200                 sortedList = applySortingAlgorithm(appConfigResources);
201             }
202 
203             for (FacesConfig resource : sortedList)
204             {
205                 //Feed
206                 dispenser.feed(resource);
207             }
208         }
209 
210         //add null check for apps which don't have a faces-config.xml (e.g. tomahawk examples for 1.1/1.2)
211         if(webAppConfig != null)
212         {
213             dispenser.feed(webAppConfig);
214         }
215     }
216 
217     /**
218      * Sort using topological ordering algorithm.
219      *
220      * @param appConfigResources
221      * @return
222      * @throws FacesException
223      */
224     protected List<FacesConfig> applySortingAlgorithm(List<FacesConfig> appConfigResources) throws FacesException
225     {
226 
227         //0. Convert the references into a graph
228         List<Vertex<FacesConfig>> vertexList = new ArrayList<Vertex<FacesConfig>>();
229         for (FacesConfig config : appConfigResources)
230         {
231             Vertex<FacesConfig> v = null;
232             if (config.getName() != null)
233             {
234                 v = new Vertex<FacesConfig>(config.getName(), config);
235             }
236             else
237             {
238                 v = new Vertex<FacesConfig>(config);
239             }
240             vertexList.add(v);
241         }
242 
243         //1. Resolve dependencies (before-after rules) and mark referenced vertex
244         boolean[] referencedVertex = new boolean[vertexList.size()];
245 
246         for (int i = 0; i < vertexList.size(); i++)
247         {
248             Vertex<FacesConfig> v = vertexList.get(i);
249             FacesConfig f = (FacesConfig) v.getNode();
250 
251             if (f.getOrdering() != null)
252             {
253                 for (OrderSlot slot : f.getOrdering().getBeforeList())
254                 {
255                     if (slot instanceof FacesConfigNameSlot)
256                     {
257                         String name = ((FacesConfigNameSlot) slot).getName();
258                         int j = DirectedAcyclicGraphVerifier.findVertex(vertexList, name);
259                         Vertex<FacesConfig> v1 = vertexList.get(j);
260                         if (v1 != null)
261                         {
262                             referencedVertex[i] = true;
263                             referencedVertex[j] = true;
264                             v1.addDependency(v);
265                         }
266                     }
267                 }
268                 for (OrderSlot slot : f.getOrdering().getAfterList())
269                 {
270                     if (slot instanceof FacesConfigNameSlot)
271                     {
272                         String name = ((FacesConfigNameSlot) slot).getName();
273                         int j = DirectedAcyclicGraphVerifier.findVertex(vertexList, name);
274                         Vertex<FacesConfig> v1 = vertexList.get(j);
275                         if (v1 != null)
276                         {
277                             referencedVertex[i] = true;
278                             referencedVertex[j] = true;
279                             v.addDependency(v1);
280                         }
281                     }
282                 }
283             }
284         }
285 
286         //2. Classify into categories
287         List<Vertex<FacesConfig>> beforeAfterOthersList = new ArrayList<Vertex<FacesConfig>>();
288         List<Vertex<FacesConfig>> othersList = new ArrayList<Vertex<FacesConfig>>();
289         List<Vertex<FacesConfig>> referencedList = new ArrayList<Vertex<FacesConfig>>();
290 
291         for (int i = 0; i < vertexList.size(); i++)
292         {
293             if (!referencedVertex[i])
294             {
295                 Vertex<FacesConfig> v = vertexList.get(i);
296                 FacesConfig f = (FacesConfig) v.getNode();
297                 boolean added = false;
298                 if (f.getOrdering() != null)
299                 {
300                     if (!f.getOrdering().getBeforeList().isEmpty())
301                     {
302                         added = true;
303                         beforeAfterOthersList.add(v);
304                     }
305                     else if (!f.getOrdering().getAfterList().isEmpty())
306                     {
307                         added = true;
308                         beforeAfterOthersList.add(v);
309                     }
310                 }
311                 if (!added)
312                 {
313                     othersList.add(v);
314                 }
315             }
316             else
317             {
318                 referencedList.add(vertexList.get(i));
319             }
320         }
321 
322         //3. Sort all referenced nodes
323         try
324         {
325             DirectedAcyclicGraphVerifier.topologicalSort(referencedList);
326         }
327         catch (CyclicDependencyException e)
328         {
329             e.printStackTrace();
330         }
331 
332         //4. Add referenced nodes
333         List<FacesConfig> sortedList = new ArrayList<FacesConfig>();
334         for (Vertex<FacesConfig> v : referencedList)
335         {
336             sortedList.add((FacesConfig)v.getNode());
337         }
338 
339         //5. add nodes without instructions at the end
340         for (Vertex<FacesConfig> v : othersList)
341         {
342             sortedList.add((FacesConfig)v.getNode());
343         }
344 
345         //6. add before/after nodes
346         for (Vertex<FacesConfig> v : beforeAfterOthersList)
347         {
348             FacesConfig f = (FacesConfig) v.getNode();
349             boolean added = false;
350             if (f.getOrdering() != null)
351             {
352                 if (!f.getOrdering().getBeforeList().isEmpty())
353                 {
354                     added = true;
355                     sortedList.add(0,f);
356                 }
357             }
358             if (!added)
359             {
360                 sortedList.add(f);
361             }
362         }
363 
364         //Check
365         for (int i = 0; i < sortedList.size(); i++)
366         {
367             FacesConfig resource = sortedList.get(i);
368 
369             if (resource.getOrdering() != null)
370             {
371                 for (OrderSlot slot : resource.getOrdering().getBeforeList())
372                 {
373                     if (slot instanceof FacesConfigNameSlot)
374                     {
375                         String name = ((FacesConfigNameSlot) slot).getName();
376                         if (name != null && !"".equals(name))
377                         {
378                             boolean founded = false;
379                             for (int j = i-1; j >= 0; j--)
380                             {
381                                 if (name.equals(sortedList.get(j).getName()))
382                                 {
383                                     founded=true;
384                                     break;
385                                 }
386                             }
387                             if (founded)
388                             {
389                                 log.severe("Circular references detected when sorting " +
390                                           "application config resources. Use absolute ordering instead.");
391                                 throw new FacesException("Circular references detected when sorting " +
392                                         "application config resources. Use absolute ordering instead.");
393                             }
394                         }
395                     }
396                 }
397                 for (OrderSlot slot : resource.getOrdering().getAfterList())
398                 {
399                     if (slot instanceof FacesConfigNameSlot)
400                     {
401                         String name = ((FacesConfigNameSlot) slot).getName();
402                         if (name != null && !"".equals(name))
403                         {
404                             boolean founded = false;
405                             for (int j = i+1; j < sortedList.size(); j++)
406                             {
407                                 if (name.equals(sortedList.get(j).getName()))
408                                 {
409                                     founded=true;
410                                     break;
411                                 }
412                             }
413                             if (founded)
414                             {
415                                 log.severe("Circular references detected when sorting " +
416                                     "application config resources. Use absolute ordering instead.");
417                                 throw new FacesException("Circular references detected when sorting " +
418                                     "application config resources. Use absolute ordering instead.");
419                             }
420                         }
421                     }
422                 }
423             }
424         }
425 
426         return sortedList;
427     }
428 
429     /**
430      * Sort a list of pre ordered elements. It scans one by one the elements
431      * and apply the conditions mentioned by Ordering object if it is available.
432      *
433      * The preOrderedList ensures that application config resources referenced by
434      * other resources are processed first, making more easier the sort procedure.
435      *
436      * @param preOrderedList
437      * @return
438      */
439     protected List<FacesConfig> sortRelativeOrderingList(List<FacesConfig> preOrderedList)
440     {
441         List<FacesConfig> sortedList = new ArrayList<FacesConfig>();
442 
443         for (int i=0; i < preOrderedList.size(); i++)
444         {
445             FacesConfig resource = preOrderedList.get(i);
446             if (resource.getOrdering() != null)
447             {
448                 if (resource.getOrdering().getBeforeList().isEmpty() &&
449                     resource.getOrdering().getAfterList().isEmpty())
450                 {
451                     //No order rules, just put it as is
452                     sortedList.add(resource);
453                 }
454                 else if (resource.getOrdering().getBeforeList().isEmpty())
455                 {
456                     //Only after rules
457                     applyAfterRule(sortedList, resource);
458                 }
459                 else if (resource.getOrdering().getAfterList().isEmpty())
460                 {
461                     //Only before rules
462 
463                     //Resolve if there is a later reference to this node before
464                     //apply it
465                     boolean referenceNode = false;
466 
467                     for (int j = i+1; j < preOrderedList.size(); j++)
468                     {
469                         FacesConfig pointingResource = preOrderedList.get(j);
470                         for (OrderSlot slot : pointingResource.getOrdering().getBeforeList())
471                         {
472                             if (slot instanceof FacesConfigNameSlot &&
473                                     resource.getName().equals(((FacesConfigNameSlot)slot).getName()) )
474                             {
475                                 referenceNode = true;
476                             }
477                             if (slot instanceof ConfigOthersSlot)
478                             {
479                                 //No matter if there is a reference, because this rule
480                                 //is not strict and before other ordering is unpredictable.
481                                 //
482                                 referenceNode = false;
483                                 break;
484                             }
485                         }
486                         if (referenceNode)
487                         {
488                             break;
489                         }
490                         for (OrderSlot slot : pointingResource.getOrdering().getAfterList())
491                         {
492                             if (slot instanceof FacesConfigNameSlot &&
493                                 resource.getName().equals(((FacesConfigNameSlot)slot).getName()) )
494                             {
495                                 referenceNode = true;
496                                 break;
497                             }
498                         }
499                     }
500 
501                     applyBeforeRule(sortedList, resource, referenceNode);
502                 }
503                 else
504                 {
505                     //Both before and after rules
506                     //In this case we should compare before and after rules
507                     //and the one with names takes precedence over the other one.
508                     //It both have names references, before rules takes
509                     //precedence over after
510                     //after some action is applied a check of the condition is made.
511                     int beforeWeight = 0;
512                     int afterWeight = 0;
513                     for (OrderSlot slot : resource.getOrdering()
514                             .getBeforeList())
515                     {
516                         if (slot instanceof FacesConfigNameSlot)
517                         {
518                             beforeWeight++;
519                         }
520                     }
521                     for (OrderSlot slot : resource.getOrdering()
522                             .getAfterList())
523                     {
524                         if (slot instanceof FacesConfigNameSlot)
525                         {
526                             afterWeight++;
527                         }
528                     }
529 
530                     if (beforeWeight >= afterWeight)
531                     {
532                         applyBeforeRule(sortedList, resource,false);
533                     }
534                     else
535                     {
536                         applyAfterRule(sortedList, resource);
537                     }
538 
539 
540                 }
541             }
542             else
543             {
544                 //No order rules, just put it as is
545                 sortedList.add(resource);
546             }
547         }
548 
549         //Check
550         for (int i = 0; i < sortedList.size(); i++)
551         {
552             FacesConfig resource = sortedList.get(i);
553 
554             if (resource.getOrdering() != null)
555             {
556                 for (OrderSlot slot : resource.getOrdering().getBeforeList())
557                 {
558                     if (slot instanceof FacesConfigNameSlot)
559                     {
560                         String name = ((FacesConfigNameSlot) slot).getName();
561                         if (name != null && !"".equals(name))
562                         {
563                             boolean founded = false;
564                             for (int j = i-1; j >= 0; j--)
565                             {
566                                 if (name.equals(sortedList.get(j).getName()))
567                                 {
568                                     founded=true;
569                                     break;
570                                 }
571                             }
572                             if (founded)
573                             {
574                                 //Cyclic reference
575                                 return null;
576                             }
577                         }
578                     }
579                 }
580                 for (OrderSlot slot : resource.getOrdering().getAfterList())
581                 {
582                     if (slot instanceof FacesConfigNameSlot)
583                     {
584                         String name = ((FacesConfigNameSlot) slot).getName();
585                         if (name != null && !"".equals(name))
586                         {
587                             boolean founded = false;
588                             for (int j = i+1; j < sortedList.size(); j++)
589                             {
590                                 if (name.equals(sortedList.get(j).getName()))
591                                 {
592                                     founded=true;
593                                     break;
594                                 }
595                             }
596                             if (founded)
597                             {
598                                 //Cyclic reference
599                                 return null;
600                             }
601                         }
602                     }
603                 }
604             }
605         }
606 
607         return sortedList;
608     }
609 
610     private void applyBeforeRule(List<FacesConfig> sortedList, FacesConfig resource, boolean referenced)
611             throws FacesException
612     {
613         //Only before rules
614         boolean configOthers = false;
615         List<String> names = new ArrayList<String>();
616 
617         for (OrderSlot slot : resource.getOrdering().getBeforeList())
618         {
619             if (slot instanceof ConfigOthersSlot)
620             {
621                 configOthers = true;
622                 break;
623             }
624             else
625             {
626                 FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
627                 names.add(nameSlot.getName());
628             }
629         }
630 
631         if (configOthers)
632         {
633             //<before>....<others/></before> case
634             //other reference where already considered when
635             //pre ordered list was calculated, so just add to the end.
636 
637             //There is one very special case, and it is when there
638             //is another resource with a reference on it. In this case,
639             //it is better do not apply this rule and add it to the end
640             //to give the chance to the other one to be applied.
641             if (resource.getOrdering().getBeforeList().size() > 1)
642             {
643                 //If there is a reference apply it
644                 sortedList.add(0,resource);
645             }
646             else if (!referenced)
647             {
648                 //If it is not referenced apply it
649                 sortedList.add(0,resource);
650             }
651             else
652             {
653                 //if it is referenced bypass the rule and add it to the end
654                 sortedList.add(resource);
655             }
656         }
657         else
658         {
659             //Scan the nearest reference and add it after
660             boolean founded = false;
661             for (int i = 0; i < sortedList.size() ; i++)
662             {
663                 if (names.contains(sortedList.get(i).getName()))
664                 {
665                     sortedList.add(i,resource);
666                     founded = true;
667                     break;
668                 }
669             }
670             if (!founded)
671             {
672                 //just add it to the end
673                 sortedList.add(resource);
674             }
675         }
676     }
677 
678     private void applyAfterRule(List<FacesConfig> sortedList, FacesConfig resource) throws FacesException
679     {
680         boolean configOthers = false;
681         List<String> names = new ArrayList<String>();
682 
683         for (OrderSlot slot : resource.getOrdering().getAfterList())
684         {
685             if (slot instanceof ConfigOthersSlot)
686             {
687                 configOthers = true;
688                 break;
689             }
690             else
691             {
692                 FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
693                 names.add(nameSlot.getName());
694             }
695         }
696 
697         if (configOthers)
698         {
699             //<after>....<others/></after> case
700             //other reference where already considered when
701             //pre ordered list was calculated, so just add to the end.
702             sortedList.add(resource);
703         }
704         else
705         {
706             //Scan the nearest reference and add it after
707             boolean founded = false;
708             for (int i = sortedList.size()-1 ; i >=0 ; i--)
709             {
710                 if (names.contains(sortedList.get(i).getName()))
711                 {
712                     if (i+1 < sortedList.size())
713                     {
714                         sortedList.add(i+1,resource);
715                     }
716                     else
717                     {
718                         sortedList.add(resource);
719                     }
720                     founded = true;
721                     break;
722                 }
723             }
724             if (!founded)
725             {
726                 //just add it to the end
727                 sortedList.add(resource);
728             }
729         }
730     }
731 
732 
733     /**
734      * Pre Sort the appConfigResources, detecting cyclic references, so when sort process
735      * start, it is just necessary to traverse the preOrderedList once. To do that, we just
736      * scan "before" and "after" lists for references, and then those references are traversed
737      * again, so the first elements of the pre ordered list does not have references and
738      * the next elements has references to the already added ones.
739      *
740      * The elements on the preOrderedList looks like this:
741      *
742      * [ no ordering elements , referenced elements ... more referenced elements,
743      *  before others / after others non referenced elements]
744      *
745      * @param appConfigResources
746      * @return
747      */
748     protected List<FacesConfig> getPostOrderedList(final List<FacesConfig> appConfigResources) throws FacesException
749     {
750 
751         //0. Clean up: remove all not found resource references from the ordering
752         //descriptions.
753         List<String> availableReferences = new ArrayList<String>();
754         for (FacesConfig resource : appConfigResources)
755         {
756             String name = resource.getName();
757             if (name != null && !"".equals(name))
758             {
759                 availableReferences.add(name);
760             }
761         }
762 
763         for (FacesConfig resource : appConfigResources)
764         {
765             Ordering ordering = resource.getOrdering();
766             if (ordering != null)
767             {
768                 for (Iterator<OrderSlot> it =  resource.getOrdering().getBeforeList().iterator();it.hasNext();)
769                 {
770                     OrderSlot slot = it.next();
771                     if (slot instanceof FacesConfigNameSlot)
772                     {
773                         String name = ((FacesConfigNameSlot) slot).getName();
774                         if (!availableReferences.contains(name))
775                         {
776                             it.remove();
777                         }
778                     }
779                 }
780                 for (Iterator<OrderSlot> it =  resource.getOrdering().getAfterList().iterator();it.hasNext();)
781                 {
782                     OrderSlot slot = it.next();
783                     if (slot instanceof FacesConfigNameSlot)
784                     {
785                         String name = ((FacesConfigNameSlot) slot).getName();
786                         if (!availableReferences.contains(name))
787                         {
788                             it.remove();
789                         }
790                     }
791                 }
792             }
793         }
794 
795         List<FacesConfig> appFilteredConfigResources = null;
796 
797         //1. Pre filtering: Sort nodes according to its weight. The weight is the number of named
798         //nodes containing in both before and after lists. The sort is done from the more complex
799         //to the most simple
800         if (appConfigResources instanceof ArrayList)
801         {
802             appFilteredConfigResources = (List<FacesConfig>)
803                 ((ArrayList<FacesConfig>)appConfigResources).clone();
804         }
805         else
806         {
807             appFilteredConfigResources = new ArrayList<FacesConfig>();
808             appFilteredConfigResources.addAll(appConfigResources);
809         }
810         Collections.sort(appFilteredConfigResources,
811                 new Comparator<FacesConfig>()
812                 {
813                     public int compare(FacesConfig o1, FacesConfig o2)
814                     {
815                         int o1Weight = 0;
816                         int o2Weight = 0;
817                         if (o1.getOrdering() != null)
818                         {
819                             for (OrderSlot slot : o1.getOrdering()
820                                     .getBeforeList())
821                             {
822                                 if (slot instanceof FacesConfigNameSlot)
823                                 {
824                                     o1Weight++;
825                                 }
826                             }
827                             for (OrderSlot slot : o1.getOrdering()
828                                     .getAfterList())
829                             {
830                                 if (slot instanceof FacesConfigNameSlot)
831                                 {
832                                     o1Weight++;
833                                 }
834                             }
835                         }
836                         if (o2.getOrdering() != null)
837                         {
838                             for (OrderSlot slot : o2.getOrdering()
839                                     .getBeforeList())
840                             {
841                                 if (slot instanceof FacesConfigNameSlot)
842                                 {
843                                     o2Weight++;
844                                 }
845                             }
846                             for (OrderSlot slot : o2.getOrdering()
847                                     .getAfterList())
848                             {
849                                 if (slot instanceof FacesConfigNameSlot)
850                                 {
851                                     o2Weight++;
852                                 }
853                             }
854                         }
855                         return o2Weight - o1Weight;
856                     }
857                 });
858 
859         List<FacesConfig> postOrderedList = new LinkedList<FacesConfig>();
860         List<FacesConfig> othersList = new ArrayList<FacesConfig>();
861 
862         List<String> nameBeforeStack = new ArrayList<String>();
863         List<String> nameAfterStack = new ArrayList<String>();
864 
865         boolean[] visitedSlots = new boolean[appFilteredConfigResources.size()];
866 
867         //2. Scan and resolve conflicts
868         for (int i = 0; i < appFilteredConfigResources.size(); i++)
869         {
870             if (!visitedSlots[i])
871             {
872                 resolveConflicts(appFilteredConfigResources, i, visitedSlots,
873                         nameBeforeStack, nameAfterStack, postOrderedList, othersList, false);
874             }
875         }
876 
877         //Add othersList to postOrderedList so <before><others/></before> and <after><others/></after>
878         //ordering conditions are handled at last if there are not referenced by anyone
879         postOrderedList.addAll(othersList);
880 
881         return postOrderedList;
882     }
883 
884     private void resolveConflicts(final List<FacesConfig> appConfigResources, int index, boolean[] visitedSlots,
885             List<String> nameBeforeStack, List<String> nameAfterStack, List<FacesConfig> postOrderedList,
886             List<FacesConfig> othersList, boolean indexReferenced) throws FacesException
887     {
888         FacesConfig facesConfig = appConfigResources.get(index);
889 
890         if (nameBeforeStack.contains(facesConfig.getName()))
891         {
892             //Already referenced, just return. Later if there exists a
893             //circular reference, it will be detected and solved.
894             return;
895         }
896 
897         if (nameAfterStack.contains(facesConfig.getName()))
898         {
899             //Already referenced, just return. Later if there exists a
900             //circular reference, it will be detected and solved.
901             return;
902         }
903 
904         if (facesConfig.getOrdering() != null)
905         {
906             boolean pointingResource = false;
907 
908             //Deal with before restrictions first
909             for (OrderSlot slot : facesConfig.getOrdering().getBeforeList())
910             {
911                 if (slot instanceof FacesConfigNameSlot)
912                 {
913                     FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
914                     //The resource pointed is not added yet?
915                     boolean alreadyAdded = false;
916                     for (FacesConfig res : postOrderedList)
917                     {
918                         if (nameSlot.getName().equals(res.getName()))
919                         {
920                             alreadyAdded = true;
921                             break;
922                         }
923                     }
924                     if (!alreadyAdded)
925                     {
926                         int indexSlot = -1;
927                         //Find it
928                         for (int i = 0; i < appConfigResources.size(); i++)
929                         {
930                             FacesConfig resource = appConfigResources.get(i);
931                             if (resource.getName() != null && nameSlot.getName().equals(resource.getName()))
932                             {
933                                 indexSlot = i;
934                                 break;
935                             }
936                         }
937 
938                         //Resource founded on appConfigResources
939                         if (indexSlot != -1)
940                         {
941                             pointingResource = true;
942                             //Add to nameStac
943                             nameBeforeStack.add(facesConfig.getName());
944 
945                             resolveConflicts(appConfigResources, indexSlot, visitedSlots,
946                                     nameBeforeStack, nameAfterStack, postOrderedList,
947                                     othersList,true);
948 
949                             nameBeforeStack.remove(facesConfig.getName());
950                         }
951                     }
952                     else
953                     {
954                         pointingResource = true;
955                     }
956                 }
957             }
958 
959             for (OrderSlot slot : facesConfig.getOrdering().getAfterList())
960             {
961                 if (slot instanceof FacesConfigNameSlot)
962                 {
963                     FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
964                     //The resource pointed is not added yet?
965                     boolean alreadyAdded = false;
966                     for (FacesConfig res : postOrderedList)
967                     {
968                         if (nameSlot.getName().equals(res.getName()))
969                         {
970                             alreadyAdded = true;
971                             break;
972                         }
973                     }
974                     if (!alreadyAdded)
975                     {
976                         int indexSlot = -1;
977                         //Find it
978                         for (int i = 0; i < appConfigResources.size(); i++)
979                         {
980                             FacesConfig resource = appConfigResources.get(i);
981                             if (resource.getName() != null && nameSlot.getName().equals(resource.getName()))
982                             {
983                                 indexSlot = i;
984                                 break;
985                             }
986                         }
987 
988                         //Resource founded on appConfigResources
989                         if (indexSlot != -1)
990                         {
991                             pointingResource = true;
992                             //Add to nameStac
993                             nameAfterStack.add(facesConfig.getName());
994 
995                             resolveConflicts(appConfigResources, indexSlot, visitedSlots,
996                                     nameBeforeStack, nameAfterStack, postOrderedList,
997                                     othersList,true);
998 
999                             nameAfterStack.remove(facesConfig.getName());
1000                         }
1001                     }
1002                     else
1003                     {
1004                         pointingResource = true;
1005                     }
1006                 }
1007             }
1008 
1009             if (facesConfig.getOrdering().getBeforeList().isEmpty() &&
1010                 facesConfig.getOrdering().getAfterList().isEmpty())
1011             {
1012                 //Fits in the category "others", put at beginning
1013                 postOrderedList.add(0,appConfigResources.get(index));
1014             }
1015             else if (pointingResource || indexReferenced)
1016             {
1017                 //If the node points to other or is referenced from other,
1018                 //add to the postOrderedList at the end
1019                 postOrderedList.add(appConfigResources.get(index));
1020             }
1021             else
1022             {
1023                 //Add to othersList
1024                 othersList.add(appConfigResources.get(index));
1025             }
1026         }
1027         else
1028         {
1029             //Add at start of the list, since does not have any ordering
1030             //instructions and on the next step makes than "before others" and "after others"
1031             //works correctly
1032             postOrderedList.add(0,appConfigResources.get(index));
1033         }
1034         //Set the node as visited
1035         visitedSlots[index] = true;
1036     }
1037 
1038     private FacesConfig getFacesConfig(List<FacesConfig> appConfigResources, String name)
1039     {
1040         for (FacesConfig cfg: appConfigResources)
1041         {
1042             if (cfg.getName() != null && name.equals(cfg.getName()))
1043             {
1044                 return cfg;
1045             }
1046         }
1047         return null;
1048     }
1049 
1050     private boolean containsResourceInSlot(List<OrderSlot> slots, String name)
1051     {
1052         for (OrderSlot slot: slots)
1053         {
1054             if (slot instanceof FacesConfigNameSlot)
1055             {
1056                 FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
1057                 if (name.equals(nameSlot.getName()))
1058                 {
1059                     return true;
1060                 }
1061             }
1062         }
1063         return false;
1064     }
1065 
1066 }