package com.nailabs.abac.process; import edu.stanford.peer.rbtm.credential.*; import com.nailabs.abac.trust.*; import com.nailabs.abac.test.*; import java.util.*; /** * The strategy handles processing a working list of nodes in the trust target * graph to be processed. This version uses a combination of heuristics with * a depth first search method. */ public class StingyStrategy extends Strategy { /** A queue for operations which need to delay */ protected Hashtable delayedOps = new Hashtable(); /** * A list of sibling children of the current node being processed. Note, * this is an ordered stack. Node operations are added the bottom of the * stack and implication edges are added to the top. */ protected Vector siblings = new Vector(); /** The current node being processed. Null if no local processing. */ protected TTGNode current = null; /** Is this strategy currently processing locally? */ protected boolean isLocal = false; /** * A threshold for determining when isDone is high enough */ public int threshold = 0; public float successWeight = 0.0f; public CountTable weights = null; /** A count of how many criteria have been met for ending a turn */ protected int isDone = 0; /** Check to see if already saved weights, which should only occur once */ private boolean isSaved = false; /** create a new stingy strategy instance */ public StingyStrategy(NegotiationContext conf, Properties props) { super(conf); try { if(props.containsKey("successWeight")) { successWeight = Float.parseFloat(props.getProperty("successWeight")); } if(props.containsKey("weightFile")) { weights = new CountTable(props.getProperty("weightFile")); } else { weights = new CountTable("weights." + context.getSelf()); } if(props.containsKey("init")) { weights.INIT = Float.parseFloat(props.getProperty("init")); } if(props.containsKey("sat")) { weights.SAT = Float.parseFloat(props.getProperty("sat")); } if(props.containsKey("training")) { if(props.getProperty("training").equalsIgnoreCase("true")) { isSaved = false; } else { isSaved = true; } } } catch(Exception ex) { ex.printStackTrace(); } } /** * The stingy strategy needs to save weights when the primary trust target * is satisfied. This is method tests the predicate and saves the weight * states as a side effect. */ public int getSatisfactionState() { int state = super.getSatisfactionState(); if(state == SatisfactionState.UNKNOWN) { return state; } if(isSaved) { return state; } isSaved = true; Iterator i = context.getGraph().getNodes(); while(i.hasNext()) { TTGNode node = (TTGNode)i.next(); EntityExpression expr = getWeightKey(node.getGoal()); if(node instanceof TargetNode) { state = ((TargetNode)node).getSatisfactionValue(); } else { continue; } if(state == SatisfactionState.SATISFIED) { // increment success weights.addSatisfied(expr); } else { //if(state == SatisfactionState.FAILED) { //increment failure or unkown nodes weights.addFailed(expr); } } debug("strategy", "Saving weights for " + context.getSelf()); weights.save("weights." + context.getSelf()); return state; } /** * Notify the strategy that a new edge needs to be added to the graph. * The strategy is responsible for performing the operation on the graph, * whether the strategy chooses to defer the operation or not. */ public void scheduleOperation(Operation op) { if(!isLocal) { // process remote operations directly super.scheduleOperation(op); return; } if(op instanceof NodeOperation) { // add node op to end of vector siblings.add(op); } else if(op instanceof ImplicationEdge) { // add to front of vector //linking implication edges should be performed NOW if(op instanceof LinkingImplicationEdge) { super.scheduleOperation(op); siblings.remove(op); } else { siblings.add(0, op); } } else { // perform the operation immediately super.scheduleOperation(op); siblings.remove(op); } } /** Notify this strategy that a control child has been satisfied */ public void addSatisfiedControlChild(TTGNode node) { Goal g = (Goal)node.getGoal(); Entity v = g.getVerifier(); if(!context.getSelf().equals(v)) { //weights.addSatisfied(getWeightKey(g)); isDone++; } } /** Notify this strategy that a new node has been added to the graph */ public void addNewNode(TTGNode node) { if(!isLocal)return; ProcessingState state = node.getProcessingState(); Entity v = node.getGoal().getVerifier(); if(context.getSelf().equals(v) && state.isVerifierProcessed()) { //increment the isDone counter isDone++; } debug("strategy", "node = " + node.getGoal()); debug("strategy", "isDone = " + isDone); } /** iterate through the work list until it is empty */ public void iterate() { isDone = 0; while(true) { debug("strategy", "beginning iteratiion"); super.iterate(); if(okToEndTurn()) { debug("strategy", "ending turning now!"); return; } debug("strategy", "processing the delayed queue"); processDelayedOps(); } } /** utility function for getting the target expression out of a goal */ protected EntityExpression getWeightKey(Goal g) { EntityExpression key = null; if(g instanceof LinkingGoal) { String roleName = ((LinkingGoal)g).getTargetRoleName().toString(); key = new Role("?X", roleName); } if(g instanceof TrustTarget) { key = ((TrustTarget)g).getTargetRole(); } return key; } /** Note the beginning of a new parent node being processed */ protected void setCurrentParent(TTGNode parent) { //initialize the state variables siblings = new Vector(); current = parent; isLocal = true; //isDone = 0; } /** Process all the nodes in the delayed queue */ protected void processDelayedOps() { Iterator i = delayedOps.values().iterator(); while(i.hasNext()) { Vector s = (Vector)i.next(); while(!s.isEmpty()) { debug("strategy", "performing delayed op = " + s.get(0)); super.scheduleOperation((Operation)s.remove(0)); } i.remove(); } } /** Note the conclusion of a new parent node being processed */ protected void scheduleOperationsForNode(TTGNode parent) { Entity v = parent.getVerifier(); int doCount = 0; // if self is not parent's verifier, perform all the operations now if(!context.getSelf().equals(v)) { while(!siblings.isEmpty()) { super.scheduleOperation((Operation)siblings.remove(0)); } current = null; isLocal = false; return; } // If the verifier finds itself processing a node it has already // processed, it will not add any more operations on that node // (this node has been fully processed; therefore, the delayed // operations can be ignored.) if(delayedOps.containsKey(current.getGoal())) { debug("strategy", "Already processed node " + current.getGoal()); debug("strategy", "siblings = " + siblings); siblings = new Vector(); // potential memory leak--should be gc'ed current = null; isLocal = false; return; } //otherwise perform at least one child Iterator i = siblings.iterator(); while(i.hasNext()) { Operation op = (Operation)i.next(); if(op instanceof ImplicationEdge) { Goal g = ((EdgeOperation)op).getChild(); // embedded decision making heuristics if(weights.getWeight(getWeightKey(g)) < successWeight) { //do nothing to delay the operation //super.scheduleOperation(op); } else { super.scheduleOperation(op); i.remove(); doCount += 1; } } } // If no edges have been added, take the first implication edge (if // any) and perform it. i = siblings.iterator(); while(doCount == 0 && i.hasNext()) { // the while is redundant // node operations are processed in the next loop below Operation op = (Operation)i.next(); if(op instanceof ImplicationEdge) { super.scheduleOperation(op); i.remove(); doCount += 1; } } //if there are no remaining edge operations, then perform the //remaining node operation (to mark as processed). //check for delayed ops and determine whether it's ok to add node op if(!siblings.isEmpty()) { if(siblings.get(0) instanceof NodeOperation) { // if all edges are done NodeOperation nodeOp = (NodeOperation)siblings.remove(0); super.scheduleOperation(nodeOp); } } //put the remaining child edges in the delayed queue Goal g = current.getGoal(); if(!siblings.isEmpty()) { delayedOps.put(g, siblings); } //clean up the state variables current = null; isLocal = false; } /** criteria for determining when to end this negotiators turn */ protected boolean okToEndTurn() { // isDone = 0; // used this to check that delayedOps is really empty // if there are no more delayed op's, then end this negotiator's turn if(delayedOps.isEmpty()) { isDone++; } //if the negotiation has suceeded or failed, then return true if(getSatisfactionState() != SatisfactionState.UNKNOWN) { isDone++; } //if the threshold for end-turn criteria has been met then return true if(isDone > threshold) { return true; } // the end-turn criteria have not been met return false; } /** * convenience method for determining whether this negotiator has * a deadlock in processing the negotiation. This method can be * overridden is subsequent versions. */ protected boolean isStuck() { // if there's no history, we cannot be stuck yet if(super.isStuck()) { if(lastMessage != null) { // if both messages contain no changes, //then a deadlock has occurred return (lastMessage.getOperationsCount() == 0 ); } } return false; } }