Sophie

Sophie

distrib > Mageia > 4 > x86_64 > by-pkgid > 81f1a0bfce24f81b88b147e76a061761 > files > 2

plexus-graph-0.13.1-8.mga4.noarch.rpm

$Id: CHANGELOG,v 1.59 2007/04/01 20:18:23 rconner Exp $

LEGAL STUFF
============================================================

Copyright (C) 1994-2007 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


INTRODUCTION
============================================================

This history is from the perspective of a Plexus user, as opposed to
someone who is working on the package itself.  For those who want the
details, check the CVS history.

I am using a typical hierarchical release numbering system.  Until
version 1.0, any change in the second number (0.1 -> 0.2, e.g)
signifies that the release is definitely not backward compatible.  A
change in the third number means that code which simply uses classes
from the library does not need to change, but classes, interfaces, or
methods may have been added.  So any new implementations or extensions
may have to change.

Releases are tagged "ver-x-y" for version x.y.  If I have to branch
again, I'll develop a tag naming scheme for that.


============================================================
v0.1

Initial version.


============================================================
v0.2

OVERVIEW:

- There is now an Edge inner interface of Graph, causing many changes.
  One intended side effect is that Edges may now point to other Edges.

- Removed the NodeIterator interface.

- Added an observable Graph facility.

- Major overhaul to GraphWrapper and its subclasses.

- Changes to DefaultGraph:
  - Implements ObservableGraph.
  - Moved AdjacencyList into DefaultGraph as a private inner class.
  - Traverser.remove() now works.
  - Traversers and edge iterators can usually tolerate changes to the
    underlying graph without throwing concurrent mod exceptions.
  - Changed the format of the text returned by toString().

- Bug fixes in AbstractGraph:
  - Self-edges for an undirected graph are now correctly counted twice
    by degree( node ).
  - Fixed a bug in the directed traverser() implementation where
    actions in one of a pair of sub-Traversers could invalidate the
    other.

- Other miscellaneous changes:
  - Graph.removeNode() now either returns true or false.
  - Removed Graph.add( Graph ).
    Added GraphUtils.add( Graph destination, Graph source ).
  - Removed GraphUtils.unmodifiableTraverser().
  - CompleteGraph, Path, Cycle, and CompleteTree now return Edges with
    consistent tails and heads.

DETAILS:

----------------------------------------

There is now an Edge inner interface of Graph.  All Graph
implementations in the Plexus library now provide their own Edge
implementations of this interface.  This is to correctly implement
Edge.equals(); see below for further info on this.  The following
changes have resulted:

- New Graph.Edge interface with the following methods:
   boolean isDirected();
   Object getUserObject();
   void setUserObject( Object object );
   Object getTail();
   Object getHead();
   Object getOtherEndpoint( Object node );

- Graph interface (and all implementations)
 - addEdge( object, tail, head ) now returns the newly created Edge
   object, or null if it didn't add it.
 - removed:
     boolean removeEdge( object )
     boolean removeEdge( tail, head )
     boolean removeEdge( object, tail, head )
     boolean containsEdge( object )
     boolean containsEdge( tail, head )
     boolean containsEdge( object, tail, head )
 - added:
     boolean removeEdge( Edge )
     boolean containsEdge( Edge )
 - getEdge( tail, head ) now returns an Edge instead of the contained
   user object.  This method now also works for multi-graphs,
   returning the first edge found.
 - edgeIterator() now returns an Iterator (returned objects implement
   Edge).
 - edgeIterator( tail, head ) now returns an Iterator (returned
   objects implement Edge).
 - Changed some formal parameter names from 'edge' to 'object' to be
   less confusing.  Variables named 'edge' should normally implement
   the Edge interface.

- EdgeIterator
 Removed.

- Traverser
 - getEdge() now returns an Edge.
 - Removed setEdge().

- class com.phoenixst.plexus.Edge
 Removed.

- ObjectEdge
 Removed.

- Added DefaultEdge, DefaultObjectEdge, and DefaultSimpleEdge.

- GraphUtils
 - Removed EMPTY_EDGE_ITERATOR.
 - Removed unmodifiableEdgeIterator().
 - singletonEdgeIterator() now takes a Graph and an Edge argument
   instead of a user-object, tail, and head.  In addition, it is
   modifiable.
 - singletonTraverser() now takes a Graph, Edge, and node arguments
   instead of a user-object, tail, and head.  In addition, it is
   modifiable.

- Weight
 - get/setWeight() now take an Edge argument instead of a
   user-object, tail, and head.

- AbstractGraph
 - removeEdge( Edge ) throws an UnsupportedOperationException if the
   graph is simple.  This is to avoid mutual recursion with
   edgeIterator( tail, head ).remove().

For the moment, Edge.isDirected() reflects whether or not the Graph
containing the edge is directed, but at some point in the future a
Graph will be allowed to have both directed and undirected edges.
Users of this library should use Edge.isDirected() if possible.

