All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.openejb.util.References Maven / Gradle / Ivy

There is a newer version: 4.7.5
Show newest version
/*
 * 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.openejb.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @version $Rev: 1153797 $ $Date: 2011-08-04 11:09:44 +0200 (Thu, 04 Aug 2011) $
 */
public class References {

    public static interface Visitor {
        String getName(T t);

        Set getReferences(T t);
    }

    public static  List sort(List objects, Visitor visitor) {

        if (objects.size() <= 1) {
            return objects;
        }

        final Map nodes = new LinkedHashMap();

        // Create nodes
        for (T obj : objects) {
            String name = visitor.getName(obj);
            Node node = new Node(name, obj);
            nodes.put(name, node);
        }

        // Link nodes
        for (Node node : nodes.values()) {
            for (String name : visitor.getReferences((T) node.object)) {
                Node ref = nodes.get(name);
                if (ref == null) throw new IllegalArgumentException("No such object in list: "+name);
                node.references.add(ref);
                node.initialReferences.add(ref);
            }
        }
        boolean circuitFounded = false;
        for (Node node : nodes.values()) {
            Set visitedNodes = new HashSet();
            if (!normalizeNodeReferences(node, node, visitedNodes)) {
                circuitFounded = true;
                break;
            }
            node.references.addAll(visitedNodes);
        }

        //detect circus
        if (circuitFounded) {
            Set circuits = new LinkedHashSet();

            for (Node node : nodes.values()) {
                findCircuits(circuits, node, new java.util.Stack());
            }

            ArrayList list = new ArrayList(circuits);
            Collections.sort(list);

            List all = new ArrayList();
            for (Circuit circuit : list) {
                all.add(unwrap(circuit.nodes));
            }

            throw new CircularReferencesException(all);
        }

        //Build Double Link Node List
        Node rootNode = new Node(null, null);
        rootNode.previous = rootNode;
        rootNode.next = nodes.values().iterator().next();

        for (Node node : nodes.values()) {
            node.previous = rootNode.previous;
            rootNode.previous.next = node;
            node.next = rootNode;
            rootNode.previous = node;
        }

        for (Node node : nodes.values()) {
            for (Node reference : node.references) {
                swap(node, reference, rootNode);
            }
        }

        List  sortedList= new ArrayList(nodes.size());
        Node currentNode = rootNode.next;
        while(currentNode != rootNode) {
            sortedList.add(currentNode.object);
            currentNode = currentNode.next;
        }
        return sortedList;
    }

    private static boolean normalizeNodeReferences(Node rootNode, Node node, Set referenceNodes) {
        if (node.references.contains(rootNode)) {
            return false;
        }
        for (Node reference : node.references) {
            if (!referenceNodes.add(reference)) {
                //this reference node has been visited in the past
                continue;
            }
            if (!normalizeNodeReferences(rootNode, reference, referenceNodes)) {
                return false;
            }
        }
        return true;
    }

    private static void swap(Node shouldAfterNode, Node shouldBeforeNode, Node rootNode) {
        Node currentNode = shouldBeforeNode;
        while(currentNode.next != rootNode) {
            if(currentNode.next == shouldAfterNode) {
                return;
            }
            currentNode = currentNode.next;
        }
        //Remove the shouldAfterNode from list
        shouldAfterNode.previous.next = shouldAfterNode.next;
        shouldAfterNode.next.previous = shouldAfterNode.previous;
        //Insert the node immediately after the shouldBeforeNode
        shouldAfterNode.previous = shouldBeforeNode;
        shouldAfterNode.next = shouldBeforeNode.next;
        shouldBeforeNode.next = shouldAfterNode;
        shouldAfterNode.next.previous = shouldAfterNode;
    }

    private static  List unwrap(List nodes) {
        ArrayList referees = new ArrayList(nodes.size());
        for (Node node : nodes) {
            referees.add((T) node.object);
        }
        return referees;
    }

    private static void findCircuits(Set circuits, Node node, java.util.Stack stack) {
        if (stack.contains(node)) {
            int fromIndex = stack.indexOf(node);
            int toIndex = stack.size();
            ArrayList circularity = new ArrayList(stack.subList(fromIndex, toIndex));

            // add ending node to list so a full circuit is shown
            circularity.add(node);

            Circuit circuit = new Circuit(circularity);

            circuits.add(circuit);

            return;
        }

        stack.push(node);

        for (Node reference : node.initialReferences) {
            findCircuits(circuits, reference, stack);
        }

        stack.pop();
    }

    private static class Node implements Comparable {
        private final String name;
        private Object object;
        private final List initialReferences = new ArrayList();
        private final Set references = new HashSet();
        private Node next;
        private Node previous;

        public Node(String name, Object object) {
            this.name = name;
            this.object = object;
        }

        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            final Node node = (Node) o;

            return name.equals(node.name);
        }

        public int hashCode() {
            return name.hashCode();
        }

        public int compareTo(Node o) {
            return this.name.compareTo(o.name);
        }

        public String toString() {
            return name;
            //return "Node("+ name +" : "+ Join.join(",", unwrap(initialReferences))+")";
        }
    }

    private static class Circuit implements Comparable {
        private final List nodes;
        private final List atomic;

        public Circuit(List nodes) {
            this.nodes = nodes;
            atomic = new ArrayList(nodes);
            atomic.remove(atomic.size()-1);
            Collections.sort(atomic);
        }

        public List getNodes() {
            return nodes;
        }

        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            final Circuit circuit = (Circuit) o;

            if (!atomic.equals(circuit.atomic)) return false;

            return true;
        }

        public int hashCode() {
            return atomic.hashCode();
        }

        public int compareTo(Circuit o) {
            int i = atomic.size() - o.atomic.size();
            if (i != 0) return i;

            Iterator iterA = atomic.listIterator();
            Iterator iterB = o.atomic.listIterator();
            while (iterA.hasNext() && iterB.hasNext()) {
                Node a = iterA.next();
                Node b = iterB.next();
                i = a.compareTo(b);
                if (i != 0) return i;
            }

            return 0;
        }

        public String toString() {
            return "Circuit(" + Join.join(",", unwrap(nodes)) + ")";
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy