/* * 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.tuscany.sca.core.invocation.impl; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Directed, weighted graph * * @param <V> The type of vertex object * @param <E> The type of edge object * * @version $Rev$ $Date$ */ public class PhaseSorter<V> implements Cloneable { private final Map<V, Vertex> vertices = new HashMap<V, Vertex>(); /** * Vertex of a graph */ public final class Vertex { private V value; // TODO: Do we want to support multiple edges for a vertex pair? If so, // we should use a List instead of Map private Map<Vertex, Edge> outEdges = new HashMap<Vertex, Edge>(); private Map<Vertex, Edge> inEdges = new HashMap<Vertex, Edge>(); private Vertex(V value) { this.value = value; } @Override public String toString() { return "(" + value + ")"; } public V getValue() { return value; } public Map<Vertex, Edge> getOutEdges() { return outEdges; } public Map<Vertex, Edge> getInEdges() { return inEdges; } } /** * An Edge connects two vertices in one direction */ public final class Edge { private Vertex sourceVertex; private Vertex targetVertex; public Edge(Vertex source, Vertex target) { this.sourceVertex = source; this.targetVertex = target; } @Override public String toString() { return sourceVertex + "->" + targetVertex; } public Vertex getTargetVertex() { return targetVertex; } public void setTargetVertex(Vertex vertex) { this.targetVertex = vertex; } public Vertex getSourceVertex() { return sourceVertex; } public void setSourceVertex(Vertex sourceVertex) { this.sourceVertex = sourceVertex; } } public void addEdge(V source, V target) { Vertex s = getVertex(source); if (s == null) { s = new Vertex(source); vertices.put(source, s); } Vertex t = getVertex(target); if (t == null) { t = new Vertex(target); vertices.put(target, t); } Edge edge = new Edge(s, t); s.outEdges.put(t, edge); t.inEdges.put(s, edge); } public void addVertext(V source) { Vertex s = getVertex(source); if (s == null) { s = new Vertex(source); vertices.put(source, s); } } public Vertex getVertex(V source) { Vertex s = vertices.get(source); return s; } public boolean removeEdge(V source, V target) { Vertex s = getVertex(source); if (s == null) { return false; } Vertex t = getVertex(target); if (t == null) { return false; } return s.outEdges.remove(t) != null && t.inEdges.remove(s) != null; } public void removeEdge(Edge edge) { edge.sourceVertex.outEdges.remove(edge.targetVertex); edge.targetVertex.inEdges.remove(edge.sourceVertex); } public void removeVertex(Vertex vertex) { vertices.remove(vertex.getValue()); for (Edge e : new ArrayList<Edge>(vertex.outEdges.values())) { removeEdge(e); } for (Edge e : new ArrayList<Edge>(vertex.inEdges.values())) { removeEdge(e); } } public Edge getEdge(Vertex source, Vertex target) { return source.outEdges.get(target); } public Edge getEdge(V source, V target) { Vertex sv = getVertex(source); if (sv == null) { return null; } Vertex tv = getVertex(target); if (tv == null) { return null; } return getEdge(getVertex(source), getVertex(target)); } @Override public String toString() { StringBuffer sb = new StringBuffer(); for (Vertex v : vertices.values()) { sb.append(v.outEdges.values()).append("\n"); } return sb.toString(); } public Map<V, Vertex> getVertices() { return vertices; } public void addGraph(PhaseSorter<V> otherGraph) { for (Vertex v : otherGraph.vertices.values()) { for (Edge e : v.outEdges.values()) { addEdge(e.sourceVertex.value, e.targetVertex.value); } } } private Vertex getFirst() { for (Vertex v : vertices.values()) { if (v.inEdges.isEmpty()) { return v; } } if (!vertices.isEmpty()) { throw new IllegalArgumentException("Circular ordering has been detected: " + toString()); } else { return null; } } public List<V> topologicalSort(boolean readOnly) { PhaseSorter<V> graph = (!readOnly) ? this : (PhaseSorter<V>)clone(); List<V> list = new ArrayList<V>(); while (true) { Vertex v = graph.getFirst(); if (v == null) { break; } list.add(v.getValue()); graph.removeVertex(v); } return list; } @Override public Object clone() { PhaseSorter<V> copy = new PhaseSorter<V>(); copy.addGraph(this); return copy; } }