As for Edge.equals() (and hashCode), it is vitally important that two
Edges only be .equals() when they refer to the same actual edge in the
same graph.  Which edge this is does *not* change when the contained
user-defined object changes (and, hence, the contained user-defined
object should not be used in computing the Edge's hash code).  In a
multigraph, the endpoints and contained user-defined object are
generally not sufficiently distinguishing characteristics.  Accepting
the default implementation from Object, which uses reference equality,
should be preferred unless Edges are lazily created on demand.

----------------------------------------

Removed the NodeIterator interface.
- Graph.nodeIterator() now returns a simple Iterator.
- Traverser now extends Iterator directly.
- Removed GraphUtils.EMPTY_NODE_ITERATOR.
- Removed GraphUtils.singletonNodeIterator().
- Removed GraphUtils.unmodifiableNodeIterator().

----------------------------------------

Added an observable Graph facility.  Added ObservableGraph,
GraphEvent, GraphListener and ObservableGraphWrapper.  Added
unmodifiable and synchronized views for an ObservableGraph to
GraphUtils.

----------------------------------------

Nothing in the Graph interface prohibits Edges from pointing to other
Edges.  In other words, Edges can be used as nodes, and the
DefaultGraph implementation allows this.  These two aspects of any
particular Edge are independent.  Adding or removing an Edge as a node
has no impact upon the object's existence as an Edge, and vice versa.

Care should be taken when copying a Graph with Edges acting in this
way, as there are now dependencies on the order in which things are
done.  A node which happens to be an Edge must be created as an Edge
before being added to the Graph as a node.  The new GraphUtils.add(
Graph destination, Graph source ) method handles this correctly.

----------------------------------------

Moved AdjacencyList into DefaultGraph, as they are now way too tightly
coupled to be separate.  Much of AdjacencyList and the DefaultGraph
internals have changed as a result.  As a user of DefaultGraph, this
particular change has little effect, except that Traverser.remove()
now works.

As a side-effect, traversers and edge iterators are much more robust.
They can usually handle changes to the underlying graph without
throwing concurrent mod exceptions.  See the javadocs for particulars.

----------------------------------------

Major overhaul to GraphWrapper and its subclasses.  This update has
affected GraphWrapper, GraphTransformer, ObservableGraphWrapper, and
all the wrappers in GraphUtils.

Rewrote GraphWrapper to factor in a bunch of stuff previously
delegated to subclasses.  It now has protected methods that wrap and
unwrap nodes, user-defined edge objects, Edges, and the various
iterators from the underlying wrapped graph.  This localizes any
transformations that the wrapper might be performing into a few
methods rather than having them peppered throughout the code.

Nodes and user-defined edge objects are passed through unchanged by
default.  Edges, however, are always wrapped and know from which
GraphWrapper they were produced.  This is to make sure that an Edge
produced by one wrapper cannot be used by another, even if that
wrapper is of the same class.  Two Edges produced by different Graph
instances should never be .equals().

SynchronizedGraphWrapper now syncs on its iterator methods as well,
just in case they perform some non-trivial processing.

Added an InvertableTransformer interface and GraphTransformer now uses
two of these instead of four normal Transformers.


============================================================
v0.2.1

OVERVIEW:

This release adds a general capability for performing filtered edge
iteration and traversals.  Methods on Graph that are superceded by the
new functionality have been deprecated, and will be removed in version
0.3.

DETAILS:

----------------------------------------

Added interface specifications for the new filters.  To be consistent
with the required new interface for TraverserFilter, a new interface
was defined for EdgeFilter as well instead of reusing Predicate.

  EdgeFilter
    public boolean evaluate( Graph.Edge edge );

  TraverserFilter
    public boolean evaluate( Object baseNode, Graph.Edge edge );

The new methods on Graph are:

  Edge getEdge( EdgeFilter edgeFilter )
  Iterator edgeIterator( EdgeFilter edgeFilter )
  Object getAdjacentNode( Object node, TraverserFilter traverserFilter )
  Traverser traverser( Object node, TraverserFilter traverserFilter )

These Graph methods are now deprecated:

  Edge getEdge( Object tail, Object head )
  Iterator edgeIterator( Object tail, Object head )
  Traverser outTraverser( Object node )
  Traverser inTraverser( Object node )

----------------------------------------

Removed TraverserFactory and the constant instances of it from
GraphUtils.  A TraverserFilter can now be used to accomplish the same
thing.

----------------------------------------

Added the following to GraphUtils:
  direction bit mask constants
  a direction bit mask inversion method
  constant true and false Predicates
  some simple constant EdgeFilters
  some simple constant TraverserFilters

----------------------------------------

Added the following predicate and filter implementations:

  EqualsPredicate - a trivially simple Predicate
  EqualsEdgeFilter - a trivially simple EdgeFilter
  EqualsTraverserFilter - a trivially simple TraverserFilter
  DefaultEdgeFilter - a default EdgeFilter, see the javadocs
  DefaultTraverserFilter - a default TraverserFilter, see the javadocs

----------------------------------------

Added the following default filtering iterator implementations:

  FilteredEdgeIterator
  FilteredTraverser

----------------------------------------

Rewrote a lot of AbstractGraph, completely changing the method
interdependencies that existed before.  See the javadocs for details.


============================================================
v0.3

Removed the following deprected methods from Graph and
implementations:
  Edge getEdge( Object tail, Object head )
  Iterator edgeIterator( Object tail, Object head )
  Traverser outTraverser( Object node )
  Traverser inTraverser( Object node )

Added the following method to Graph and all implementations:
  getIncidentEdge( Object node, TraverserFilter traverserFilter )

Added a new com.phoenixst.plexus.util subpackage.

Moved the following classes (some of them private inner classes of
GraphUtils) to the new util subpackage:
  FilteredEdgeIterator
  FilteredTraverser
  EqualsEdgeFilter
  EqualsTraverserFilter
  SingletonEdgeIterator
  SingletonTraverser
  SynchronizedGraphWrapper
  SynchronizedObservableGraphWrapper
  UnmodifiableGraphWrapper
  UnmodifiableObservableGraphWrapper

Added TraverserEdgeIteratorAdapter to the util subpackage, which wraps
a Traverser to look like an edge Iterator.

Changed the parameter order for GraphUtils.singletonTraverser().

Added the following filter helper methods to GraphUtils:
  public static Graph.Edge getEdge( graph, edgeFilter )
  public static Iterator edgeIterator( graph, edgeFilter )
  public static Graph.Edge getIncidentEdge( graph, node, traverserFilter )
  public static Traverser traverser( graph, node, traverserFilter )

Updated AbstractGraph and GraphWrapper to use the new GraphUtils
filter helper methods.

Removed explicit mutex parameter versions for synchronized Graph
methods in GraphUtils.  They're still available as alternate
constructors for the newly separated classes.


============================================================
v0.4

----------------------------------------

Graphs are no longer explicitly directed/undirected or simple/multi.
Of course, any particular Graph implementation may choose to only have
directed edges, or it may disallow duplicate edges and self-loops, but
the Graph interface no longer enforces any such distinction.  As a
result of this, the following changes have been made:

Removed the following methods from Graph and all of its
implementations:
  boolean isSimple()
  boolean isDirected()

Changed the signature of Graph.addEdge() and all of its
implementations to:
  Edge addEdge( Object object,
                Object tail, Object head,
                boolean isDirected );

Since Graphs are no longer distinguished as directed or not,
Graph.outDegree() and Graph.inDegree() will no longer throw an
UnsupportedOperationException.

----------------------------------------

Added a capability to filter entire Graphs.  These are the new
interfaces and classes:

- GraphFilter: interface similar to EdgeFilter and TraverserFilter

- DefaultGraphFilter: default implementation of GraphFilter

- FilteredGraph: constructed with a Graph and a GraphFilter, presents
  just the subgraph that passes the filter

- util.FilteredNodeIterator: helper class

----------------------------------------

All example graphs except PetersenGraph now have directed edges.
PetersenGraph now extends IntegerNodeGraph and is lazy.

Join and Product now allow operands with any mixture of
directed/undirected edges.  Added a boolean isDirected parameter to
the Join constructor which sets the directedness of the created edges
between the two Join operands.

Added com.phoenixst.plexus.util.SingletonGraph class and a
GraphUtils.singletonGraph(node) method to create them.

Product Edge implementations now create their endpoints on demand.
Added some more efficiency FIXME's to Product.

Modified GraphUtils.add() to be more correct in behavior.  It will now
tolerate the destination graph not allowing particular nodes from the
source graph to be added.

Fixed some methods of returned Iterators not being synchronized in
SynchronizedGraphWrapper.

Updated overview and package docs.


============================================================
v0.5

Added Graph.degree( node, TraverserFilter ).
Removed Graph.out/inDegree( node ).

Removed Traverser.getOtherEndpoint().

Moved various copies of equals(a,b) methods into a single public
GraphUtils method.

----------------------------------------

Added the following interfaces:
  GraphView
  RootedGraphView
  OrientedForestView
  RootedTreeView

Added the following classes:
  AbstractOrientedForestView
  DefaultOrientedForestView
  DefaultRootedTreeView

----------------------------------------

Made FilteredGraph observable.

GraphWrapper now implements ObservableGraph.  The add/remove listener
operations will throw exceptions if the wrapped graph is not
observable.  ObservableGraphWrapper no longer extends GraphWrapper.

Removed:
  UnmodifiableObservableGraphWrapper
  SynchronizedObservableGraphWrapper
  GraphUtils.unmodifiableObservableGraph()
  GraphUtils.synchronizedObservableGraph()

Added ObservableGraphDelegate, a helper class for ObservableGraph
implementations.  Updated DefaultGraph, GraphWrapper, and
ObservableGraphWrapper to use ObservableGraphDelegate.

----------------------------------------

Added the following util classes:
  IteratorChain
  TraverserChain
  UnmodifiableIterator
  UnmodifiableTraverser
The IteratorChain in Jakarta commons-collections fails if a
sub-iterator is empty.  Mine is also a little different.  If/when
Jakarta fixes theirs, I'll update TraverserChain to mirror its
functionality.

Updated Join to use the new chain iterators.

Removed the Graph implementation NodeOffsetTransformer.  Added the
InvertibleTransformer implementation IntegerOffsetTransformer.
Modified Star, Wheel, and CompleteBipartiteGraph to take this into
account.

----------------------------------------

Moved this change log from README to new file CHANGELOG.  Added README
to distribution jar.

Added more jars to distribution build:
  plexus-core.jar - base package and util subpackage
  plexus-operations.jar - operations subpackage
  plexus-examples.jar - examples subpackage
The orignal plexus.jar is still all the class files.

Removed build.properties and added build.properties.sample.  By
default, compiler debug is now off.

Fix for random NPE on dual-processor machines.
Made a number of optimizations to DefaultGraph and FilteredGraph.


============================================================
v0.6

Added the following to the core plexus package:
  PruningTraverser
  Walker
  BreadthFirstTraverser
  PreOrderTraverser
  PostOrderTraverser
  DepthFirstTraverser
  ForestTreeAdapter

Removed Graph.isEmpty().

DefaultGraphFilter and FilteredGraph now check their constructor
arguments for being non-null.

Made internal filters used by FilteredGraph serializable.

AbstractOrientedForestView.getHeight() is no longer recursive, at the
expense of using more heap for a DepthFirstTraverser.

Changed the documented exceptional conditions for Traverser.getEdge()
and removeEdge().  Previously, these methods were specified to throw a
NoSuchElementException if no Edge was traversed to reach the last node
returned by next().  Now, getEdge() is specified to return null and
removeEdge() should throw an IllegalStateException.

----------------------------------------

Changed some of the semantics of RootedTreeView.  It is now an
OrientedForestView which is restricted to the descendants of a single
root node.  It is no longer necessary that all nodes of the underlying
graph be part of the tree.  Many RootedTreeView methods may
*optionally* throw a NoSuchNodeException if given a node not in the
tree, as documented in the javadocs.

Added a new method RootedTreeView.isTreeNode( node ) to help support
the new RootedTreeView semantics.

Changed the following methods of DefaultRootedTreeView to throw an
exception if given a node not in the tree.  The other methods do not
perform this check.
    getRoot( node )
    getLeastCommonAncestor( aNode, bNode )
    getDepth( node )

----------------------------------------

Moved the following to the util subpackage:
  DefaultEdge
  DefaultObjectEdge
  DefaultSimpleEdge

Added the following to the util subpackage:
  EdgeIteratorTraverserAdapter
  TraverserNodeIteratorAdapter
  DefaultTraverserFactory
  ChildTraverserFactory
  DefaultIncidentEdgeGetter
  ParentEdgeGetter

Allow SingletonTraverser to use a null Edge.

----------------------------------------

Added new com.phoenixst.plexus.algorithms subpackage.

Added the following to the algorithms subpackage:
  AbstractDepthFirstForestView (package-private)
  DepthFirstTreeView
  DepthFirstForestView

----------------------------------------

Added new com.phoenixst.collections package.  This package contains
additions and/or fixes to the Jakarta-Commons Collections package.
Much of the functionality here has been made obsolete by the release
of version 3.0 of that package, but I can't upgrade the Plexus Graph
Library until other unrelated products have also been upgraded (Plexus
is currently in production use and must integrate well with JBoss,
struts, etc.).

Moved the following to the collections package:
  plexus.InvertibleTransformer
  plexus.EqualsPredicate (renamed to EqualPredicate)
  plexus.util.IteratorChain
  plexus.util.UnmodifiableIterator

Added the following to the collections package:
  AllPredicate
  AndPredicate
  AnyPredicate
  IdentityPredicate
  InstanceofPredicate
  NotPredicate
  OrPredicate
  PredicateUtils
  SimpleStack

Removed GraphUtils.TRUE and GraphUtils.FALSE.

----------------------------------------

Added the following to the examples subpackage:
  FileSystemForest
  CirculantGraph
  LoopGraph
  RandomGraphFactory

Cycle now inherits from LoopGraph.

----------------------------------------

Serialization updates across the whole library.
- Defined serialVersionUID for all serializable classes.
- The following are not serializable:
    Iterators
    Inner classes
- The following are serializable:
    All concrete Graph implementations
    All Edge implementations
    All concrete GraphView implementations
    All EdgeFilter implementations
    All TraverserFilter implementations
    All GraphFilter implementations
    All GraphUtils filter constants
    GraphEvent
    NoSuchNodeException
    EqualsPredicate
    IntegerOffsetTransformer

Updated some .equals() methods.

Added javadoc.linksource property to build.xml.  Have to remember to
set that property to "no" when building online docs.


============================================================
v0.6.1

This is the first step in an update to convert all uses of EdgeFilter
and TraverserFilter to use standard Predicates instead.  Basically,
this step adds the requisite methods and functionality to all
implementations, but not to the Graph interface itself.  This is so
that everything depending on Plexus will still build.  After dependent
projects have been updated, the next step will be to add the methods
to the Graph interface and deprecate the old filter usage.  Then,
finally, the filters will be removed.

Added accessor methods to compound Predicates in the collections
subpackage.

Adding legacy bridge classes to be used for imminent migration:
  EdgeFilterPredicateAdapter
  TraverserFilterPredicateAdapter
  PredicateEdgeFilterAdapter
  PredicateTraverserFilterAdapter

Added
  DefaultEdgePredicate
  DefaultTraverserPredicate
  EqualsTraverserPredicate

Converted EdgeFilter use in DefaultGraphFilter to a Predicate.

Added predicate equivalents to all filter fields and methods in
GraphUtils.

Made the following classes use Predicates, and made
Edge/TraverserFilter constructors delegate to the new Predicate
constructors.
  plexus
    BreadthFirstTraverser
    DepthFirstTraverser
    PostOrderTraverser
    PreOrderTraverser
    Walker
  plexus.util
    DefaultIncidentEdgeGetter
    DefaultTraverserFactory
    FilteredEdgeIterator
    FilteredTraverser
  plexus.algorithms
    AbstractDepthFirstForestView
    DepthFirstForestView
    DepthFirstTreeView

Added these methods:
    Graph.Edge getEdge( Predicate edgePredicate )
    Iterator edgeIterator( Predicate edgePredicate )
    int degree( Object node, Predicate traverserPredicate )
    Object getAdjacentNode( Object node, Predicate traverserPredicate )
    Graph.Edge getIncidentEdge( Object node, Predicate traverserPredicate )
    Traverser traverser( Object node, Predicate traverserPredicate )
To these graph implementations:
  plexus
    DefaultGraph
    AbstractGraph
    GraphWrapper
    ObservableGraphWrapper
    FilteredGraph
  plexus.examples
    EmptyGraph
  plexus.util
    SingletonGraph
    SynchronizedGraphWrapper

Moved inner Product.OrderedPair class to a new top-level class in the
collections subpackage, and made it mutable.

Updated GraphTest.OrderdPair to extend the new public class.

Minor rewrite of EqualPredicate equals test, for possible efficiency
gain.

Javadoc and formatting updates, import cleanup, etc.


============================================================
v0.6.2

Added the following methods to the Graph interface:
    Graph.Edge getEdge( Predicate edgePredicate )
    Iterator edgeIterator( Predicate edgePredicate )
    int degree( Object node, Predicate traverserPredicate )
    Object getAdjacentNode( Object node, Predicate traverserPredicate )
    Graph.Edge getIncidentEdge( Object node, Predicate traverserPredicate )
    Traverser traverser( Object node, Predicate traverserPredicate )

Deprecated EdgeFilter and TraverserFilter.

Completely rewrote DefaultGraph to be optimized for Predicates instead
of Filters.

Removed EqualsEdgeFilter and EqualsTraverserFilter.

GraphUtils - Removed the following:
  Edge/TraverserFilter constants and inner classes.
  getEdge( Graph, EdgeFilter )
  edgeIterator( Graph, EdgeFilter )
  getIncidentEdge( Graph, node, TraverserFilter )
  traverser( Graph, node, TraverserFilter )

Rewrote the filter methods in AbstractGraph and GraphWrapper to
delegate using a filter-predicate adapter since the GraphUtils methods
they used to call have been removed.

Removed the filter-using constructors in the following classes:
  BreadthFirstTraverser
  DepthFirstTraverser
  PostOrderTraverser
  PreOrderTraverser
  Walker
  util.DefaultIncidentEdgeGetter
  util.DefaultTraverserFactory
  util.FilteredEdgeIterator
  util.FilteredTraverser
  algorithms.DepthFirstForestView
  algorithms.DepthFirstTreeView

Migrated the following to use Predicates.  Fully implemented the
Predicate or Predicate-using methods.
  FilteredGraph
  ObservableGraphWrapper
  util.DefaultIncidentEdgeGetter
  util.DefaultTraverserFactory
  examples.RandomGraphFactory

Rewrote DefaultOrientedForestView to use Predicates.  Added Predicate
constructors to DefaultRootedTreeView and made filter constructors
delegate to them.

Removed filter methods completely from examples.EmptyGraph, they are
now inherited from AbstractGraph.


============================================================
v0.7

Removed EdgeFilter, TraverserFilter, all implementations of them, and
all other references to them.


============================================================
v0.7.1

Deprecated the following methods on Graph (to be removed in 0.8):
  int nodeSize()
  int edgeSize()
  void clear()
  Iterator nodeIterator()
  Iterator edgeIterator()
  Iterator edgeIterator( Predicate )
  Traverser traverser( node )

Added the following methods to the Graph interface:
  Collection nodes( Predicate nodePredicate )
  Collection edges( Predicate edgePredicate )
  Collection adjacentNodes( Object node, Predicate traverserPredicate )
  Collection incidentEdges( Object node, Predicate traverserPredicate )
  Object getNode( Predicate nodePredicate )

The Collection-returning methods return views.  That is, they reflect
the current state of the underlying Graph and are write-through.
Although none of the Collection views implemented in Plexus support
add(), they do support removal.  Note that removing a node from an
adjacentNodes() view will remove one instance of the node from being
adjacent, it will not remove the node from the graph.  In other words,
it will remove one connecting edge.

Just about every Graph implementation has changed as a result.  Added
a bunch of support classes to help with this (all com.phoenixst...)

  collections.AbstractSingletonCollection
  collections.AbstractUnmodifiableCollection
  collections.CollectionWrapper
  collections.CompositeCollection
  collections.FilteredCollection
  collections.FilteredIterator

  plexus.util.AbstractEdgeCollection
  plexus.util.AbstractNodeCollection
  plexus.util.AdjacentNodeCollection
  plexus.util.IncidentEdgeCollection
  plexus.util.SingletonEdgeCollection
  plexus.util.SingletonNodeCollection
  plexus.util.TraverserAdjacentNodeIteratorAdapter

----------------------------------------

The new FilteredIterator is a much more robust version than previous
attempts.  It now implements remove() by calling remove() on the
wrapped iterator if it hasn't advanced the underlying iterator.  If
the underlying iterator has been advanced, then it delegates to a
protected remove( Object ) method which throws an exception by
default.  FilteredEdgeIterator and FilteredNodeIterator now extend
this class, and FilteredTraverser is modeled after it.

Extensions behave as follows for these cases:
- FilteredCollection.iterator().remove() delegates to
  Collection.remove( Object ).
- FilteredNodeIterator delegates to Graph.removeNode( Object ).
- FilteredEdgeIterator delegates to Graph.removeEdge( Object ).

----------------------------------------

Removed the GraphFilter interface and the DefaultGraphFilter
implementation.  FilteredGraph now takes a node and edge Predicate
instead.  Also, FilteredGraph internally handles the logic to test
that the endpoints of an edge pass the node filter before testing the
edge filter, so it is no longer the user's responsibility to deal with
this.  The wrapped graph may be given an AndPredicate for an edge
filter, depending upon the constructor arguments.

----------------------------------------

Added the following methods to ObservableGraphDelegate:
- GraphListener[] getGraphListeners()
- void removeAllGraphListeners()

----------------------------------------

Completely rewrote GraphWrapper and its subclasses
(SynchronizedGraphWrapper, UnmodifiableGraphWrapper, and
GraphTransformer).  The protected methods which can be overridden are
now:

  Object wrapNode( Object node )
  Object unwrapNode( Object node )
  Object wrapEdgeObject( Object edgeObject )
  Object unwrapEdgeObject( Object edgeObject )
  EdgeWrapper createEdge( Graph.Edge edge )
  Traverser wrapTraverser( Traverser traverser )
  Predicate wrapNodePredicate( Predicate nodePredicate )
  Predicate wrapEdgePredicate( Predicate edgePredicate )
  Predicate wrapTraverserPredicate( Predicate traverserPredicate )

Subclasses now should not handle the possibility that a node might be
also be an edge within the wrap/unwrapNode() methods.  This case is
dealt with before those methods see the object.

The Predicate wrapper methods already do a great deal of translation
on the argument, if it is a standard Predicate instance (a GraphUtils
constant Predicate, a DefaultEdgePredicate, etc.).  These should only
be overridden to handle application specific cases, and then they
should delegate to the implementation defined in GraphWrapper if it is
not such a case.

----------------------------------------

Removed the following methods from GraphUtils:
  Iterator edgeIterator( graph, edgePredicate )
  Graph.Edge getEdge( graph, edgePredicate )
  Graph.Edge getIncidentEdge( graph, node, traverserPredicate )
  Traverser traverser( graph, node, traverserPredicate )

----------------------------------------

Factored out the reaping functionality used by DefaultGraph into a
more general implementation in the com.phoenixst.collections package
(Reapable, Reaper, and ReapableCollection).


============================================================
v0.8

Removed the following deprecated methods from Graph and all of its
implementations:

  int nodeSize()
  int edgeSize()
  void clear()
  Iterator nodeIterator()
  Iterator edgeIterator()
  Iterator edgeIterator( Predicate )
  Traverser traverser( node )

Renamed AbstractGraph.toBeRenamed(node) to traverser(node).

Added SynchronizedCollection to the collections subpackage.  This
differs from the one provided by java.util.Collections in that the
mutex can be specified in the constructor.  Rewrote SynchronizedGraph
to use this new Collection wrapper.


============================================================
v0.9

Removed DefaultEdgePredicate and DefaultTraverserPredicate.  Added new
interfaces EdgePredicate and TraverserPredicate.  Added new factory
classes EdgePredicateFactory and TraverserPredicateFactory.  See the
javadocs for details.

----------------------------------------

Plexus now uses Log4J.  See the README for details.

A default log4j.properties file is packaged in plexus.jar and
plexus-core.jar, so that using Plexus does not *require* manual
configuration from the user.  The bundled log4j.properties file
defines a standard ConsoleAppender and sets the Level of the
"com.phoenixst" Logger to WARN.  If you have your own log4j
configuration which defines an appender at or above "com.phoenixst",
then it will also handle logs from Plexus.  In particular, if you
define a ConsoleAppender for the root Logger, then all logs from
Plexus will go to the console twice, which is probably not what you
want.

----------------------------------------

Added LoggingSupport, LoggingCollection, and LoggingIterator to the
collections subpackage.  Added LoggingGraph and LoggingTraverser to
the main package and the util subpackage, respectively.

LoggingSupport is a simple base class with some useful methods that is
extended by the other Logging classes.

These Logging classes are all wrappers which log the invocation of
every method of the implemented interface, both arguments and return
values.  LoggingCollection and LoggingGraph also log invocations of
equals(), hashCode(), and toString().  Thrown Exceptions are neither
caught nor logged.  Alternate constructors allow the user to specify
both the Logger to use and the Level at which to log.

----------------------------------------

ObservableGraphDelegate now logs each invocation of fireXXX() to a
Logger and Level optionally specified by the constructor.  Any
exceptions thrown by listeners are logged to the ERROR Level.  If the
Logger and Level are not specified, they default to
"com.phoenixst.plexus.util.ObservableGraphDelegate" and DEBUG.

Graph implementations which use an ObservableGraphDelegate now supply
their own logger.  These include DefaultGraph, FilteredGraph,
GraphWrapper, and ObservableGraphWrapper.  The event Logger for
DefaultGraph is "com.phoenixst.plexus.DefaultGraph.Event", just in
case the user wants to log those events at a different level than
DefaultGraph's normal logging output (of which there isn't any at the
moment).

