blob: e7ed9b39d1f0fe7d4b823a3518b0ac6a243ad172 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.config;
import org.apache.myfaces.config.element.ConfigOthersSlot;
import org.apache.myfaces.config.element.FacesConfig;
import org.apache.myfaces.config.element.FacesConfigData;
import org.apache.myfaces.config.element.FacesConfigNameSlot;
import org.apache.myfaces.config.element.OrderSlot;
import org.apache.myfaces.config.element.Ordering;
import org.apache.myfaces.config.impl.FacesConfigDispenserImpl;
import org.apache.myfaces.config.util.CyclicDependencyException;
import org.apache.myfaces.config.util.DirectedAcyclicGraphVerifier;
import org.apache.myfaces.config.util.Vertex;
import org.apache.myfaces.spi.FacesConfigurationMerger;
import org.apache.myfaces.spi.FacesConfigurationProvider;
import org.apache.myfaces.spi.FacesConfigurationProviderFactory;
import javax.faces.FacesException;
import javax.faces.context.ExternalContext;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.myfaces.util.lang.StringUtils;
/**
* Default impl of the FacesConfigurationMerger-SPI.
*
* This impl gets all FacesConfig data from the current FacesConfigurationProvider SPI impl and merges
* it into one FacesConfigData object using the ordering and sorting rules of the JSF spec.
*
* @author Jakob Korherr
*/
public class DefaultFacesConfigurationMerger extends FacesConfigurationMerger
{
private static final Logger log = Logger.getLogger(DefaultFacesConfigurationMerger.class.getName());
@Override
public FacesConfigData getFacesConfigData(ExternalContext externalContext)
{
// get the FacesConfigProvider SPI impl in order to get the faces-config data for the merging process
FacesConfigurationProvider facesConfigProvider = FacesConfigurationProviderFactory
.getFacesConfigurationProviderFactory(externalContext).getFacesConfigurationProvider(externalContext);
FacesConfigDispenser dispenser = new FacesConfigDispenserImpl();
// standard-faces-config.xml
dispenser.feed(facesConfigProvider.getStandardFacesConfig(externalContext));
// META-INF/services/[factory name] factory definitions
dispenser.feed(facesConfigProvider.getMetaInfServicesFacesConfig(externalContext));
// WEB-INF/faces-config.xml
FacesConfig webAppFacesConfig = facesConfigProvider.getWebAppFacesConfig(externalContext);
//read metadata-complete attribute on WEB-INF/faces-config.xml
boolean metadataComplete = false;
if(webAppFacesConfig != null)
{
metadataComplete = Boolean.valueOf(webAppFacesConfig.getMetadataComplete());
}
else
{
//assume false if no faces-config.xml was found
//metadata-complete can only be specified in faces-config.xml per the JSF 2.0 schema
metadataComplete = false;
}
// faces-config data from Annotations
FacesConfig annotationFacesConfig = facesConfigProvider
.getAnnotationsFacesConfig(externalContext, metadataComplete);
if (annotationFacesConfig != null)
{
dispenser.feed(annotationFacesConfig);
}
List<FacesConfig> appConfigResources = new ArrayList<>();
// META-INF/faces-config.xml files
appConfigResources.addAll(facesConfigProvider.getClassloaderFacesConfig(externalContext));
// faces-config.xml files from javax.faces.CONFIG_FILES
appConfigResources.addAll(facesConfigProvider.getContextSpecifiedFacesConfig(externalContext));
// JSF 2.2 ApplicationConfigurationResourceDocumentPopulator FacesConfig
appConfigResources.addAll(facesConfigProvider.
getApplicationConfigurationResourceDocumentPopulatorFacesConfig(externalContext));
// JSF 2.2 Faces Flow
appConfigResources.addAll(facesConfigProvider.getFacesFlowFacesConfig(externalContext));
// apply the ordering and sorting algorithm
orderAndFeedArtifacts(dispenser, appConfigResources, webAppFacesConfig);
List<FacesConfig> faceletTagLibFacesConfig =
facesConfigProvider.getFaceletTaglibFacesConfig(externalContext);
// at last feed facelet taglib faces config. These ones does not need
// to be included in the ordering algorithm.
if (faceletTagLibFacesConfig != null && !faceletTagLibFacesConfig.isEmpty())
{
for (FacesConfig fc : faceletTagLibFacesConfig)
{
dispenser.feed(fc);
}
}
LogMetaInfUtils.logMetaInf();
return dispenser;
}
protected void orderAndFeedArtifacts(FacesConfigDispenser dispenser,
List<FacesConfig> appConfigResources,
FacesConfig webAppConfig)
throws FacesException
{
if (webAppConfig != null && webAppConfig.getAbsoluteOrdering() != null)
{
if (webAppConfig.getOrdering() != null)
{
if (log.isLoggable(Level.WARNING))
{
log.warning("<ordering> element found in application faces config. " +
"This description will be ignored and the actions described " +
"in <absolute-ordering> element will be taken into account instead.");
}
}
//Absolute ordering
//1. Scan all appConfigResources and create a list
//containing all resources not mentioned directly, preserving the
//order founded
List<FacesConfig> othersResources = new ArrayList<>();
List<OrderSlot> slots = webAppConfig.getAbsoluteOrdering().getOrderList();
for (FacesConfig resource : appConfigResources)
{
// First condition: if faces-config.xml does not have name it is
// 1) pre-JSF-2.0 or
// 2) has no <name> element,
// -> in both cases cannot be ordered
// Second condition : faces-config.xml has a name but <ordering>
// element does not have slot with that name
// -> resource can be ordered, but will fit into <others /> element
if ((resource.getName() == null) ||
(resource.getName() != null && !containsResourceInSlot(slots, resource.getName())))
{
othersResources.add(resource);
}
}
//2. Scan slot by slot and merge information according
for (OrderSlot slot : webAppConfig.getAbsoluteOrdering().getOrderList())
{
if (slot instanceof ConfigOthersSlot)
{
//Add all mentioned in othersResources
for (FacesConfig resource : othersResources)
{
dispenser.feed(resource);
}
}
else
{
//Add it to the sorted list
FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
// We need to check if the resource is on appConfigResources, otherwise we can
// ignore it safely.
FacesConfig targetFacesConfig = getFacesConfig(appConfigResources, nameSlot.getName());
if (targetFacesConfig != null)
{
dispenser.feed(targetFacesConfig);
}
}
}
}
else if (!appConfigResources.isEmpty())
{
//Relative ordering
for (FacesConfig resource : appConfigResources)
{
if (resource.getAbsoluteOrdering() != null)
{
if (log.isLoggable(Level.WARNING))
{
log.warning("<absolute-ordering> element found in application " +
"configuration resource "+resource.getName()+". " +
"This description will be ignored and the actions described " +
"in <ordering> elements will be taken into account instead.");
}
}
}
List<FacesConfig> postOrderedList = getPostOrderedList(appConfigResources);
List<FacesConfig> sortedList = sortRelativeOrderingList(postOrderedList);
if (sortedList == null)
{
//The previous algorithm can't sort correctly, try this one
sortedList = applySortingAlgorithm(appConfigResources);
}
for (FacesConfig resource : sortedList)
{
//Feed
dispenser.feed(resource);
}
}
//add null check for apps which don't have a faces-config.xml
if(webAppConfig != null)
{
dispenser.feed(webAppConfig);
}
}
/**
* Sort using topological ordering algorithm.
*
* @param appConfigResources
* @return
* @throws FacesException
*/
protected List<FacesConfig> applySortingAlgorithm(List<FacesConfig> appConfigResources) throws FacesException
{
//0. Convert the references into a graph
List<Vertex<FacesConfig>> vertexList = new ArrayList<>();
for (FacesConfig config : appConfigResources)
{
Vertex<FacesConfig> v;
if (config.getName() != null)
{
v = new Vertex<>(config.getName(), config);
}
else
{
v = new Vertex<>(config);
}
vertexList.add(v);
}
//1. Resolve dependencies (before-after rules) and mark referenced vertex
boolean[] referencedVertex = new boolean[vertexList.size()];
for (int i = 0; i < vertexList.size(); i++)
{
Vertex<FacesConfig> v = vertexList.get(i);
FacesConfig f = (FacesConfig) v.getNode();
if (f.getOrdering() != null)
{
for (OrderSlot slot : f.getOrdering().getBeforeList())
{
if (slot instanceof FacesConfigNameSlot)
{
String name = ((FacesConfigNameSlot) slot).getName();
int j = DirectedAcyclicGraphVerifier.findVertex(vertexList, name);
Vertex<FacesConfig> v1 = vertexList.get(j);
if (v1 != null)
{
referencedVertex[i] = true;
referencedVertex[j] = true;
v1.addDependency(v);
}
}
}
for (OrderSlot slot : f.getOrdering().getAfterList())
{
if (slot instanceof FacesConfigNameSlot)
{
String name = ((FacesConfigNameSlot) slot).getName();
int j = DirectedAcyclicGraphVerifier.findVertex(vertexList, name);
Vertex<FacesConfig> v1 = vertexList.get(j);
if (v1 != null)
{
referencedVertex[i] = true;
referencedVertex[j] = true;
v.addDependency(v1);
}
}
}
}
}
//2. Classify into categories
List<Vertex<FacesConfig>> beforeAfterOthersList = new ArrayList<>();
List<Vertex<FacesConfig>> othersList = new ArrayList<>();
List<Vertex<FacesConfig>> referencedList = new ArrayList<>();
for (int i = 0; i < vertexList.size(); i++)
{
if (!referencedVertex[i])
{
Vertex<FacesConfig> v = vertexList.get(i);
FacesConfig f = (FacesConfig) v.getNode();
boolean added = false;
if (f.getOrdering() != null)
{
if (!f.getOrdering().getBeforeList().isEmpty())
{
added = true;
beforeAfterOthersList.add(v);
}
else if (!f.getOrdering().getAfterList().isEmpty())
{
added = true;
beforeAfterOthersList.add(v);
}
}
if (!added)
{
othersList.add(v);
}
}
else
{
referencedList.add(vertexList.get(i));
}
}
//3. Sort all referenced nodes
try
{
DirectedAcyclicGraphVerifier.topologicalSort(referencedList);
}
catch (CyclicDependencyException e)
{
e.printStackTrace();
}
//4. Add referenced nodes
List<FacesConfig> sortedList = new ArrayList<>();
for (Vertex<FacesConfig> v : referencedList)
{
sortedList.add((FacesConfig)v.getNode());
}
//5. add nodes without instructions at the end
for (Vertex<FacesConfig> v : othersList)
{
sortedList.add((FacesConfig)v.getNode());
}
//6. add before/after nodes
for (Vertex<FacesConfig> v : beforeAfterOthersList)
{
FacesConfig f = (FacesConfig) v.getNode();
boolean added = false;
if (f.getOrdering() != null && !f.getOrdering().getBeforeList().isEmpty())
{
added = true;
sortedList.add(0,f);
}
if (!added)
{
sortedList.add(f);
}
}
//Check
for (int i = 0; i < sortedList.size(); i++)
{
FacesConfig resource = sortedList.get(i);
if (resource.getOrdering() != null)
{
for (OrderSlot slot : resource.getOrdering().getBeforeList())
{
if (slot instanceof FacesConfigNameSlot)
{
String name = ((FacesConfigNameSlot) slot).getName();
if (name != null && !name.isEmpty())
{
boolean founded = false;
for (int j = i-1; j >= 0; j--)
{
if (name.equals(sortedList.get(j).getName()))
{
founded=true;
break;
}
}
if (founded)
{
log.severe("Circular references detected when sorting " +
"application config resources. Use absolute ordering instead.");
throw new FacesException("Circular references detected when sorting " +
"application config resources. Use absolute ordering instead.");
}
}
}
}
for (OrderSlot slot : resource.getOrdering().getAfterList())
{
if (slot instanceof FacesConfigNameSlot)
{
String name = ((FacesConfigNameSlot) slot).getName();
if (StringUtils.isNotEmpty(name))
{
boolean founded = false;
for (int j = i+1; j < sortedList.size(); j++)
{
if (name.equals(sortedList.get(j).getName()))
{
founded=true;
break;
}
}
if (founded)
{
log.severe("Circular references detected when sorting " +
"application config resources. Use absolute ordering instead.");
throw new FacesException("Circular references detected when sorting " +
"application config resources. Use absolute ordering instead.");
}
}
}
}
}
}
return sortedList;
}
/**
* Sort a list of pre ordered elements. It scans one by one the elements
* and apply the conditions mentioned by Ordering object if it is available.
*
* The preOrderedList ensures that application config resources referenced by
* other resources are processed first, making more easier the sort procedure.
*
* @param preOrderedList
* @return
*/
protected List<FacesConfig> sortRelativeOrderingList(List<FacesConfig> preOrderedList)
{
List<FacesConfig> sortedList = new ArrayList<>();
for (int i=0; i < preOrderedList.size(); i++)
{
FacesConfig resource = preOrderedList.get(i);
if (resource.getOrdering() != null)
{
if (resource.getOrdering().getBeforeList().isEmpty() &&
resource.getOrdering().getAfterList().isEmpty())
{
//No order rules, just put it as is
sortedList.add(resource);
}
else if (resource.getOrdering().getBeforeList().isEmpty())
{
//Only after rules
applyAfterRule(sortedList, resource);
}
else if (resource.getOrdering().getAfterList().isEmpty())
{
//Only before rules
//Resolve if there is a later reference to this node before
//apply it
boolean referenceNode = false;
for (int j = i+1; j < preOrderedList.size(); j++)
{
FacesConfig pointingResource = preOrderedList.get(j);
for (OrderSlot slot : pointingResource.getOrdering().getBeforeList())
{
if (slot instanceof FacesConfigNameSlot &&
resource.getName().equals(((FacesConfigNameSlot)slot).getName()) )
{
referenceNode = true;
}
if (slot instanceof ConfigOthersSlot)
{
//No matter if there is a reference, because this rule
//is not strict and before other ordering is unpredictable.
//
referenceNode = false;
break;
}
}
if (referenceNode)
{
break;
}
for (OrderSlot slot : pointingResource.getOrdering().getAfterList())
{
if (slot instanceof FacesConfigNameSlot &&
resource.getName().equals(((FacesConfigNameSlot)slot).getName()) )
{
referenceNode = true;
break;
}
}
}
applyBeforeRule(sortedList, resource, referenceNode);
}
else
{
//Both before and after rules
//In this case we should compare before and after rules
//and the one with names takes precedence over the other one.
//It both have names references, before rules takes
//precedence over after
//after some action is applied a check of the condition is made.
int beforeWeight = 0;
int afterWeight = 0;
for (OrderSlot slot : resource.getOrdering().getBeforeList())
{
if (slot instanceof FacesConfigNameSlot)
{
beforeWeight++;
}
}
for (OrderSlot slot : resource.getOrdering().getAfterList())
{
if (slot instanceof FacesConfigNameSlot)
{
afterWeight++;
}
}
if (beforeWeight >= afterWeight)
{
applyBeforeRule(sortedList, resource,false);
}
else
{
applyAfterRule(sortedList, resource);
}
}
}
else
{
//No order rules, just put it as is
sortedList.add(resource);
}
}
//Check
for (int i = 0; i < sortedList.size(); i++)
{
FacesConfig resource = sortedList.get(i);
if (resource.getOrdering() != null)
{
for (OrderSlot slot : resource.getOrdering().getBeforeList())
{
if (slot instanceof FacesConfigNameSlot)
{
String name = ((FacesConfigNameSlot) slot).getName();
if (StringUtils.isNotEmpty(name))
{
boolean founded = false;
for (int j = i-1; j >= 0; j--)
{
if (name.equals(sortedList.get(j).getName()))
{
founded=true;
break;
}
}
if (founded)
{
//Cyclic reference
return null;
}
}
}
}
for (OrderSlot slot : resource.getOrdering().getAfterList())
{
if (slot instanceof FacesConfigNameSlot)
{
String name = ((FacesConfigNameSlot) slot).getName();
if (StringUtils.isNotEmpty(name))
{
boolean founded = false;
for (int j = i+1; j < sortedList.size(); j++)
{
if (name.equals(sortedList.get(j).getName()))
{
founded=true;
break;
}
}
if (founded)
{
//Cyclic reference
return null;
}
}
}
}
}
}
return sortedList;
}
private void applyBeforeRule(List<FacesConfig> sortedList, FacesConfig resource, boolean referenced)
throws FacesException
{
//Only before rules
boolean configOthers = false;
List<String> names = new ArrayList<>();
for (OrderSlot slot : resource.getOrdering().getBeforeList())
{
if (slot instanceof ConfigOthersSlot)
{
configOthers = true;
break;
}
else
{
FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
names.add(nameSlot.getName());
}
}
if (configOthers)
{
//<before>....<others/></before> case
//other reference where already considered when
//pre ordered list was calculated, so just add to the end.
//There is one very special case, and it is when there
//is another resource with a reference on it. In this case,
//it is better do not apply this rule and add it to the end
//to give the chance to the other one to be applied.
if (resource.getOrdering().getBeforeList().size() > 1)
{
//If there is a reference apply it
sortedList.add(0,resource);
}
else if (!referenced)
{
//If it is not referenced apply it
sortedList.add(0,resource);
}
else
{
//if it is referenced bypass the rule and add it to the end
sortedList.add(resource);
}
}
else
{
//Scan the nearest reference and add it after
boolean founded = false;
for (int i = 0; i < sortedList.size() ; i++)
{
if (names.contains(sortedList.get(i).getName()))
{
sortedList.add(i,resource);
founded = true;
break;
}
}
if (!founded)
{
//just add it to the end
sortedList.add(resource);
}
}
}
private void applyAfterRule(List<FacesConfig> sortedList, FacesConfig resource) throws FacesException
{
boolean configOthers = false;
List<String> names = new ArrayList<>();
for (OrderSlot slot : resource.getOrdering().getAfterList())
{
if (slot instanceof ConfigOthersSlot)
{
configOthers = true;
break;
}
else
{
FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
names.add(nameSlot.getName());
}
}
if (configOthers)
{
//<after>....<others/></after> case
//other reference where already considered when
//pre ordered list was calculated, so just add to the end.
sortedList.add(resource);
}
else
{
//Scan the nearest reference and add it after
boolean founded = false;
for (int i = sortedList.size()-1 ; i >=0 ; i--)
{
if (names.contains(sortedList.get(i).getName()))
{
if (i+1 < sortedList.size())
{
sortedList.add(i+1,resource);
}
else
{
sortedList.add(resource);
}
founded = true;
break;
}
}
if (!founded)
{
//just add it to the end
sortedList.add(resource);
}
}
}
/**
* Pre Sort the appConfigResources, detecting cyclic references, so when sort process
* start, it is just necessary to traverse the preOrderedList once. To do that, we just
* scan "before" and "after" lists for references, and then those references are traversed
* again, so the first elements of the pre ordered list does not have references and
* the next elements has references to the already added ones.
*
* The elements on the preOrderedList looks like this:
*
* [ no ordering elements , referenced elements ... more referenced elements,
* before others / after others non referenced elements]
*
* @param appConfigResources
* @return
*/
protected List<FacesConfig> getPostOrderedList(final List<FacesConfig> appConfigResources) throws FacesException
{
//0. Clean up: remove all not found resource references from the ordering
//descriptions.
List<String> availableReferences = new ArrayList<>();
for (FacesConfig resource : appConfigResources)
{
String name = resource.getName();
if (StringUtils.isNotEmpty(name))
{
availableReferences.add(name);
}
}
for (FacesConfig resource : appConfigResources)
{
Ordering ordering = resource.getOrdering();
if (ordering != null)
{
for (Iterator<OrderSlot> it = resource.getOrdering().getBeforeList().iterator();it.hasNext();)
{
OrderSlot slot = it.next();
if (slot instanceof FacesConfigNameSlot)
{
String name = ((FacesConfigNameSlot) slot).getName();
if (!availableReferences.contains(name))
{
it.remove();
}
}
}
for (Iterator<OrderSlot> it = resource.getOrdering().getAfterList().iterator();it.hasNext();)
{
OrderSlot slot = it.next();
if (slot instanceof FacesConfigNameSlot)
{
String name = ((FacesConfigNameSlot) slot).getName();
if (!availableReferences.contains(name))
{
it.remove();
}
}
}
}
}
List<FacesConfig> appFilteredConfigResources = null;
//1. Pre filtering: Sort nodes according to its weight. The weight is the number of named
//nodes containing in both before and after lists. The sort is done from the more complex
//to the most simple
if (appConfigResources instanceof ArrayList)
{
appFilteredConfigResources = (List<FacesConfig>)
((ArrayList<FacesConfig>)appConfigResources).clone();
}
else
{
appFilteredConfigResources = new ArrayList<>(appConfigResources);
}
Collections.sort(appFilteredConfigResources,
new Comparator<FacesConfig>()
{
@Override
public int compare(FacesConfig o1, FacesConfig o2)
{
int o1Weight = 0;
int o2Weight = 0;
if (o1.getOrdering() != null)
{
for (OrderSlot slot : o1.getOrdering().getBeforeList())
{
if (slot instanceof FacesConfigNameSlot)
{
o1Weight++;
}
}
for (OrderSlot slot : o1.getOrdering().getAfterList())
{
if (slot instanceof FacesConfigNameSlot)
{
o1Weight++;
}
}
}
if (o2.getOrdering() != null)
{
for (OrderSlot slot : o2.getOrdering().getBeforeList())
{
if (slot instanceof FacesConfigNameSlot)
{
o2Weight++;
}
}
for (OrderSlot slot : o2.getOrdering().getAfterList())
{
if (slot instanceof FacesConfigNameSlot)
{
o2Weight++;
}
}
}
return o2Weight - o1Weight;
}
});
List<FacesConfig> postOrderedList = new LinkedList<>();
List<FacesConfig> othersList = new ArrayList<>();
List<String> nameBeforeStack = new ArrayList<>();
List<String> nameAfterStack = new ArrayList<>();
boolean[] visitedSlots = new boolean[appFilteredConfigResources.size()];
//2. Scan and resolve conflicts
for (int i = 0; i < appFilteredConfigResources.size(); i++)
{
if (!visitedSlots[i])
{
resolveConflicts(appFilteredConfigResources, i, visitedSlots,
nameBeforeStack, nameAfterStack, postOrderedList, othersList, false);
}
}
//Add othersList to postOrderedList so <before><others/></before> and <after><others/></after>
//ordering conditions are handled at last if there are not referenced by anyone
postOrderedList.addAll(othersList);
return postOrderedList;
}
private void resolveConflicts(final List<FacesConfig> appConfigResources, int index, boolean[] visitedSlots,
List<String> nameBeforeStack, List<String> nameAfterStack, List<FacesConfig> postOrderedList,
List<FacesConfig> othersList, boolean indexReferenced) throws FacesException
{
FacesConfig facesConfig = appConfigResources.get(index);
if (nameBeforeStack.contains(facesConfig.getName()))
{
//Already referenced, just return. Later if there exists a
//circular reference, it will be detected and solved.
return;
}
if (nameAfterStack.contains(facesConfig.getName()))
{
//Already referenced, just return. Later if there exists a
//circular reference, it will be detected and solved.
return;
}
if (facesConfig.getOrdering() != null)
{
boolean pointingResource = false;
//Deal with before restrictions first
for (OrderSlot slot : facesConfig.getOrdering().getBeforeList())
{
if (slot instanceof FacesConfigNameSlot)
{
FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
//The resource pointed is not added yet?
boolean alreadyAdded = false;
for (FacesConfig res : postOrderedList)
{
if (nameSlot.getName().equals(res.getName()))
{
alreadyAdded = true;
break;
}
}
if (!alreadyAdded)
{
int indexSlot = -1;
//Find it
for (int i = 0; i < appConfigResources.size(); i++)
{
FacesConfig resource = appConfigResources.get(i);
if (resource.getName() != null && nameSlot.getName().equals(resource.getName()))
{
indexSlot = i;
break;
}
}
//Resource founded on appConfigResources
if (indexSlot != -1)
{
pointingResource = true;
//Add to nameStac
nameBeforeStack.add(facesConfig.getName());
resolveConflicts(appConfigResources, indexSlot, visitedSlots,
nameBeforeStack, nameAfterStack, postOrderedList,
othersList,true);
nameBeforeStack.remove(facesConfig.getName());
}
}
else
{
pointingResource = true;
}
}
}
for (OrderSlot slot : facesConfig.getOrdering().getAfterList())
{
if (slot instanceof FacesConfigNameSlot)
{
FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
//The resource pointed is not added yet?
boolean alreadyAdded = false;
for (FacesConfig res : postOrderedList)
{
if (nameSlot.getName().equals(res.getName()))
{
alreadyAdded = true;
break;
}
}
if (!alreadyAdded)
{
int indexSlot = -1;
//Find it
for (int i = 0; i < appConfigResources.size(); i++)
{
FacesConfig resource = appConfigResources.get(i);
if (resource.getName() != null && nameSlot.getName().equals(resource.getName()))
{
indexSlot = i;
break;
}
}
//Resource founded on appConfigResources
if (indexSlot != -1)
{
pointingResource = true;
//Add to nameStac
nameAfterStack.add(facesConfig.getName());
resolveConflicts(appConfigResources, indexSlot, visitedSlots,
nameBeforeStack, nameAfterStack, postOrderedList,
othersList,true);
nameAfterStack.remove(facesConfig.getName());
}
}
else
{
pointingResource = true;
}
}
}
if (facesConfig.getOrdering().getBeforeList().isEmpty() &&
facesConfig.getOrdering().getAfterList().isEmpty())
{
//Fits in the category "others", put at beginning
postOrderedList.add(0,appConfigResources.get(index));
}
else if (pointingResource || indexReferenced)
{
//If the node points to other or is referenced from other,
//add to the postOrderedList at the end
postOrderedList.add(appConfigResources.get(index));
}
else
{
//Add to othersList
othersList.add(appConfigResources.get(index));
}
}
else
{
//Add at start of the list, since does not have any ordering
//instructions and on the next step makes than "before others" and "after others"
//works correctly
postOrderedList.add(0,appConfigResources.get(index));
}
//Set the node as visited
visitedSlots[index] = true;
}
private FacesConfig getFacesConfig(List<FacesConfig> appConfigResources, String name)
{
for (FacesConfig cfg: appConfigResources)
{
if (cfg.getName() != null && name.equals(cfg.getName()))
{
return cfg;
}
}
return null;
}
private boolean containsResourceInSlot(List<OrderSlot> slots, String name)
{
for (OrderSlot slot: slots)
{
if (slot instanceof FacesConfigNameSlot)
{
FacesConfigNameSlot nameSlot = (FacesConfigNameSlot) slot;
if (name.equals(nameSlot.getName()))
{
return true;
}
}
}
return false;
}
}