com.phoenixst.plexus.AbstractGraph.java Source code

Java tutorial

Introduction

Here is the source code for com.phoenixst.plexus.AbstractGraph.java

Source

/*
 *  $Id: AbstractGraph.java,v 1.59 2005/10/03 15:24:00 rconner Exp $
 *
 *  Copyright (C) 1994-2005 by Phoenix Software Technologists,
 *  Inc. and others.  All rights reserved.
 *
 *  THIS PROGRAM AND DOCUMENTATION IS PROVIDED UNDER THE TERMS OF THE
 *  COMMON PUBLIC LICENSE ("AGREEMENT") WHICH ACCOMPANIES IT.  ANY
 *  USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES
 *  RECIPIENT'S ACCEPTANCE OF THE AGREEMENT.
 *
 *  The license text can also be found at
 *    http://opensource.org/licenses/cpl.php
 */

package com.phoenixst.plexus;

import java.util.*;

import org.apache.commons.collections.Predicate;

import com.phoenixst.collections.*;
import com.phoenixst.plexus.util.*;

/**
 *  This class provides a skeletal implementation of the
 *  <code>Graph</code> interface, to minimize the effort required to
 *  implement this interface.  Any concrete extension of this class
 *  must override the following methods to provide a full
 *  implemnetation:
 *
 *  <UL>
 *    <LI>{@link #nodes() nodes()}
 *    <LI>{@link #edges() edges()}
 *    <LI>{@link #traverser(Object) traverser( node )}
 *  </UL>
 *
 *  <P>Alternately, an extension may override one or more of the
 *  following methods (which normally defer to those listed above) if
 *  doing so admits a more efficient solution.  In this case, the
 *  above methods should probably still be implemented correctly.
 *
 *  <UL>
 *    <LI>{@link #nodes(Predicate) nodes( nodePredicate )}
 *    <LI>{@link #edges(Predicate) edges( edgePredicate )}
 *    <LI>{@link #traverser(Object,Predicate) traverser( node, traverserPredicate )}
 *  </UL>
 *
 *  <P>Any modifiable concrete extensions of this class must also
 *  implement:
 *
 *  <UL>
 *    <LI>{@link #addNode(Object) addNode( node )}
 *    <LI>{@link #addEdge(Object,Object,Object,boolean) addEdge( object, tail, head, isDirected )}
 *    <LI>Modifying operations of the collection views and traversers
 *  </UL>
 *
 *  <P>The documentation for each non-abstract method in this class
 *  describes its implementation in detail. Each of these methods may
 *  be overridden if the graph being implemented admits a more
 *  efficient implementation.  Note that almost every method
 *  implementation here is written in terms of an iterator over the
 *  structure of this graph; these methods are all rather inefficient.
 *
 *  <P>The programmer should generally provide a void (no argument) and
 *  <code>Graph</code> constructor, as per the recommendation in the
 *  <code>Graph</code> interface specification.
 *
 *  @version    $Revision: 1.59 $
 *  @author     Ray A. Conner
 *
 *  @since      1.0
 */
public abstract class AbstractGraph implements Graph {

    ////////////////////////////////////////
    // Constructor
    ////////////////////////////////////////

    /**
     *  Protected constructor, called implicitly by subclasses.
     */
    protected AbstractGraph() {
        super();
    }

    ////////////////////////////////////////
    // Methods to be overridden by subclasses.
    ////////////////////////////////////////

    /**
     *  Returns a <code>Collection</code> view of all the nodes
     *  in this <code>Graph</code>.  This method is only called
     *  by {@link #nodes(Predicate) nodes( Predicate )}.
     */
    protected abstract Collection nodes();

    /**
     *  Returns a <code>Collection</code> view of all the
     *  <code>Graph.Edges</code> in this <code>Graph</code>.
     *  This method is only called by {@link #edges(Predicate)
     *  edges( Predicate )}.
     */
    protected abstract Collection edges();

    /**
     *  Returns an unfiltered <code>Traverser</code> over those
     *  <code>Graph.Edges</code> incident to the specified node.
     *  This method is only called by {@link
     *  #traverser(Object,Predicate) traverser( node, Predicate )}.
     */
    protected abstract Traverser traverser(Object node);

    ////////////////////////////////////////
    // Graph
    ////////////////////////////////////////

    /**
     *  This implementation throws an
     *  <code>UnsupportedOperationException</code>.
     */
    public boolean addNode(Object node) {
        throw new UnsupportedOperationException();
    }

    /**
     *  This implementation iterates over the nodes in this graph
     *  looking for the specified element.  If it finds the element,
     *  it removes the element using using the {@link
     *  Iterator#remove()} operation.
     *
     *  <P>Note that this implementation will throw an
     *  <code>UnsupportedOperationException</code> if the iterator
     *  returned by this graph's <code>nodes( null ).iterator()</code>
     *  method does not implement the <code>remove</code> method and
     *  this graph contains the specified node.
     */
    public boolean removeNode(Object node) {
        if (node == null) {
            for (Iterator i = nodes(null).iterator(); i.hasNext();) {
                if (i.next() == null) {
                    i.remove();
                    return true;
                }
            }
        } else {
            for (Iterator i = nodes(null).iterator(); i.hasNext();) {
                if (node.equals(i.next())) {
                    i.remove();
                    return true;
                }
            }
        }
        return false;
    }

    /**
     *  This implementation iterates over the nodes in this graph
     *  looking for the specified element.
     */
    public boolean containsNode(Object node) {
        if (node == null) {
            for (Iterator i = nodes(null).iterator(); i.hasNext();) {
                if (i.next() == null) {
                    return true;
                }
            }
        } else {
            for (Iterator i = nodes(null).iterator(); i.hasNext();) {
                if (node.equals(i.next())) {
                    return true;
                }
            }
        }
        return false;

    }

    /**
     *  This implementation throws an
     *  <code>UnsupportedOperationException</code>.
     */
    public Graph.Edge addEdge(Object object, Object tail, Object head, boolean isDirected) {
        throw new UnsupportedOperationException();
    }

    /**
     *  This implementation traverses over the edges in this graph
     *  incident on the tail of the specified <code>edge</code>.  If
     *  it finds the element, it removes the element using using the
     *  {@link Traverser#remove()} operation.
     *
     *  <P>Note that this implementation will throw an
     *  <code>UnsupportedOperationException</code> if the traverser
     *  returned by this graph's {@link #traverser(Object,Predicate)
     *  traverser( node, predicate )} method does not implement the
     *  <code>removeEdge</code> method and this graph contains the
     *  specified edge.
     */
    public boolean removeEdge(Graph.Edge edge) {
        if (edge != null) {
            Object tail = edge.getTail();
            if (!containsNode(tail)) {
                return false;
            }
            for (Traverser t = traverser(tail, null); t.hasNext();) {
                t.next();
                if (edge.equals(t.getEdge())) {
                    t.removeEdge();
                    return true;
                }
            }
        }
        return false;
    }

    /**
     *  This implementation traverses over the edges in this graph
     *  incident on the tail of the specified <code>edge</code>,
     *  looking for it and returning <code>true</code> if found.
     */
    public boolean containsEdge(Graph.Edge edge) {
        if (edge != null) {
            Object tail = edge.getTail();
            if (!containsNode(tail)) {
                return false;
            }
            for (Traverser t = traverser(tail, null); t.hasNext();) {
                t.next();
                if (edge.equals(t.getEdge())) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     *  This implementation counts the number of elements accessed by
     *  this graph's {@link #traverser(Object,Predicate) traverser(
     *  node, null )} method, counting self-loops twice.
     */
    public int degree(Object node) {
        int count = 0;
        for (Traverser t = traverser(node, null); t.hasNext();) {
            Object adjNode = t.next();
            if ((node == null) ? (adjNode == null) : node.equals(adjNode)) {
                count++;
            }
            count++;
        }
        return count;
    }

    /**
     *  This implementation counts the number of elements accessed by
     *  this graph's {@link #traverser(Object,Predicate) traverser(
     *  node, traverserPredicate )} method, without counting
     *  self-loops twice.
     */
    public int degree(Object node, Predicate traverserPredicate) {
        int count = 0;
        for (Traverser t = traverser(node, traverserPredicate); t.hasNext();) {
            t.next();
            count++;
        }
        return count;
    }

    /**
     *  This implementation delegates to {@link #nodes() nodes()},
     *  except for when the specified <code>nodePredicate</code> is
     *  either {@link FalsePredicate#INSTANCE} or an instance of
     *  {@link EqualPredicate}.  These two cases are optimized.
     */
    public Collection nodes(Predicate nodePredicate) {
        if (nodePredicate == null || nodePredicate == TruePredicate.INSTANCE) {
            return nodes();
        } else if (nodePredicate == FalsePredicate.INSTANCE) {
            return Collections.EMPTY_SET;
        } else if (nodePredicate instanceof EqualPredicate) {
            Object testNode = ((EqualPredicate) nodePredicate).getTestObject();
            if (!containsNode(testNode)) {
                return Collections.EMPTY_SET;
            }
            return new SingletonNodeCollection(this, testNode);
        } else {
            return new FilteredCollection(nodes(), nodePredicate);
        }
    }

    /**
     *  This implementation delegates to {@link #edges() edges()},
     *  except for when the specified <code>edgePredicate</code> is
     *  either {@link FalsePredicate#INSTANCE} or an instance of
     *  {@link EqualPredicate}.  These two cases are optimized.
     */
    public Collection edges(Predicate edgePredicate) {
        if (edgePredicate == null || edgePredicate == TruePredicate.INSTANCE) {
            return edges();
        } else if (edgePredicate == FalsePredicate.INSTANCE) {
            return Collections.EMPTY_SET;
        } else if (edgePredicate instanceof EqualPredicate) {
            Graph.Edge testEdge = (Graph.Edge) ((EqualPredicate) edgePredicate).getTestObject();
            if (!containsEdge(testEdge)) {
                return Collections.EMPTY_SET;
            }
            return new SingletonEdgeCollection(this, testEdge);
        } else {
            return new FilteredCollection(edges(), edgePredicate);
        }
    }

    /**
     *  This implementation returns a new {@link
     *  AdjacentNodeCollection}.
     */
    public Collection adjacentNodes(Object node, Predicate traverserPredicate) {
        return new AdjacentNodeCollection(this, node, traverserPredicate);
    }

    /**
     *  This implementation returns a new {@link
     *  IncidentEdgeCollection}.
     */
    public Collection incidentEdges(Object node, Predicate traverserPredicate) {
        return new IncidentEdgeCollection(this, node, traverserPredicate);
    }

    /**
     *  This implementation returns the first node accessed by {@link
     *  #nodes(Predicate)} if present, otherwise it returns
     *  <code>null</code>.
     */
    public Object getNode(Predicate nodePredicate) {
        Iterator i = nodes(nodePredicate).iterator();
        return i.hasNext() ? i.next() : null;
    }

    /**
     *  This implementation returns the first <code>Edge</code>
     *  accessed by {@link #edges(Predicate)} if present, otherwise it
     *  returns <code>null</code>.
     */
    public Graph.Edge getEdge(Predicate edgePredicate) {
        Iterator i = edges(edgePredicate).iterator();
        return i.hasNext() ? (Graph.Edge) i.next() : null;
    }

    /**
     *  This implementation returns the other endpoint of the
     *  <code>Edge</code> returned by {@link
     *  #getIncidentEdge(Object,Predicate)} if present, otherwise it
     *  returns <code>null</code>.
     */
    public Object getAdjacentNode(Object node, Predicate traverserPredicate) {
        Graph.Edge edge = getIncidentEdge(node, traverserPredicate);
        return (edge != null) ? edge.getOtherEndpoint(node) : null;
    }

    /**
     *  This implementation returns the first <code>Edge</code>
     *  accessed by {@link #incidentEdges(Object,Predicate)} if
     *  present, otherwise it returns <code>null</code>.
     */
    public Graph.Edge getIncidentEdge(Object node, Predicate traverserPredicate) {
        Traverser t = traverser(node, traverserPredicate);
        if (!t.hasNext()) {
            return null;
        }
        t.next();
        return t.getEdge();
    }

    /**
     *  This implementation delegates to {@link #traverser(Object)
     *  traverser( node )}, except for when the specified
     *  <code>traverserPredicate</code> is either {@link
     *  FalsePredicate#INSTANCE} or an instance of {@link
     *  EqualsTraverserPredicate}.  These two cases are optimized.
     */
    public Traverser traverser(Object node, Predicate traverserPredicate) {
        if (traverserPredicate == null || traverserPredicate == TruePredicate.INSTANCE) {
            return traverser(node);
        } else if (traverserPredicate == FalsePredicate.INSTANCE) {
            return GraphUtils.EMPTY_TRAVERSER;
        } else if (traverserPredicate instanceof EqualsTraverserPredicate) {
            Graph.Edge testEdge = ((EqualsTraverserPredicate) traverserPredicate).getTestEdge();
            return ((GraphUtils.equals(node, testEdge.getTail()) || GraphUtils.equals(node, testEdge.getHead()))
                    && containsEdge(testEdge))
                            ? new SingletonTraverser(this, testEdge.getOtherEndpoint(node), testEdge)
                            : GraphUtils.EMPTY_TRAVERSER;
        } else {
            return new FilteredTraverser(traverser(node), traverserPredicate);
        }
    }

}