----------------------------------------

Added some debug logging to the following classes:

  DefaultGraph
  BreadthFirstTraverser
  DepthFirstTraverser
  PreOrderTraverser
  PostOrderTraverser
  DepthFirstForestView
  DepthFirstTreeView

Added some debug logging to:

   GraphUtils.add( Graph destination, Graph source )

Added these protected constructors to DefaultGraph which allow
subclasses to specify a different logger to use.

  protected DefaultGraph( Logger logger, Logger eventLogger )
  protected DefaultGraph( Graph g, Logger logger, Logger eventLogger )

----------------------------------------

Fixed bugs in ObservableGraphWrapper:
  nodes( Predicate ).containsAll( Collection )
  edges( Predicate ).containsAll( Collection )

----------------------------------------

Changed when the protected event delivery extension points are called
in DefaultGraph.  They are now called after all events have been
delivered.  Added new extension points which are called before any
events have been delivered.  As an example, the sequence for removing
a node is now:

  nodeRemoving( node )
  remove incident edges (which causes its own events/notifications)
  actually remove the node from internal structures
  fire nodeRemoved events
  nodeRemoved( node )

The pre-event methods are called before any action is taken, but after
it has been verified that the action is possible.  For example,
nodeRemoving() won't be called on a node that is not present in the
graph, and will be called before removing any incident edges.

