org.opendaylight.yangtools.yang.parser.util.TopologicalSort.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.yangtools.yang.parser.util.TopologicalSort.java

Source

/*
 * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.yangtools.yang.parser.util;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * Utility class that provides topological sort
 */
public final class TopologicalSort {

    /**
     * It isn't desirable to create instance of this class
     */
    private TopologicalSort() {
    }

    /**
     * Topological sort of dependent nodes in acyclic graphs.
     *
     * @param nodes graph nodes
     * @return Sorted {@link List} of {@link Node}s. Order: Nodes with no
     *         dependencies starting.
     * @throws IllegalStateException
     *             when cycle is present in the graph
     */
    public static List<Node> sort(Set<Node> nodes) {
        List<Node> sortedNodes = Lists.newArrayList();

        Set<Node> dependentNodes = getDependentNodes(nodes);

        while (!dependentNodes.isEmpty()) {
            Node n = dependentNodes.iterator().next();
            dependentNodes.remove(n);

            sortedNodes.add(n);

            for (Edge e : n.getInEdges()) {
                Node m = e.getFrom();
                m.getOutEdges().remove(e);

                if (m.getOutEdges().isEmpty()) {
                    dependentNodes.add(m);
                }
            }
        }

        detectCycles(nodes);

        return sortedNodes;
    }

    private static Set<Node> getDependentNodes(Set<Node> nodes) {
        Set<Node> dependentNodes = Sets.newHashSet();
        for (Node n : nodes) {
            if (n.getOutEdges().isEmpty()) {
                dependentNodes.add(n);
            }
        }
        return dependentNodes;
    }

    private static void detectCycles(Set<Node> nodes) {
        // Detect cycles
        boolean cycle = false;
        Node cycledNode = null;

        for (Node n : nodes) {
            if (!n.getOutEdges().isEmpty()) {
                cycle = true;
                cycledNode = n;
                break;
            }
        }
        Preconditions.checkState(!cycle, "Cycle detected in graph around node: " + cycledNode);
    }

    /**
     * Interface for nodes in graph that can be sorted topologically
     */
    public interface Node {
        Set<Edge> getInEdges();

        Set<Edge> getOutEdges();
    }

    /**
     * Interface for edges in graph that can be sorted topologically
     */
    public interface Edge {
        Node getFrom();

        Node getTo();
    }

    /**
     * Basic Node implementation.
     */
    public static class NodeImpl implements Node {
        private final Set<Edge> inEdges;
        private final Set<Edge> outEdges;

        public NodeImpl() {
            inEdges = Sets.newHashSet();
            outEdges = Sets.newHashSet();
        }

        @Override
        public Set<Edge> getInEdges() {
            return inEdges;
        }

        @Override
        public Set<Edge> getOutEdges() {
            return outEdges;
        }

        public void addEdge(Node to) {
            Edge e = new EdgeImpl(this, to);
            outEdges.add(e);
            to.getInEdges().add(e);
        }
    }

    /**
     * Basic Edge implementation
     */
    public static class EdgeImpl implements Edge {
        private final Node from;
        private final Node to;

        public EdgeImpl(Node from, Node to) {
            this.from = from;
            this.to = to;
        }

        @Override
        public Node getFrom() {
            return from;
        }

        @Override
        public Node getTo() {
            return to;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + Objects.hashCode(from);
            result = prime * result + Objects.hashCode(to);
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            EdgeImpl other = (EdgeImpl) obj;
            if (from == null) {
                if (other.from != null) {
                    return false;
                }
            } else if (!from.equals(other.from)) {
                return false;
            }
            if (to == null) {
                if (other.to != null) {
                    return false;
                }
            } else if (!to.equals(other.to)) {
                return false;
            }
            return true;
        }
    }

}