Index: fedd/abac-src/rbtm/engine/AbstractProofNode.java
===================================================================
--- fedd/abac-src/rbtm/engine/AbstractProofNode.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/rbtm/engine/AbstractProofNode.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,341 @@
+package edu.stanford.peer.rbtm.engine;
+
+import java.util.*;
+
+import edu.stanford.peer.rbtm.credential.*;
+import edu.stanford.peer.rbtm.util.*;
+
+/**
+ * The parent class of all proof nodes. This is the base class which contains
+ * default implementations of all common methods.
+ */
+public abstract class AbstractProofNode implements ProofNode
+{
+    // The following two fields can't be changed by other classes.  
+    // If subclasses need to access them, use get methods
+
+    /** The EntityExpression this node is about. */
+    EntityExpression   _roleExp;  
+    
+    /** 
+     * The proof _graph this node is in, this reference is used while 
+     * processing this node 
+     */
+    ProofGraph       _graph;
+
+    /** Processing mode for subclassed node types */
+    public final boolean addRole = true;
+    
+    /** Nodes that can reach this node directly, evidences are credentials. */
+    protected ResultEvidenceMap  parents;
+
+    /** Nodes that this node can reach directly, evidecens are credentials. */
+    protected ResultEvidenceMap  children; 
+
+	/** Backward solutions on this node  */
+    protected ResultEvidenceMap  backwardSolutions;
+
+	/** Forward solutions on this node */
+    protected ResultEvidenceMap  forwardSolutions;
+
+    protected ArrayList  backwardListeners;
+    protected ArrayList  forwardListeners;
+
+    boolean backwardProcessed;
+    boolean forwardProcessed;
+
+    AbstractProofNode (ProofGraph graph, EntityExpression re, int trackType)
+    {
+	_graph = graph;
+	_roleExp = re;
+        Debug.debugInfo("A new node is created for " + re);
+
+        parents = new ResultEvidenceMap(trackType);  
+        children = new ResultEvidenceMap(trackType); 
+        backwardSolutions = new ResultEvidenceMap(trackType);
+	forwardSolutions = new ResultEvidenceMap(trackType);
+	
+	backwardListeners = new ArrayList(10);
+	forwardListeners = new ArrayList(10);
+    }
+
+    public ProofGraph getGraph() {
+	return _graph;
+    }
+    
+    public EntityExpression getRoleExp() {
+	return _roleExp;
+    }
+    
+    public ResultEvidenceMap getForwardSolutions() {
+	return forwardSolutions;
+    }
+    
+    public ResultEvidenceMap getBackwardSolutions() {
+	return backwardSolutions;
+    }
+    
+    public ResultEvidenceMap getChildren() {
+	return children;
+    }
+    
+    public ResultEvidenceMap getParents() {
+	return parents;
+    }
+    
+    /** 
+     * A single iteration of evidence gathering. This recursive method is 
+     * polymorphic and may be extended in child proof node implementations. 
+     * @param size the size of the evidence set (of credentials)
+     * @param target the parent expression to be found in the cred graph
+     */
+    public HashSet getChain(int size, EntityExpression target) {
+	return new HashSet(size);
+    }
+
+
+    public void invalidateForward() {
+    	Debug.debugInfo("Invalidate forward result on " + this);
+    	if(forwardProcessed) {
+	    forwardProcessed = false;
+	    //reuse the credential and update the forward search
+	    getGraph().addForwardNode(getRoleExp());
+	}
+    }
+
+    public void invalidateBackward() {
+    	Debug.debugInfo("Invalidate backward result on " + this);
+    	if(backwardProcessed) {
+	    backwardProcessed = false;
+	    //reuse the credential and update the backward search
+	    getGraph().addBackwardNode(getRoleExp());
+	}
+    }
+
+    public void backwardProcess() {
+	if (backwardProcessed) { return; }
+	Predicate p = getGraph().getPredicate();
+	EntityExpression expr = getRoleExp();
+	Debug.debugInfo("Backward processing " + this);
+	if(p == null) {	// cred mgr has null predicate
+	    // backwards compatibility for credential manager
+	    backwardSolutionAdded(this, expr);
+	    additionalBackwardProcess();
+	}
+	else {
+	    if(p.test(expr)) { 
+		// add this expression to the soln and stop
+		backwardSolutionAdded(this, expr);
+	    } else {	
+		// skip this soln and continue processing 
+		additionalBackwardProcess();
+	    }
+	}
+	backwardProcessed = true;
+    }
+    
+    // The method that does the work when we visit a node
+    public void forwardProcess() 
+    {
+	if (forwardProcessed) {
+	    return;
+	}
+	
+        // first step: go over all credentials that have this as subject
+        Debug.debugInfo("Forward processing " + this);
+        Iterator  credIt = _graph.findCredentialsBySubject(_roleExp);
+        while (credIt.hasNext()) { 
+            StaticCredential credential = (StaticCredential) credIt.next();
+            Debug.debugInfo("Find one credential: " + credential);
+            ProofNode node = _graph.addForwardNode(credential.getDefinedRole());
+	    node.addParent(this, credential);
+            //_graph.addProofEdge(this, node, credential);
+        }
+	
+		  additionalForwardProcess();
+		  forwardProcessed = true;
+		  
+		  // second step: find partial solutions which match this node's
+		  //              role expression, unless its an intersection
+		  if (_roleExp instanceof Intersection) { return;	}
+		  credIt = _graph.findCredentialsByPartialSubject(_roleExp);
+		  while (credIt.hasNext()) { 
+				StaticCredential credential = (StaticCredential) credIt.next();
+				ProofNode node = _graph.addForwardNode(credential.getSubject());
+				node.backwardProcess();
+				// Forward discovery of roles
+				//
+				// This is not reuired according to the algorithm from 
+				// "Distributed Credential Chain Discovery in Trust Management" 
+				// in JCS but is needed for credential discovery in ATN where 
+				// forward search takes place from sensitive roles.
+				node.forwardProcess();
+				//int j = 
+				//((Intersection) credential.getSubject()).getIndexOf(_roleExp);
+				//forward.solutionAdded(new PartialSolution(_roleExp, j));
+		  }
+    }
+    
+    abstract protected void additionalForwardProcess();
+    abstract protected void additionalBackwardProcess();
+    
+    
+    public void addBackwardListener(BackwardSolutionListener sl) {
+        Debug.debugInfo(sl + " is now listening on " + this + 
+			" for backward solutions");
+        backwardListeners.add(sl);
+    	propagateBackwardSolutionsTo(sl);
+    }
+    
+    public void addForwardListener(ForwardSolutionListener sl) {
+        Debug.debugInfo(sl + " is now listening on " + this + 
+			" for forward solutions");
+        forwardListeners.add(sl);
+    	propagateForwardSolutionsTo(sl);
+    }
+    
+    /**
+     * Add a node as a parent to this node
+     * @param  node: the parent node
+     */
+    public void addParent(ProofNode node, Object evidence) {
+        if (parents.putResultEvidence(node.getRoleExp(), evidence)) {  
+	    addForwardListener(node);
+        }
+    }
+    
+    public void addChild(ProofNode node, Object evidence) {
+	if (children.putResultEvidence(node.getRoleExp(), evidence)) {  
+	    addBackwardListener(node);
+	}
+    }
+    
+    public void backwardSolutionAdded(ProofNode s, BackwardSolution r)
+    {
+        if (backwardSolutions.putResultEvidence(r, s)) {   
+	    // when solution r is new
+            Debug.debugInfo("Backward solution added to: " + this + 
+			    " from: " + s + " value: " + r);
+	    propagateBackwardSolution(r);
+        }
+    }
+    
+    public void forwardSolutionAdded(ProofNode s, ForwardSolution r) {
+	/*
+       if (r instanceof PartialSolution) {
+            Intersection re = r.getIntersection();
+            Integer index = r.getNumber();
+            HashMap value = (HashMap) partialSols.get(re);
+            if (value == null) {   // first piece
+                value = new HashMap();
+                partialSols.put(re, value);
+            }
+            SmallSet evidences = value.get(index);
+            if (evidences == null) { // A new piece
+                evidences = new SmallSet(s);
+                value.put(index, evidences);
+                if (value.size() == re.getK()) { // have all pieces
+                    // Add an edge from current node to re
+                    // addEdge();
+                }
+            } else if (trackAll) {
+                evidences.add(s);
+            }
+			return;
+        } 
+	*/
+	if (forwardSolutions.putResultEvidence(r, s)) {
+	    Debug.debugInfo("Forward solution added to: " + this + 
+			    " from: " + s + " value: " + r);
+	    propagateForwardSolution(r);
+	}
+    }
+
+    /** propagate backward solutions to all listening nodes. */
+    protected void propagateBackwardSolutionsTo(BackwardSolutionListener listener)
+    {
+    	Object[] sols = backwardSolutions.resultSet().toArray();
+    	for (int i=0; i<sols.length; i++) {
+	    listener.backwardSolutionAdded(this, (BackwardSolution)(sols[i]));
+    	}
+    }
+    
+    protected void propagateForwardSolutionsTo(ForwardSolutionListener listener)
+    {
+    	Object[] sols = forwardSolutions.resultSet().toArray();
+    	for (int i=0; i<sols.length; i++) {
+	    listener.forwardSolutionAdded(this, (ForwardSolution)(sols[i]));
+    	}
+    }
+    
+    protected void propagateBackwardSolution(BackwardSolution g)
+    {
+    	Object[] listeners = backwardListeners.toArray();
+    	for (int i=0; i<listeners.length; i++) {
+    	    ((BackwardSolutionListener)listeners[i]).backwardSolutionAdded(this, g);
+    	}
+    }
+    
+    protected void propagateForwardSolution(ForwardSolution g)
+    {
+    	Object[] listeners = forwardListeners.toArray();
+    	for (int i=0; i<listeners.length; i++) {
+    	    ((ForwardSolutionListener)listeners[i]).forwardSolutionAdded(this, g);
+    	}
+    }
+    
+    public String toString() 
+    {
+		  return "node " + _roleExp;
+    }
+    
+
+    // boolean hasParent(ProofNode node) { return parents.containsResult(node._roleExp); }
+
+
+	//////////// code for SelectiveProofNode
+    /*
+     * The following two fields store desired goals.  Only desired goals are 
+     * passed through edges.  Setting them to null means all goals are 
+     * desired.
+     * In backward search, if child A.r only wants to see one solution, while 
+     * child A.r1.r2 wants to see all solutions.  All goals are desired, so
+     * they are passed to A.r as well.  But A.r should have only one desired
+     * solution, and so A.r will not propagate them further.
+     */
+    // SmallSet  backwardGoals = new SmallSet(); 
+    // SmallSet  forwardGoals = new SmallSet();
+
+    /* 
+    void enableBackwardGoal(EntityExpression g)
+    {
+        if (backwardGoals != null && ! backwardGoals.containsGoal(g)) { 
+    		// has not been enabled before
+            backwardGoals.addGoal(g);
+            if (backwardSoltuions.containsResult(g)) {
+    			propagateBackwardSolution(g);
+            }
+            // Enable this backward goal for all parents
+            Object[] list = parents.toArray();  // inform listeners
+            for (int i=0; i<list.length; i++) {
+                ((ProofNode)list[i]).enableBackwardGoal(g);
+            }
+        }
+    }
+
+    void enableAllBackwardGoals()
+    {
+        if (backwardGoals == null ) {
+            backwardGoals = null;
+            // if have been procesed, loop over all parents, and enable them
+            // if haven't been processed, just enable it
+        }
+    }
+    */
+} // End of class ProofNode
+
+
+
+
+
+