----------------------------------------

Added protected DefaultGraph.createEdge(...) method, which allows
subclasses to override the kind of Graph.Edge created when an edge is
added to the graph.  This method should simply create the requested
edge, without checking to see whether it already exists.  DefaultGraph
will not allow two edges which are .equals() in the same adjacency
list.  The addEdge() method has been updated to return null if the new
edge already exists in either endpoint's adjacency list.

----------------------------------------

These Predicate implementations now implement .equals() (and
hashCode()) semantically:

- all implementations in the collections subpackage
- All Predicates produced by EdgePredicateFactory and
  TraverserPredicateFactory
- Internal implementations in FilteredGraph, which it may pass to the
  wrapped graph
- EqualsTraverserPredicate

----------------------------------------

Refactored Product to be more efficient in its implementation of
Iterators and Traversers.


============================================================
v0.10

Added a new traversals subpackage and moved the following classes and
interfaces there:

  BreadthFirstTraverser
  DepthFirstTraverser
  PostOrderTraverser
  PreOrderTraverser
  PruningTraverser
  Walker

Added TopologicalSortTraverser and GraphStructureIterator to the
traversals subpackage.  Rewrote GraphUtils.add() to use the new
GraphStructureIterator.

----------------------------------------

Separated the forest/tree interaces from GraphView.  This will allow
both forest/tree implementations that are views (as before) and those
that simply are graphs, or even implementations that are neither.

