KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > clif > scenario > util > isac > engine > behavior > BehaviorExecutionThread


1 /*
2  * CLIF is a Load Injection Framework
3  * Copyright (C) 2004 France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * CLIF
20  *
21  * Contact: clif@objectweb.org
22  */

23 package org.objectweb.clif.scenario.util.isac.engine.behavior;
24
25 import java.util.Hashtable JavaDoc;
26 import java.util.Vector JavaDoc;
27
28 import org.objectweb.clif.datacollector.api.DataCollectorWrite;
29 import org.objectweb.clif.scenario.util.isac.engine.IsacScenarioEngine;
30 import org.objectweb.clif.scenario.util.isac.engine.behavior.node.ExecutableNode;
31 import org.objectweb.clif.scenario.util.isac.engine.behavior.node.description.ChoiceDescription;
32 import org.objectweb.clif.scenario.util.isac.engine.behavior.node.description.IfDescription;
33 import org.objectweb.clif.scenario.util.isac.engine.behavior.node.description.PreemptiveDescription;
34 import org.objectweb.clif.scenario.util.isac.engine.behavior.node.description.SampleDescription;
35 import org.objectweb.clif.scenario.util.isac.engine.behavior.node.description.TestDescription;
36 import org.objectweb.clif.scenario.util.isac.engine.behavior.node.description.TimerDescription;
37 import org.objectweb.clif.scenario.util.isac.engine.behavior.node.description.WhileDescription;
38 import org.objectweb.clif.scenario.util.isac.exception.IsacRuntimeException;
39 import org.objectweb.clif.scenario.util.isac.plugin.SampleAction;
40 import org.objectweb.clif.scenario.util.isac.plugin.TestAction;
41 import org.objectweb.clif.scenario.util.isac.plugin.TimerAction;
42 import org.objectweb.clif.scenario.util.isac.util.BooleanHolder;
43 import org.objectweb.clif.scenario.util.isac.util.SessionObjectHashtable;
44 import org.objectweb.clif.scenario.util.isac.util.IntHolder;
45 import org.objectweb.clif.scenario.util.isac.util.tree.Node;
46 import org.objectweb.clif.storage.api.ActionEvent;
47 import org.objectweb.util.monolog.api.BasicLevel;
48 import org.objectweb.util.monolog.api.Logger;
49
50 /**
51  * This class is a implementation of a behavior execution thread
52  * This thread is able to execute a behavior and send the reports to the
53  * right clif module
54  *
55  * @author JC Meillaud
56  * @author A Peyrard
57  */

58 /**
59  * @author teut
60  *
61  * TODO To change the template for this generated type comment go to Window -
62  * Preferences - Java - Code Style - Code Templates
63  */

