protected List applySortingAlgorithm()

in impl/src/main/java/org/apache/myfaces/config/DefaultFacesConfigurationMerger.java [247:446]


    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 = v.getNode();

            if (f.getOrdering() != null)
            {
                for (OrderSlot slot : f.getOrdering().getBeforeList())
                {
                    if (slot instanceof FacesConfigNameSlot nameSlot)
                    {
                        String name = nameSlot.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 nameSlot)
                    {
                        String name = nameSlot.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 = 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(v.getNode());
        }

        //5. add nodes without instructions at the end
        for (Vertex<FacesConfig> v : othersList)
        {
            sortedList.add(v.getNode());
        }

        //6. add before/after nodes
        for (Vertex<FacesConfig> v : beforeAfterOthersList)
        {
            FacesConfig f = 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 nameSlot)
                    {
                        String name = nameSlot.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 nameSlot)
                    {
                        String name = nameSlot.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;
    }