Added new interfaces:
  Rooted
  OrientedForest
  RootedTree

Removed interfaces:
  RootedGraphView
  OrientedForestView
  RootedTreeView

Added DefaultOrientedForest, which is an extension of DefaultGraph
that also implements the OrientedForest interface.  It provides an
implementation where the parent/child relationships are "hard-wired"
in the internal representation.  Once an edge is created, it is always
either a forest edge or not.  This fills the use case where whether or
not an edge is forest has nothing to do with its endpoints, direction,
or contained user-defined object.  It is also more efficient to
traverse than predicate-based views.  Note that there is nothing
preventing a forest GraphView from wrapping a DefaultOrientedForest
and presenting a different forest structure; it is fundamentally still
a Graph after all.

Added a rootNodes() method to the OrientedForest interface.  Changed
the name of DepthFirstForestView.getRoots() to the new method.  The
implementations of rootNodes() for DefaultOrientedForest and
DefaultOrientedForestView are lazy.

Renamed AbstractOrientedForestView to AbstractOrientedForest.

ForestTreeAdapter now takes an OrientedForest and implements
RootedTree.

FileSystemForest now implements Graph directly instead of GraphView.

Added the following helper methods to GraphUtils:
   Object getLeastCommonAncestor( OrientedForest forest,
                                  Object a, Object b )
   Object getFirstCommonNode( Transformer incidentEdgeGetter,
                              Object a, Object b )