64 public class BehaviorExecutionThread extends Thread JavaDoc {
65     // logger
66
static protected Logger log = IsacScenarioEngine.logger
67             .getLogger(BehaviorExecutionThread.class.getName());
68
69     // attributes
70
// locks...
71
private Object JavaDoc scenarioLock;
72
73     private Object JavaDoc activitiesLock;
74
75     private Object JavaDoc timerLock;
76
77     private Object JavaDoc dataControlWrite_lock;
78
79     // client interface datacontrolwrite
80
private DataCollectorWrite dataControlWrite;
81
82     // boolean running states shared with others threads and the group manager
83
private volatile BooleanHolder started;
84
85     private volatile BooleanHolder stopped;
86
87     private volatile BooleanHolder suspended;
88
89     // Vector storing all threads of the group, shared with the group manager
90
private volatile Vector JavaDoc behaviorsThreads;
91
92     // int storing number of waiting thread in the group, shared with the group
93
// manager and all group threads
94
private volatile IntHolder behaviorsThreadsWaiting;
95
96     // int storing number of waiting thread in the group, shared with the group
97
// manager and all group threads
98
private volatile IntHolder behaviorsThreadsRunningRequired;
99
100     // boolean to stop only this thread
101
private boolean localStopped;
102
103     // root tree node to be executed
104
private ExecutableNode executableNode;
105
106     // table containing all the sessions objects needed to execute this behavior
107
private SessionObjectHashtable sessionsObjectsTable;
108
109     // pile of tests
110
private Vector JavaDoc testsPile;
111
112     // id of this thread, numbre of the entry in the vector
113
private int threadId;
114
115     // id of the group, used in debug mode to know whose thread is printing msg
116
private int groupId;
117
118     private String JavaDoc bladeId;
119
120     /**
121      * Constructor, build a new behavior executable thread
122      *
123      * @param threadId
124      * The thread id of this thread
125      * @param executableNode
126      * The executable node to be executed
127      * @param sot
128      * The sessions objects table
129      * @param sl
130      * The scenarioLock used to lock the life cycle operations
131      * @param al
132      * The activities lock used to manage number of thread launched
133      * @param tl
134      * The timer lock used to execute a wait time
135      * @param dcw
136      * The data control write client interface
137      * @param dcwl
138      * The lock for this interface
139      * @param started
140      * The boolean which tell if the behavior is in started state
141      * @param stopped
142      * The boolean which tell if the behavior is in stopped state
143      * @param suspended
144      * The boolean which tell if the behavior is in suspended state
145      * @param bt
146      * The vector which store each thread of a group
147      * @param btw
148      * The reference on an integer which represents the number of
149      * waiting threads
150      * @param btrr
151      * The reference of an integer which represents the number of
152      * threads required for this group
153      */

154     public BehaviorExecutionThread(String JavaDoc bladeId, int threadId, ExecutableNode executableNode,
155             SessionObjectHashtable sot, Object JavaDoc sl, Object JavaDoc al, Object JavaDoc tl,
156             DataCollectorWrite dcw, Object JavaDoc dcwl, BooleanHolder started,
157             BooleanHolder stopped, BooleanHolder suspended, Vector JavaDoc bt,
158             IntHolder btw, IntHolder btrr) {
159         this.bladeId = bladeId;
160         this.threadId = threadId;
161         this.executableNode = executableNode;
162         this.sessionsObjectsTable = sot;
163         this.scenarioLock = sl;
164         this.activitiesLock = al;
165         this.timerLock = tl;
166         this.dataControlWrite = dcw;
167         this.dataControlWrite_lock = dcwl;
168         this.started = started;
169         this.stopped = stopped;
170         this.suspended = suspended;
171         this.behaviorsThreads = bt;
172         this.behaviorsThreadsWaiting = btw;
173         this.behaviorsThreadsRunningRequired = btrr;
174         // init the local stopped state
175
this.localStopped = false;
176         // init the test pile
177
this.testsPile = new Vector JavaDoc();
178     }
179
180     /**
181      * This method is the method which is called when we used the method start()
182      * on the thread, we will execute the executable node of the behavior tree.
183      * And remove the thread of the group manager
184      *
185      * @see java.lang.Runnable#run()
186      */

187     public void run() {
188         // execute only if we are not in stopped state
189
if (!this.localStopped && !this.stopped.getBooleanValue()) {
190             // if we are in suspended state, execute the supsend method
191
this.executeSuspendIfNeeded();
192             // launch the execution
193
this.executeNode(this.executableNode);
194         }
195         // remove the thread of the behaviors threads vector
196
// which is shared with the group manager
197
synchronized (this.activitiesLock) {
198             this.behaviorsThreads.remove(this);
199             // check if all the thread has been stopped, in this case,
200
// notify
201
// the group execution
202
if (this.stopped.getBooleanValue() || this.localStopped) {
203                 // the stop have been forced so awake the group because it's
204
// waiting
205
// for us, if we are the last thread i the group to stop
206
if (behaviorsThreads.size() == this.behaviorsThreadsRunningRequired
207                         .getIntValue()) {
208                     this.activitiesLock.notifyAll();
209                 }
210             }
211             // we naturaly finish
212
else {
213                 // do nothing
214
}
215         }
216     }
217
218     /**
219      * The method which execute a node executable
220      *
221      * @param node
222      * The node to be executed
223      */

224     private void executeNode(ExecutableNode node) {
225         log.log(BasicLevel.DEBUG, "\t\t-- BET -- executeNode");
226         // test if all the test in the pile are still right
227
for (int i = 0; i < this.testsPile.size(); i++) {
228             // if the test is not right stop the execution of this node
229
if (!this
230                     .executeTest((TestDescription) this.testsPile.elementAt(i)))
231                 return;
232         }
233         // init a boolean which store if we need to execute the children of
234
// the node
235
boolean executeChildren = false;
236         // execute the specific method for this kind of node
237
String JavaDoc type = node.getType();
238         // sample
239
if (type.equals(Node.SAMPLE)) {
240             executeChildren = executeSample(node);
241         }
242         // timer
243
else if (type.equals(Node.TIMER)) {
244             executeChildren = executeTimer(node);
245         }
246         // if
247
else if (type.equals(Node.IF)) {
248             executeChildren = executeIf(node);
249         }
250         // while
251
else if (type.equals(Node.WHILE)) {
252             executeChildren = executeWhile(node);
253         }
254         // preeptive
255
else if (type.equals(Node.PREEMPTIVE)) {
256             executeChildren = executePreemptive(node);
257         }
258         // nchoice
259
else if (type.equals(Node.NCHOICE)) {
260             executeChildren = executeNChoice(node);
261         }
262         // choice or then or else, just execute the children
263
else if (type.equals(Node.CHOICE) || type.equals(Node.THEN)
264                 || type.equals(Node.ELSE) || type.equals(Node.BEHAVIOR)) {
265             executeChildren = true;
266         }
267         // should never append
268
else {
269             throw new IsacRuntimeException(
270                     "This node type is UNKNOW, could not execute it : " + type);
271         }
272         // if we need to execute children
273
if (executeChildren) {
274             for (int i = 0; i < node.getChildren().size() && !this.localStopped
275                     && !this.stopped.getBooleanValue(); i++) {
276                 this.executeSuspendIfNeeded();
277                 this.executeNode((ExecutableNode) node.getChildren().elementAt(
278                         i));
279             }
280         }
281     }
282
283     /**
284      * Execute a sample node
285      *
286      * @param node
287      * The executable node to be executed
288      * @return false, because we don't need to execute the children
289      */

290     private boolean executeSample(ExecutableNode node) {
291         log.log(BasicLevel.DEBUG, "\t\t-- BET -- execute sample : ");
292         // get the sample description of the node
293
SampleDescription desc = (SampleDescription) node.getDescription();
294         // get the datas
295
Object JavaDoc sessionObject = this.sessionsObjectsTable.get(desc
296                 .getSessionObjectId());
297         Hashtable JavaDoc params = desc.getParams();
298         int nb = desc.getMethodNumber();
299         // execute the doSample method on the session object
300
ActionEvent report = ((SampleAction) sessionObject).doSample(nb,
301                 params, new ActionEvent(System.currentTimeMillis(), bladeId, null, 0,
302                         threadId, true, 0, null, ""));
303         // send the result to the clif component if not null
304
if (report != null)
305         {
306             synchronized (this.dataControlWrite_lock) {
307                 if (this.dataControlWrite != null)
308                     this.dataControlWrite.add(report);
309             }
310         }
311         // we don't need to execute the children,
312
// because this kind of node could not has children
313
return false;
314     }
315
316     /**
317      * Execute a timer node
318      *
319      * @param node
320      * The executable node to be executed
321      * @return false, because we don't need to execute the children
322      */

323     private boolean executeTimer(ExecutableNode node) {
324         log.log(BasicLevel.DEBUG, "\t\t-- BET -- execute timer : ");
325         // get the timer description of the node
326
TimerDescription desc = (TimerDescription) node.getDescription();
327         // get the datas
328
Object JavaDoc sessionObject = this.sessionsObjectsTable.get(desc
329                 .getSessionObjectId());
330         Hashtable JavaDoc params = desc.getParams();
331         int nb = desc.getMethodNumber();
332         // execute the doTimer method on the session object
333
long waitingTime = ((TimerAction) sessionObject).doTimer(nb, params);
334         // execute a waiting method during the time of the stop
335
this.executeWaitTime(waitingTime);
336         // we don't need to execute the children,
337
// because this kind of node could not has children
338
return false;
339     }
340
341     /**
342      * Method which executes an if executable node
343      *
344      * @param node
345      * The executable node to be executed
346      * @return false, because, we organize the execution of the children in this
347      * method
348      */

349     private boolean executeIf(ExecutableNode node) {
350         log.log(BasicLevel.DEBUG, "\t\t-- BET -- execute if : ");
351         // get the value of the condition
352
boolean condition = executeTest(((IfDescription) node.getDescription())
353                 .getCondition());
354         // get the then child and the else child if it exists
355
ExecutableNode thenNode = null;
356         ExecutableNode elseNode = null;
357         // the size should be 1 or 2
358
for (int i = 0; i < node.getChildren().size() && !this.localStopped
359                 && !this.stopped.getBooleanValue(); i++) {
360             this.executeSuspendIfNeeded();
361             // get a child
362
ExecutableNode child = (ExecutableNode) node.getChildren()
363                     .elementAt(i);
364             if (child.getType().equals(Node.THEN))
365                 thenNode = child;
366             else if (child.getType().equals(Node.ELSE))
367                 elseNode = child;
368             else
369                 throw new IsacRuntimeException("Unexpected node type : "
370                         + child.getType());
371         }
372         // if we have been stopped don't execute the children
373
if (this.localStopped || this.stopped.getBooleanValue()) {
374             return false;
375         }
376         // execute the right child depending on the condition
377
if (condition)
378             this.executeNode(thenNode);
379         else if (elseNode != null)
380             this.executeNode(elseNode);
381         // don't launch the children, because it's already done
382
return false;
383     }
384
385     /**
386      * Method which executes a while executable node
387      *
388      * @param node
389      * The executable node to be executed
390      * @return false, because, we organize the execution of the children in this
391      * method
392      */

393     private boolean executeWhile(ExecutableNode node) {
394         log.log(BasicLevel.DEBUG, "\t\t-- BET -- execute while : ");
395         // get the value of the condition
396
boolean condition = executeTest(((WhileDescription) node
397                 .getDescription()).getCondition());
398         // while the condition is right do it
399
while (condition && !stopped.getBooleanValue() && !localStopped) {
400             // execute all child
401
for (int i = 0; i < node.getChildren().size() && !this.localStopped
402                     && !this.stopped.getBooleanValue(); i++) {
403                 this.executeSuspendIfNeeded();
404                 this.executeNode((ExecutableNode) node.getChildren().elementAt(
405                         i));
406             }
407             // revaluate the condition
408
condition = executeTest(((WhileDescription) node.getDescription())
409                     .getCondition());
410         }
411         // don't launch the children, because it's already done
412
return false;
413     }
414
415     /**
416      * This method execute a preemptive node
417      *
418      * @param node
419      * The excutable node to execute
420      * @return false, because, we organize the execution of the children in this
421      * method
422      */

423     private boolean executePreemptive(ExecutableNode node) {
424         log.log(BasicLevel.DEBUG, "\t\t-- BET -- execute preemptive : ");
425         // put the test of this node in the tests pile
426
this.testsPile.add(((PreemptiveDescription) node.getDescription())
427                 .getCondition());
428         // execute the child all this child will evaluate the condition
429
// putted in the pile
430
for (int i = 0; i < node.getChildren().size() && !this.localStopped
431                 && !this.stopped.getBooleanValue(); i++) {
432             this.executeSuspendIfNeeded();
433             this.executeNode((ExecutableNode) node.getChildren().elementAt(i));
434         }
435         // remove the test from the pile
436
this.testsPile.remove(node.getDescription());
437         // don't launch the children, because it's already done
438
return false;
439     }
440
441     /**
442      * This method execute a nchoice node
443      *
444      * @param node
445      * The excutable node to execute
446      * @return false, because, we organize the execution of the children in this
447      * method
448      */

449     private boolean executeNChoice(ExecutableNode node) {
450         log.log(BasicLevel.DEBUG, "\t\t-- BET -- execute nchoice : ");
451         // create a table to store all the probabilities, one for each child
452
int[] probabilityRange = new int[node.getChildren().size()];
453         // init a counter to adds the propabilities
454
int totalPorbablities = 0;
455         // init this vector
456
for (int i = 0; i < node.getChildren().size(); i++) {
457             int proba = ((ChoiceDescription) ((ExecutableNode) node
458                     .getChildren().elementAt(i)).getDescription())
459                     .getProbability();
460             totalPorbablities += proba;
461             probabilityRange[i] = totalPorbablities;
462         }
463         // get a random value between 0 and totalProbabilities
464
int random = (int) (Math.random() * totalPorbablities);
465         // get the right choice
466
for (int i = 0; i < probabilityRange.length; i++) {
467             // must be true only one time...
468
if (random < probabilityRange[i]) {
469                 if (!this.localStopped && !this.stopped.getBooleanValue()) {
470                     this.executeSuspendIfNeeded();
471                     // execute this branch : i
472
this.executeNode((ExecutableNode) node.getChildren()
473                             .elementAt(i));
474                 }
475                 // don't launch the children, because it's already done
476
return false;
477             }
478         }
479         // should never append
480
throw new IsacRuntimeException(
481                 "Unable to make a choice, no branch was selected");
482     }
483
484     /**
485      * This method execute a test
486      *
487      * @param td
488      * The test description which will be executed
489      * @return The result of the test
490      */

491     private boolean executeTest(TestDescription td) {
492         log.log(BasicLevel.DEBUG, "\t\t-- BET -- execute test");
493         // get the datas
494
Object JavaDoc sessionObject = this.sessionsObjectsTable.get(td
495                 .getSessionObjectId());
496         Hashtable JavaDoc params = td.getParams();
497         int nb = td.getMethodNumber();
498         // execute the doTimer method on the session object
499
return ((TestAction) sessionObject).doTest(nb, params);
500     }
501
502     /**
503      * Method which execute a timer, if the thread switch to suspend mode,
504      * execute the suspend but redo the timer in the same state than before the
505      * suspend
506      *
507      * @param duration
508      * The duration of the timer
509      */

510     private void executeWaitTime(long duration) {
511         if (IsacScenarioEngine.DEBUG_ON && log.isLoggable(BasicLevel.DEBUG)) {
512             log.log(BasicLevel.DEBUG, "\t\t-- BET -- execute wait : "
513                     + duration);
514         }
515         // define a variable to store the elapsed_time if a suspend append
516
long ellapsedTime = 0;
517         // do this since the duration time has not been wait, and
518
// since the stop state don't append
519
while (ellapsedTime < duration && !stopped.getBooleanValue()
520                 && !localStopped) {
521             // try to do suspend
522
this.executeSuspendIfNeeded();
523             // store the starting time
524
long startTimerTime = System.currentTimeMillis();
525             // synchronize on the timer object
526
synchronized (this.timerLock) {
527                 try {
528                     this.timerLock.wait(duration - ellapsedTime);
529                 } catch (InterruptedException JavaDoc ex) {
530                     throw new IsacRuntimeException("-- BET" + threadId + ":"
531                             + groupId + " Unable to execute timer",ex);
532                 }
533             }
534             // if we reach this line, either we sleep all the duration time
535
// or the group execution stop us in order to do a stop or
536
// suspend mode
537
// calcul the time we manage to wait
538
ellapsedTime += System.currentTimeMillis() - startTimerTime;
539         }
540     }
541
542     /**
543      * This method analyse if we are in suspended state and wait during the
544      * suspended state if we are
545      */

546     private void executeSuspendIfNeeded() {
547         // synchronized (this.scenarioLock) {
548
if (this.suspended.getBooleanValue()) {
549             log
550                     .log(BasicLevel.WARN,
551                             "\t\t-- BET -- WE MANAGE TO ENTER SUSPEND");
552             synchronized (this.scenarioLock) {
553                 synchronized (this.activitiesLock) {
554                     // increments the number of waiting threads
555
this.behaviorsThreadsWaiting
556                             .setIntValue(this.behaviorsThreadsWaiting
557                                     .getIntValue() + 1);
558                     log.log(BasicLevel.WARN, "\t\t-- BET -- threads running="
559                             + this.behaviorsThreads.size() + " waiting="
560                             + this.behaviorsThreadsWaiting.getIntValue());
561                     if (this.behaviorsThreadsWaiting.getIntValue() == this.behaviorsThreads
562                             .size()) {
563                         // notify the group execution thread because we are the
564
// last thread entering waiting mode
565
// of this group
566
log.log(BasicLevel.WARN,
567                                 "\t\t-- BET -- awake GROUPPPPPPPPP");
568                         this.activitiesLock.notifyAll();
569                     }
570                 }
571                 log.log(BasicLevel.WARN, "\t\t-- BET -- do SUSPEND");
572                 try {
573                     this.scenarioLock.wait();
574                 } catch (InterruptedException JavaDoc ex) {
575                     throw new IsacRuntimeException(
576                             "Unable to wait during the suspended state",ex);
577                 }
578                 synchronized (this.activitiesLock) {
579                     // now decrease the number of thread suspended
580
this.behaviorsThreadsWaiting
581                             .setIntValue(this.behaviorsThreadsWaiting
582                                     .getIntValue() - 1);
583                     if (this.behaviorsThreadsWaiting.getIntValue() == 0) {
584                         // notify the group execution thread because we are the
585
// last thread entering resume mode
586
// of this group
587
this.activitiesLock.notifyAll();
588                     }
589                 }
590             }
591         }
592     }
593
594     /**
595      * @param localStopped
596      * The localStopped to set.
597      */

598     public void setLocalStopped(boolean localStopped) {
599         this.localStopped = localStopped;
600     }
601 }
Popular Tags