The AP Library

Description | Download | Use

Please read first the AP Library Fact Sheet.

Description

Adaptive Programming (AP) is a programming technology where programs are split into cross-cutting building blocks in a novel way to control tangling and redundancy. In AP, at least one of the building blocks is represented by a graph and other building blocks refer to subgraphs of the graph without revealing the details of the subgraphs. This is a form of succinct specification of graphs similar to the hierarchical specification of graphs widely used in hardware and software designs. A succinct specification can be expanded to a flat representation that is usually much larger than the succinct representation.

AP is a special case of AOP. Connection to Aspect-Oriented Programming.

The AP Library contains the core algorithm for expanding a succinct representation of a graph into a flat, detailed representation of a graph. A succinct specification is given by a strategy graph. Definition: Given a graph G, a strategy graph S of G is any subgraph of the transitive closure of G. The flat representation of a strategy graph S with respect to G is (in many cases) the subgraph of G that consists of all paths in G that are expansions of paths in S.

The problem the AP Library solves is (in simplified form): Given as input a strategy graph S and a graph G, return the flat representation of S with respect to G. The flat representation is the set of paths in G defined by S and is called a traversal graph.

The AP Library deals with more complex graphs, namely class graphs that have several kinds of nodes and edges. The strategy graphs can also have constraints attached to their edges. And the AP Library deals with name maps, to allow to map nodes in the strategy graph to nodes in the class graph. The details are in Strategies Paper.

The AP Library has been developed as a part of DemeterJ and is heavily used. What are the applications of the AP Library outside DemeterJ? It is a useful technology to map graphs into other more complex graphs or to select subgraphs from more complex graphs. This is a very generic problem in hardware and software design and has therefore many applications. Check the Demeter page for many applications such as framework design, distributed programming, API implementations, Visitor Design pattern, expressing object collaborations, traversals, Aspect-Oriented Programming etc. For example, the graph nodes could be classes and the edges associations or the graph nodes could be components and the edges could be connectors.

Why is the AP Library useful to an architecture toolkit?. Because it allows for flexible specification of connections between components. See the work on Adaptive Plug-and-Play Components (OOPSLA 98).

Downloading and installing the AP Library

See the Demeter software installation guide.

Using the AP Library

  1. In your program, import the AP Library package (edu.neu.ccs.demeter.aplib.*.).
  2. Define classes implementing the six interfaces StrategyI, StrategyGraphI, ClassGraphI, EdgeI, NameMapI, and ConstraintMapI. Alternatively, you can use the provided class graph and strategy graph implementations, by importing edu.neu.ccs.demeter.aplib.cd.* and edu.neu.ccs.demeter.aplib.sg.* (see documentation for these packages below-- sorry, the API docs are just a skeleton currently).
  3. Construct StrategyI, ClassGraphI, NameMapI, and ConstraintMapI objects and call the TraversalGraph(S,G,N,B) constructor. Alternatively, you can just make StrategyI and ClassGraphI objects and call the TraversalGraph(S,G) constructor, which uses the identity name map and the null constraint map. You will then have a TraversalGraph object.
  4. To determine whether a particular node of the class graph is in the traversal graph, call the getNodeSet method on the TraversalGraph object; this returns null if it is not, or else an object of the class TraversalGraph.NodeSet, which represent a set of nodes in the traversal graph which are copies of the node in the class graph. Each copy of the node has an integer index corresponding to an edge in the strategy graph; you can query the NodeSet object with hasIndex to see whether the set contains a given index.
  5. Similarly, to determine whether a particular edge of the class graph is in the traversal graph, call getConstructionEdgeSet, getAlternationEdgeSet, or getInheritanceEdgeSet, all of which return an object of the class TraversalGraph.EdgeSet, which represent a set of copies of the edge.
The provided implementation for StrategyI, StrategyGraphI, and ConstraintMapI is the class StrategyGraph, which can be parsed from a reader or a string by these static methods:
  /** Read a strategy expression from a reader and normalize it. */
  public static StrategyGraph readFrom(Reader in) throws ParseException;

  /** Convert a string to a strategy expression and normalize it. */
  public static StrategyGraph fromString(String s);
The syntax for strategy expressions is described in the user manual.

The provided implementation for ClassGraphI is the class ClassGraph, which can be parsed from a reader or a string by these static methods:

  /** Read a class dictionary from a reader and normalize it. */
  public static ClassGraph readFrom(Reader in) throws ParseException;

  /** Convert a string to a class dictionary and normalize it. */
  public static ClassGraph fromString(String s);
The syntax for class dictionaries is also described in the user manual.

Alternatively, you can build a ClassGraph object using the no-arguments constructor and these methods:

  /** Add a construction edge named name from the node labeled
      source to the node labeled target. */
  public Part addConstructionEdge(String source, String name, String target);

  /** Add an alternation edge from the node labeled source to the
      node labeled target. */
  public Subclass addAlternationEdge(String source, String target);

  /** Add an inheritance edge from the node labeled source to the
      node labeled target. */
  public Superclass addInheritanceEdge(String source, String target);
Note that inheritance edges are not needed if your class graph is flat. If it is not flat, i.e. if you have alternation classes with outgoing construction edges, then you'll need to add an inheritance edge corresponding to every alternation edge (but in the opposite direction).

This method is also provided as a convenience on ClassGraph:

  /** Print the class dictionary corresponding to the subgraph
      determined by the traversal graph. */
  public void printTraversalEdges(TraversalGraph tg, PrintWriter out);

The Demeter team <dem@ccs.neu.edu>
Last modified: Mon Nov 27 06:35:33 EST 2000