----------------------------------------

Updated the following classes to use OrientedForest instead of
OrientedForestView:

  BreadthFirstTraverser
  DepthFirstTraverser
  PostOrderTraverser
  PreOrderTraverser
  Walker
  ChildTraverserFactory
  ParentEdgeGetter

Each of the above Traverser implementations (Breadth, Depth, PreOrder,
PostOrder, & Walker) now exposes a previously private constructor of
the following form (the Transformer for Walker should return an
incident edge rather than a Traverser):

    public BreadthFirstTraverser( Object startNode,
                                  Graph graph,
                                  Transformer traverserFactory )

The Traverser constructors which use an OrientedForest (like this
one):

    public BreadthFirstTraverser( Object startNode,
                                  OrientedForest forest )

Now have the behavioral restriction that startNode cannot be removed
by the remove() method (this form of the Walker constructor is
completely unmodifiable).  If it is necessary to allow the removal of
the startNode, then the newly exposed constructor above must be used.

----------------------------------------

Changed how the protected DefaultGraph.createEdge() method works by
adding an extra argument that can be supplied by subclasses.  Added a
protected addEdge() method which takes that extra argument and passes
it on to createEdge().  This was to solve an operation ordering issue
with DefaultOrientedForest, so that created edges are fully formed
when event delivery to listeners takes place.

