org.apache.openejb.util.References Maven / Gradle / Ivy
/*
* 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