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 | } |
---|