----------------------------------------

Added Identifier to the collections subpackage.

----------------------------------------

Made PetersenGraph a singleton.


============================================================
v0.11

Added TrivialOrientedForestView, ForestTreeExtension.

Added OrderedPair.get/setFirst/Second() convenience methods.  Added a
no-arg OrderedPair constructor, which inits the elements to null.

Changed all usages for Predicates used in a Traverser context (the
ones whose evaluate() methods are expecting List arguments) to use
OrderedPair objects exclusively.

Rewrote Product to only use OrderedPairs for nodes.

Made Identifier serializable.

Changed some usages like this:
    graph.degree( node, predicate ) == 0;
to this:
    graph.getIncidentEdge( node, predicate ) == null;
The extra overhead should be minimal in those cases where it is worse,
but in many instances it will perform much better.

Added GraphUtils.directionFlagsToString( int flags ) method.

Implemented toString() for default EdgePredicate and
TraverserPredicate implementations.

Added classpath attribute to test.compile target.

Minor javadoc fixes.


============================================================
v0.12

Updated to use JDK 1.5, which is now required.

Added version numbers to the jar filenames.

----------------------------------------

Added the following to the collections package:
  UnorderedPair
  ContainsPredicate
  ClosureChain
  TransformerChain

Added the following to the util subpackage:
  ForwardingGraphListener
  FilteredGraphListener
  TransformingGraphListener

Renamed IntegerNodeGraph to AbstractIntegerNodeGraph.

Added CharSequence GraphUtils.getTextValue( edge, includeUserObject? ),
a convenience method for use by Graph.Edge.toString() implementations.

Many classes have changed serialization UID's, including
DefaultOrientedForest, but not DefaultGraph.

----------------------------------------

Changed from throwing an NPE for null arguments to throwing an
IllegalArgumentException.

Fixed a minor synchronization bug in ObservableGraphDelegate.

Removed synchronization from DefaultGraph.add/removeGraphListener().

Changed ForestTreeExtension.isTreeNode() to return false only if a
NoSuchNodeException is thrown by the delegate forest, not if any
Exception is thrown.

The CompositeCollection, IteratorChain, and TraverserChain constructors
now copy their array-valued arguments.

----------------------------------------

Added constructors to all classes that didn't have one, removing any
reliance on the default no-arg constructor (except for anonymous
classes).

Avoid calling overridable methods in constructors.

Made inner classes as private as possible, and static when not too
onerous.

Made fields, methods, and constructors as private as possible, and
final when possible.  In some cases, protected get() accessors were
added for subclass use.

Moved some initialization from constructors to declarations.

Rename some identifiers to be more descriptive.

Used StringBuilder instead of StringBuffer or the concat operator.

Better exception messages.

----------------------------------------

Renamed CloneableTestCase to AbstractCloneableTestCase.

Renamed GraphTest to AbstractGraphTest.


============================================================
v0.12.1

Fixed a bug in a few OrientedForest.getHeight() implementations where
the result would be one greater than it should have been.

Added GraphUtils.NULL_GRAPH, an immutable, constant ObservableGraph
instance with no nodes or edges.

Moved the definition of GraphUtils.EMPTY_TRAVERSER into a private inner
class and made it Serializable.

The internal Predicate implementations in DefaultOrientedForest now
implement Serializable.


============================================================
v0.13

Plexus has been updated to use Jakarta-Commons Collections version
2.1.1, and the resulting deprecation warnings have been removed.  This
version will not work with version 2.1, clients *must* upgrade.  It
should now be safe to use 3.1, although I haven't tried it.  There
will be some naming conflicts with classes from that version and the
collections sub-package here.

----------------------------------------

A fundamental change has been made to an assumption concerning Edge
identity in Plexus, that a given Edge could only be in one Graph.
Previously, it had been considered best practice that different Graphs
should not produce Graph.Edge instances which could be .equals() to
one another.  This behavioral restriction is no longer assumed or even
encouraged.

