/******************************************************************************* * Copyright (c) 2013 GoPivotal, Inc. * 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 * * Contributors: * GoPivotal, Inc. - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.boot.completions; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; import org.apache.commons.collections.MultiMap; import org.apache.commons.collections.map.MultiValueMap; import org.eclipse.core.runtime.Assert; import org.springsource.ide.eclipse.commons.completions.externaltype.ExternalType; /** * Thin wrapper around a {@link MultiMap} which is interpreted as edges of * a directed graph. * * Only operations that traverse edges from parent to child are supported. * Other operations would be too expensive to implement (require back pointers or * complete graph traversals). * * Note using raw types because it is based on an implementation of * {@link MultiMap} that doesn't use generics. * * @author Kris De Volder */ public class DirectedGraph { private MultiMap dgraph; public DirectedGraph() { this.dgraph = new MultiValueMap(); } /** * Retrieve all nodes in the graph that are reachable from a given starting node. * The starting node itself is not included in the result unless there is cycle * in the graph leading back to the starting node. */ @SuppressWarnings("rawtypes") public Set getDescendants(Object node) { Set descendants = new LinkedHashSet(); return getDescendants(node, descendants); } /** * Retrieve all nodes in the graph that are reachable from a given starting node. * The starting node itself is not included in the result unless there is cycle * in the graph leading back to the starting node. * * @param descendants a (emtpy) collection that will be used to collect the * result into (this allows client to determine the type of collection used * (e.g. HashSet versus LinkedHashSet). */ private Set<Object> getDescendants(Object node, Set<Object> descendants) { Assert.isLegal(descendants.isEmpty()); collectDescendants(node, descendants); return descendants; } @SuppressWarnings({ "rawtypes", "unchecked" }) private void collectDescendants(Object node, Set ancestors) { Collection children = (Collection) dgraph.get(node); if (children!=null && !children.isEmpty()) { for (Object parent : children) { boolean isNew = ancestors.add(parent); if (isNew) { collectDescendants(parent, ancestors); } } } } @SuppressWarnings("rawtypes") public Collection getSuccessors(ExternalType type) { return (Collection) dgraph.get(type); } public void addEdge(Object parent, Object child) { dgraph.put(parent, child); } /** * Get all nodes in the graph that have at least one successor. */ @SuppressWarnings("rawtypes") public Set getNonLeafNodes() { return dgraph.keySet(); } }