[8780cbec] | 1 | package com.nailabs.abac.process; |
---|
| 2 | |
---|
| 3 | import edu.stanford.peer.rbtm.credential.*; |
---|
| 4 | import com.nailabs.abac.trust.*; |
---|
| 5 | import com.nailabs.abac.test.*; |
---|
| 6 | import java.util.*; |
---|
| 7 | /** |
---|
| 8 | * The strategy handles processing a working list of nodes in the trust target |
---|
| 9 | * graph to be processed. This version uses a combination of heuristics with |
---|
| 10 | * a depth first search method. |
---|
| 11 | */ |
---|
| 12 | public class StingyStrategy extends Strategy { |
---|
| 13 | /** A queue for operations which need to delay */ |
---|
| 14 | protected Hashtable delayedOps = new Hashtable(); |
---|
| 15 | |
---|
| 16 | /** |
---|
| 17 | * A list of sibling children of the current node being processed. Note, |
---|
| 18 | * this is an ordered stack. Node operations are added the bottom of the |
---|
| 19 | * stack and implication edges are added to the top. |
---|
| 20 | */ |
---|
| 21 | protected Vector siblings = new Vector(); |
---|
| 22 | |
---|
| 23 | /** The current node being processed. Null if no local processing. */ |
---|
| 24 | protected TTGNode current = null; |
---|
| 25 | |
---|
| 26 | /** Is this strategy currently processing locally? */ |
---|
| 27 | protected boolean isLocal = false; |
---|
| 28 | |
---|
| 29 | /** |
---|
| 30 | * A threshold for determining when isDone is high enough |
---|
| 31 | */ |
---|
| 32 | public int threshold = 0; |
---|
| 33 | |
---|
| 34 | public float successWeight = 0.0f; |
---|
| 35 | |
---|
| 36 | public CountTable weights = null; |
---|
| 37 | |
---|
| 38 | /** A count of how many criteria have been met for ending a turn */ |
---|
| 39 | protected int isDone = 0; |
---|
| 40 | |
---|
| 41 | /** Check to see if already saved weights, which should only occur once */ |
---|
| 42 | private boolean isSaved = false; |
---|
| 43 | |
---|
| 44 | /** create a new stingy strategy instance */ |
---|
| 45 | public StingyStrategy(NegotiationContext conf, Properties props) { |
---|
| 46 | super(conf); |
---|
| 47 | try { |
---|
| 48 | if(props.containsKey("successWeight")) { |
---|
| 49 | successWeight = |
---|
| 50 | Float.parseFloat(props.getProperty("successWeight")); |
---|
| 51 | } |
---|
| 52 | if(props.containsKey("weightFile")) { |
---|
| 53 | weights = new CountTable(props.getProperty("weightFile")); |
---|
| 54 | } else { |
---|
| 55 | weights = new CountTable("weights." + context.getSelf()); |
---|
| 56 | } |
---|
| 57 | if(props.containsKey("init")) { |
---|
| 58 | weights.INIT = |
---|
| 59 | Float.parseFloat(props.getProperty("init")); |
---|
| 60 | } |
---|
| 61 | if(props.containsKey("sat")) { |
---|
| 62 | weights.SAT = |
---|
| 63 | Float.parseFloat(props.getProperty("sat")); |
---|
| 64 | } |
---|
| 65 | if(props.containsKey("training")) { |
---|
| 66 | if(props.getProperty("training").equalsIgnoreCase("true")) { |
---|
| 67 | isSaved = false; |
---|
| 68 | } else { |
---|
| 69 | isSaved = true; |
---|
| 70 | } |
---|
| 71 | } |
---|
| 72 | } catch(Exception ex) { |
---|
| 73 | ex.printStackTrace(); |
---|
| 74 | } |
---|
| 75 | } |
---|
| 76 | |
---|
| 77 | /** |
---|
| 78 | * The stingy strategy needs to save weights when the primary trust target |
---|
| 79 | * is satisfied. This is method tests the predicate and saves the weight |
---|
| 80 | * states as a side effect. |
---|
| 81 | */ |
---|
| 82 | public int getSatisfactionState() { |
---|
| 83 | int state = super.getSatisfactionState(); |
---|
| 84 | if(state == SatisfactionState.UNKNOWN) { |
---|
| 85 | return state; |
---|
| 86 | } |
---|
| 87 | if(isSaved) { |
---|
| 88 | return state; |
---|
| 89 | } |
---|
| 90 | isSaved = true; |
---|
| 91 | Iterator i = context.getGraph().getNodes(); |
---|
| 92 | while(i.hasNext()) { |
---|
| 93 | TTGNode node = (TTGNode)i.next(); |
---|
| 94 | EntityExpression expr = getWeightKey(node.getGoal()); |
---|
| 95 | if(node instanceof TargetNode) { |
---|
| 96 | state = ((TargetNode)node).getSatisfactionValue(); |
---|
| 97 | } else { |
---|
| 98 | continue; |
---|
| 99 | } |
---|
| 100 | if(state == SatisfactionState.SATISFIED) { // increment success |
---|
| 101 | weights.addSatisfied(expr); |
---|
| 102 | } else { |
---|
| 103 | //if(state == SatisfactionState.FAILED) { |
---|
| 104 | //increment failure or unkown nodes |
---|
| 105 | weights.addFailed(expr); |
---|
| 106 | } |
---|
| 107 | } |
---|
| 108 | debug("strategy", "Saving weights for " + context.getSelf()); |
---|
| 109 | weights.save("weights." + context.getSelf()); |
---|
| 110 | return state; |
---|
| 111 | } |
---|
| 112 | |
---|
| 113 | /** |
---|
| 114 | * Notify the strategy that a new edge needs to be added to the graph. |
---|
| 115 | * The strategy is responsible for performing the operation on the graph, |
---|
| 116 | * whether the strategy chooses to defer the operation or not. |
---|
| 117 | */ |
---|
| 118 | public void scheduleOperation(Operation op) { |
---|
| 119 | if(!isLocal) { // process remote operations directly |
---|
| 120 | super.scheduleOperation(op); |
---|
| 121 | return; |
---|
| 122 | } |
---|
| 123 | if(op instanceof NodeOperation) { // add node op to end of vector |
---|
| 124 | siblings.add(op); |
---|
| 125 | } else if(op instanceof ImplicationEdge) { // add to front of vector |
---|
| 126 | //linking implication edges should be performed NOW |
---|
| 127 | if(op instanceof LinkingImplicationEdge) { |
---|
| 128 | super.scheduleOperation(op); |
---|
| 129 | siblings.remove(op); |
---|
| 130 | } else { |
---|
| 131 | siblings.add(0, op); |
---|
| 132 | } |
---|
| 133 | } else { // perform the operation immediately |
---|
| 134 | super.scheduleOperation(op); |
---|
| 135 | siblings.remove(op); |
---|
| 136 | } |
---|
| 137 | } |
---|
| 138 | |
---|
| 139 | /** Notify this strategy that a control child has been satisfied */ |
---|
| 140 | public void addSatisfiedControlChild(TTGNode node) { |
---|
| 141 | Goal g = (Goal)node.getGoal(); |
---|
| 142 | Entity v = g.getVerifier(); |
---|
| 143 | if(!context.getSelf().equals(v)) { |
---|
| 144 | //weights.addSatisfied(getWeightKey(g)); |
---|
| 145 | isDone++; |
---|
| 146 | } |
---|
| 147 | } |
---|
| 148 | |
---|
| 149 | /** Notify this strategy that a new node has been added to the graph */ |
---|
| 150 | public void addNewNode(TTGNode node) { |
---|
| 151 | if(!isLocal)return; |
---|
| 152 | ProcessingState state = node.getProcessingState(); |
---|
| 153 | Entity v = node.getGoal().getVerifier(); |
---|
| 154 | if(context.getSelf().equals(v) && state.isVerifierProcessed()) { |
---|
| 155 | //increment the isDone counter |
---|
| 156 | isDone++; |
---|
| 157 | } |
---|
| 158 | debug("strategy", "node = " + node.getGoal()); |
---|
| 159 | debug("strategy", "isDone = " + isDone); |
---|
| 160 | } |
---|
| 161 | |
---|
| 162 | /** iterate through the work list until it is empty */ |
---|
| 163 | public void iterate() { |
---|
| 164 | isDone = 0; |
---|
| 165 | while(true) { |
---|
| 166 | debug("strategy", "beginning iteratiion"); |
---|
| 167 | super.iterate(); |
---|
| 168 | if(okToEndTurn()) { |
---|
| 169 | debug("strategy", "ending turning now!"); |
---|
| 170 | return; |
---|
| 171 | } |
---|
| 172 | debug("strategy", "processing the delayed queue"); |
---|
| 173 | processDelayedOps(); |
---|
| 174 | } |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | /** utility function for getting the target expression out of a goal */ |
---|
| 178 | protected EntityExpression getWeightKey(Goal g) { |
---|
| 179 | EntityExpression key = null; |
---|
| 180 | if(g instanceof LinkingGoal) { |
---|
| 181 | String roleName = |
---|
| 182 | ((LinkingGoal)g).getTargetRoleName().toString(); |
---|
| 183 | key = new Role("?X", roleName); |
---|
| 184 | } |
---|
| 185 | if(g instanceof TrustTarget) { |
---|
| 186 | key = ((TrustTarget)g).getTargetRole(); |
---|
| 187 | } |
---|
| 188 | return key; |
---|
| 189 | } |
---|
| 190 | |
---|
| 191 | /** Note the beginning of a new parent node being processed */ |
---|
| 192 | protected void setCurrentParent(TTGNode parent) { |
---|
| 193 | //initialize the state variables |
---|
| 194 | siblings = new Vector(); |
---|
| 195 | current = parent; |
---|
| 196 | isLocal = true; |
---|
| 197 | //isDone = 0; |
---|
| 198 | } |
---|
| 199 | |
---|
| 200 | /** Process all the nodes in the delayed queue */ |
---|
| 201 | protected void processDelayedOps() { |
---|
| 202 | Iterator i = delayedOps.values().iterator(); |
---|
| 203 | while(i.hasNext()) { |
---|
| 204 | Vector s = (Vector)i.next(); |
---|
| 205 | while(!s.isEmpty()) { |
---|
| 206 | debug("strategy", "performing delayed op = " + s.get(0)); |
---|
| 207 | super.scheduleOperation((Operation)s.remove(0)); |
---|
| 208 | } |
---|
| 209 | i.remove(); |
---|
| 210 | } |
---|
| 211 | } |
---|
| 212 | |
---|
| 213 | /** Note the conclusion of a new parent node being processed */ |
---|
| 214 | protected void scheduleOperationsForNode(TTGNode parent) { |
---|
| 215 | Entity v = parent.getVerifier(); |
---|
| 216 | int doCount = 0; |
---|
| 217 | |
---|
| 218 | // if self is not parent's verifier, perform all the operations now |
---|
| 219 | if(!context.getSelf().equals(v)) { |
---|
| 220 | while(!siblings.isEmpty()) { |
---|
| 221 | super.scheduleOperation((Operation)siblings.remove(0)); |
---|
| 222 | } |
---|
| 223 | current = null; |
---|
| 224 | isLocal = false; |
---|
| 225 | return; |
---|
| 226 | } |
---|
| 227 | // If the verifier finds itself processing a node it has already |
---|
| 228 | // processed, it will not add any more operations on that node |
---|
| 229 | // (this node has been fully processed; therefore, the delayed |
---|
| 230 | // operations can be ignored.) |
---|
| 231 | if(delayedOps.containsKey(current.getGoal())) { |
---|
| 232 | debug("strategy", "Already processed node " + current.getGoal()); |
---|
| 233 | debug("strategy", "siblings = " + siblings); |
---|
| 234 | siblings = new Vector(); // potential memory leak--should be gc'ed |
---|
| 235 | current = null; |
---|
| 236 | isLocal = false; |
---|
| 237 | return; |
---|
| 238 | } |
---|
| 239 | //otherwise perform at least one child |
---|
| 240 | Iterator i = siblings.iterator(); |
---|
| 241 | while(i.hasNext()) { |
---|
| 242 | Operation op = (Operation)i.next(); |
---|
| 243 | |
---|
| 244 | if(op instanceof ImplicationEdge) { |
---|
| 245 | Goal g = ((EdgeOperation)op).getChild(); |
---|
| 246 | // embedded decision making heuristics |
---|
| 247 | if(weights.getWeight(getWeightKey(g)) < successWeight) { |
---|
| 248 | //do nothing to delay the operation |
---|
| 249 | //super.scheduleOperation(op); |
---|
| 250 | } else { |
---|
| 251 | super.scheduleOperation(op); |
---|
| 252 | i.remove(); |
---|
| 253 | doCount += 1; |
---|
| 254 | } |
---|
| 255 | } |
---|
| 256 | } |
---|
| 257 | // If no edges have been added, take the first implication edge (if |
---|
| 258 | // any) and perform it. |
---|
| 259 | i = siblings.iterator(); |
---|
| 260 | while(doCount == 0 && i.hasNext()) { // the while is redundant |
---|
| 261 | // node operations are processed in the next loop below |
---|
| 262 | Operation op = (Operation)i.next(); |
---|
| 263 | if(op instanceof ImplicationEdge) { |
---|
| 264 | super.scheduleOperation(op); |
---|
| 265 | i.remove(); |
---|
| 266 | doCount += 1; |
---|
| 267 | } |
---|
| 268 | } |
---|
| 269 | //if there are no remaining edge operations, then perform the |
---|
| 270 | //remaining node operation (to mark as processed). |
---|
| 271 | //check for delayed ops and determine whether it's ok to add node op |
---|
| 272 | if(!siblings.isEmpty()) { |
---|
| 273 | if(siblings.get(0) instanceof NodeOperation) { |
---|
| 274 | // if all edges are done |
---|
| 275 | NodeOperation nodeOp = (NodeOperation)siblings.remove(0); |
---|
| 276 | super.scheduleOperation(nodeOp); |
---|
| 277 | } |
---|
| 278 | } |
---|
| 279 | //put the remaining child edges in the delayed queue |
---|
| 280 | Goal g = current.getGoal(); |
---|
| 281 | if(!siblings.isEmpty()) { |
---|
| 282 | delayedOps.put(g, siblings); |
---|
| 283 | } |
---|
| 284 | //clean up the state variables |
---|
| 285 | current = null; |
---|
| 286 | isLocal = false; |
---|
| 287 | } |
---|
| 288 | |
---|
| 289 | /** criteria for determining when to end this negotiators turn */ |
---|
| 290 | protected boolean okToEndTurn() { |
---|
| 291 | // isDone = 0; // used this to check that delayedOps is really empty |
---|
| 292 | // if there are no more delayed op's, then end this negotiator's turn |
---|
| 293 | if(delayedOps.isEmpty()) { |
---|
| 294 | isDone++; |
---|
| 295 | } |
---|
| 296 | //if the negotiation has suceeded or failed, then return true |
---|
| 297 | if(getSatisfactionState() != SatisfactionState.UNKNOWN) { |
---|
| 298 | isDone++; |
---|
| 299 | } |
---|
| 300 | //if the threshold for end-turn criteria has been met then return true |
---|
| 301 | if(isDone > threshold) { |
---|
| 302 | return true; |
---|
| 303 | } |
---|
| 304 | // the end-turn criteria have not been met |
---|
| 305 | return false; |
---|
| 306 | } |
---|
| 307 | |
---|
| 308 | /** |
---|
| 309 | * convenience method for determining whether this negotiator has |
---|
| 310 | * a deadlock in processing the negotiation. This method can be |
---|
| 311 | * overridden is subsequent versions. |
---|
| 312 | */ |
---|
| 313 | protected boolean isStuck() { |
---|
| 314 | // if there's no history, we cannot be stuck yet |
---|
| 315 | if(super.isStuck()) { |
---|
| 316 | if(lastMessage != null) { |
---|
| 317 | // if both messages contain no changes, |
---|
| 318 | //then a deadlock has occurred |
---|
| 319 | return (lastMessage.getOperationsCount() == 0 ); |
---|
| 320 | } |
---|
| 321 | } |
---|
| 322 | return false; |
---|
| 323 | } |
---|
| 324 | |
---|
| 325 | |
---|
| 326 | |
---|
| 327 | } |
---|