There are two reasons for doing this.  One is that the overhead
involved with creating the wrapper edges can be significant,
especially if they are serializable, since they must keep track of the
Graph which created them.  The other is that it is extremely
inconvenient for Graphs which are views of other Graphs (unmod, sync,
filtered, forest->tree, etc.) to not be consistent with each other.

An adverse side-effect is that a Graph which delegates to more than
one other Graph will not necessarily be able to tell from which of its
delegates a particular Edge comes.

----------------------------------------

ObservableGraphDelegate now uses a CopyOnWriteArrayList internally to
maintain its list of listeners.  Adding or removing a listener will be
slower, but event firing will be faster since it no longer requires
synchronization.  The fireXxx methods will no longer perform any
logging if there are no registered listeners; there is now an early
return for that case.

ForwardingGraphListener, FilteredGraphListener, and
TransformingGraphListener now maintain a WeakReference to their
wrapped ObservableGraphDelegate.  If these listeners ever receive an
event and the Reference has been cleared, they will remove themselves
as listeners from the Graph which was the source of the event.

Rewrote the listener handling in DefaultGraph, SynchronizedGraph,
UnmodifiableGraph, FilteredGraph, LoggingGraph, GraphWrapper, and
ObservableGraphWrapper.  They no longer create and dispose of the
internal ObservableGraphDelegate and/or forwarding listeners when the
set of listeners changes between empty and non-empty.  Since the
utility classes now return quickly in the empty case, there is no
compelling reason for the extra code.

Added a hasListeners() method to ObservableGraphDelegate.  The
removeGraphListener( listener ) method now has return type void.

Added null checks to the add/removeGraphListener( listener ) methods
of ObservableGraphDelegate.

----------------------------------------

Separated the Reaper implementation into an interface (Reaper) and
implementation (RunnableReaper).  The interface defines only this
method:

  Reference createReference( Reapable reapable, Object referent );

Note that createReference() is now defined to return a general
Reference, rather than a WeakReference in particular.  A Reaper
implementation shouldn't create PhantomReferences if the referent
needs to be retrievable while it is still referencable through other
paths, or if the Reference.clear() is not guaranteed to be called.

The RunnableReaper implementation differs from the original in that it
implements Runnable, but does not extend Thread.  Static factory
methods are provided which also create a Thread to run the Reaper.

Completely rewrote ReapableCollection.  It now explicitly maintains
its own storage array and is much more aggressive in reclaiming space.
In practice, this implementation should use at most half the space of
the previous one and will usually be 10-20% faster.

----------------------------------------

SynchronizedGraphWrapper and UnmodifiableGraphWrapper have been
renamed to SynchronizedGraph and UnmodifiableGraph.  These classes no
longer extend GraphWrapper, and also no longer wrap Edges from the
underlying delegate Graph.

The Edges retrieved from an UnmodifiableGraph (or by using the
GraphUtils.unmodifiableGraph() method) *allow* the contained
user-defined object to be modified.

The Edges retrieved from a SynchronizedGraph (or by using the
GraphUtils.synchronizedGraph() method) are not synchronized.

----------------------------------------

FilteredGraph, ObservableGraphWrapper, and GraphWrapper are no longer
serializable, but have been rewritten to support serializable
subclasses.  See Effective Java, item #54, for a description of the
usage pattern which GraphWrapper and GraphTransformer use.

GraphUtils.EMPTY_TRAVERSER is no longer serializable.

Made CompositeCollection serializable.

Added null element checks to the constructors and deserialization of
AllPredicate, AnyPredicate, CompositeCollection, ClosureChain,
TransformerChain, IteratorChain, and TraverserChain.

Moved methods associated with serialization to just after
constructors, since they are related.

----------------------------------------

Join no longer checks that its operands have disjoint node sets,
although it will definitely behave strangely if they aren't.

Join no longer wraps Edges originating from its delegate graphs.

The Product constructor no longer checks that its operand graphs have
more than zero nodes.

The Edges produced by Product graphs no longer reference the enclosing
Product, and so that is not used as a distinguishing factor in
Edge.equals().  So, if you create two Products of the same two operand
Graphs, their edges will be indistinguishable.  As a side effect, the
Edge serialization has changed.

Refactored the internal classes of Join and Product.

----------------------------------------

The Logger and event Logger for DefaultGraph and DefaultOrientedForest
are no longer configurable through the constructors.  DefaultGraph now
uses a normal constant Logger.

Removed LoggingSupport and refactored its subclasses to use Log4J
objects directly.

Removed equals() and hashCode() from LoggingCollection and
LoggingGraph, since .equals() cannot be symmetric while simply
delegating to the wrapped object.

----------------------------------------

The Edge implementation of AbstractIntegerNodeGraph (and all of its
subclasses) no longer knows which Graph created it.  So the 0->1 Edge
from a Path is .equals() to the 0->1 Edge from a CompleteTree.

AllPredicate and AnyPredicate now (shallow) copy their constructor
arguments rather than using the provided Collection of Predicates
directly.  The getOperands() method now returns an unmodifiable List
rather than a reference to the internal data.

Added CartesianProduct to the collections sub-package.

Added CompositeCollection.getOperands().

Added toString() method to ObservableGraphWrapper.

Walker and DefaultGraph now use enums rather than int constants for
some internal state management.  No external changes should be visible
from this.


============================================================
v0.13.1

Fixed a bug in DefaultGraph.incidentEdges(node,predicate) where
constructing the incident edge collection with a null/true predicate
would cause contains/remove() to throw a NPE.

DefaultSimpleEdge no longer keeps track of its owning Graph, and so
its constructor has changed.

SimpleObjectEdge in the junit test suite no longer keeps track of its
owning Graph, and so its constructor has changed.