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