KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > clif > scenario > util > transitions > TransitionTable


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

27
28 package org.objectweb.clif.scenario.util.transitions;
29
30 import org.objectweb.clif.util.ClifClassLoader;
31
32 import java.io.BufferedReader JavaDoc;
33 import java.io.FileNotFoundException JavaDoc;
34 import java.io.FileReader JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.io.InputStreamReader JavaDoc;
37 import java.util.NoSuchElementException JavaDoc;
38 import java.util.Properties JavaDoc;
39 import java.util.Random JavaDoc;
40 import java.util.Stack JavaDoc;
41 import java.util.StringTokenizer JavaDoc;
42
43 /**
44  * This class provides utilities to design a scenario, which deals with these
45  * aspects: <br>- Probability for the virtual user to reach a given link. <br>-
46  * Probability for the virtual user to click on the back button. <br>-
47  * Probability for the virtual user to end the session. <br>- Think time
48  * between each virtual user action. <br>
49  * <br>
50  * The structure is a matrix that represents the probability for a virtual user
51  * to navigate from a specific page to another one. <br>
52  * <br>
53  * This class need an external text file which has the following structure: <br>
54  * <br>- Each value at ligne x and column y represents the probality for the
55  * virtual user, to go from the "page y" to the "page x". <br>
56  * It must be a value between 0 and 1.<br>
57  *
58  */

59 public class TransitionTable implements Cloneable JavaDoc {
60
61     private int nbColumns;
62
63     private int nbRows;
64
65     // The matrix which contains transitions probabilities
66
private float transitions[][];
67
68     // The table that contains the transitions think time
69
private int transitionsTime[];
70
71     private int beforeStep;
72
73     private Random JavaDoc rand = new Random JavaDoc();
74
75     // The stack of the previous states, useful when the user click on back
76
// button
77
private Stack JavaDoc previousStates = new Stack JavaDoc();
78
79     // The current state is the initial state (first column of the matrix)
80
private int currentState = 0;
81
82     // Use the think time specified in the matrix
83
private boolean useMatrixThinkTime;
84
85     private boolean identifyByOrigin;
86
87     // The table that contains all the names of the pages
88
private String JavaDoc[] stateNames;
89
90     // The table which makes the association between the state and the action
91
private String JavaDoc[] action;
92
93     private String JavaDoc[][] actionByOrigin;
94
95     private boolean isBackClicked;
96
97     private Properties JavaDoc prop = new Properties JavaDoc();
98
99     private Transition trans = new Transition();
100
101     private boolean DEBUG = false;
102
103     /**
104      * Create a transition table with specifics files and give information about
105      * how to handle think time. <br>
106      * In all cases, the scenario can handle its own think time in addition to
107      * one describe above.
108      *
109      * @param filename
110      * The transition file to load data from.
111      * @param actions_file
112      * The file containing the actions.
113      * @param useMatrixThinkTime
114      * true means that think time in the matrix are used.
115      * @param identifyByOrigin
116      * true means that the actions depends on the previous state.
117      */

118     public TransitionTable(String JavaDoc filename, String JavaDoc actions_file,
119             boolean useMatrixThinkTime, boolean identifyByOrigin) {
120
121         this.useMatrixThinkTime = useMatrixThinkTime;
122         this.identifyByOrigin = identifyByOrigin;
123         readMatrixTextFile(filename);
124         readActionsTextFile(actions_file);
125         trans.setProperties(prop);
126     }
127
128     /**
129      * Empty constructor, build a new empty transition table object used in
130      * createnewtransitiontable method
131      */

132     private TransitionTable() {
133     }
134
135     /**
136      * Create a new transition table, which have the same table than it table
137      *
138      * @return the new transition table
139      */

140     public TransitionTable createNewTransitionTable() {
141         // create an empty object
142
TransitionTable copy = new TransitionTable();
143         // clone all values of this transition table to the clone
144
copy.nbColumns = this.nbColumns;
145         copy.nbRows = this.nbRows;
146         copy.transitions = new float[this.transitions.length][transitions[0].length];
147         for (int i = 0; i < this.transitions.length; i++) {
148             for (int j = 0; j < this.transitions[i].length; j++) {
149                 copy.transitions[i][j] = this.transitions[i][j];
150             }
151         }
152         copy.transitionsTime = new int[this.transitionsTime.length];
153         for (int i = 0; i < this.transitionsTime.length; i++) {
154             copy.transitionsTime[i] = this.transitionsTime[i];
155         }
156         copy.beforeStep = this.beforeStep;
157         copy.rand = new Random JavaDoc();
158         // copy the stack
159
copy.previousStates = new Stack JavaDoc();
160         copy.useMatrixThinkTime = this.useMatrixThinkTime;
161         copy.identifyByOrigin = this.identifyByOrigin;
162         copy.stateNames = new String JavaDoc[this.stateNames.length];
163         for (int i = 0; i < this.stateNames.length; i++) {
164             copy.stateNames[i] = new String JavaDoc(this.stateNames[i]);
165         }
166         copy.action = new String JavaDoc[this.action.length];
167         for (int i = 0; i < this.action.length; i++) {
168             copy.action[i] = new String JavaDoc(this.action[i]);
169         }
170         if (this.actionByOrigin != null) {
171             copy.actionByOrigin = new String JavaDoc[this.actionByOrigin.length][this.actionByOrigin[0].length];
172             for (int i = 0; i < this.actionByOrigin.length; i++) {
173                 if (this.actionByOrigin[i] != null) {
174                     for (int j = 0; j < this.actionByOrigin[i].length; j++) {
175                         copy.actionByOrigin[i][j] = this.actionByOrigin[i][j];
176                     }
177                 }
178             }
179         }
180         copy.isBackClicked = this.isBackClicked;
181         copy.prop = new Properties JavaDoc(this.prop);
182         copy.trans = new Transition();
183         return copy;
184     }
185
186     /**
187      * This method is used to reset all the previous states
188      */

189     public void resetPreviousState() {
190         this.currentState = 0;
191         this.previousStates.clear();
192     }
193
194     /**
195      * Fill all the structures reading the file.
196      *
197      * @param filename
198      * The file to load data from.
199      * @return true if the loading is successful.
200      */

201     private boolean readMatrixTextFile(String JavaDoc filename) {
202         BufferedReader JavaDoc reader;
203         Float JavaDoc f;
204         Integer JavaDoc t;
205
206         // Try to open the file
207
try {
208             reader = new BufferedReader JavaDoc(new FileReader JavaDoc(filename));
209         } catch (FileNotFoundException JavaDoc fnf) {
210             try {
211                 reader = new BufferedReader JavaDoc(
212                     new InputStreamReader JavaDoc(
213                         ClifClassLoader.getClassLoader().getResourceAsStream(filename)));
214             } catch (Exception JavaDoc e) {
215                 System.err.println("File " + filename + " not found. " + e);
216                 return false;
217             }
218         }
219
220         // Now read the file using tab (\t) as field delimiter
221
try {
222
223             while (!reader.readLine().startsWith("#")) {
224             }
225
226             reader.readLine(); // From >>>
227

228             // Column headers
229
StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(reader.readLine(), "\t");
230
231             // Each state + Wait time + 1st column
232
nbColumns = st.countTokens();
233
234             // Each state + Back + End Session
235
nbRows = nbColumns;
236
237             stateNames = new String JavaDoc[nbRows];
238             transitions = new float[nbRows][nbColumns - 2];
239             transitionsTime = new int[nbRows];
240
241             // Read the matrix
242
for (int i = 0; i < nbRows; i++) {
243                 st = new StringTokenizer JavaDoc(reader.readLine(), "\t");
244                 // The first column is the name of the state.
245
stateNames[i] = st.nextToken();
246
247                 // For all the columns except the last one
248
for (int j = 0; j < nbColumns - 2; j++) {
249                     // We get the value
250
f = new Float JavaDoc(st.nextToken());
251                     // And add the value to the matrix
252
transitions[i][j] = f.floatValue();
253                 }
254
255                 // Last column is transition_waiting_time
256
t = new Integer JavaDoc(st.nextToken());
257                 transitionsTime[i] = t.intValue();
258             }
259
260             reader.close();
261
262         } catch (IOException JavaDoc ioe) {
263             System.err.println("An error occured while reading " + filename
264                     + ". (" + ioe.getMessage() + ")");
265             return false;
266         } catch (NoSuchElementException JavaDoc nsu) {
267             System.err.println("File format error in file " + filename
268                     + " Reason: " + nsu.getMessage());
269             return false;
270         } catch (NumberFormatException JavaDoc ne) {
271             System.err.println("Number format error in file " + filename
272                     + "Reason: " + ne.getMessage());
273             return false;
274         }
275
276         return true;
277     }
278
279     /**
280      * Read the file containing the actions.
281      *
282      * @param filename
283      * @return
284      */

285     private boolean readActionsTextFile(String JavaDoc filename) {
286         BufferedReader JavaDoc reader;
287         StringTokenizer JavaDoc st;
288         String JavaDoc line;
289         int j;
290
291         // Try to open the file
292
try {
293             reader = new BufferedReader JavaDoc(new FileReader JavaDoc(filename));
294         } catch (FileNotFoundException JavaDoc fnf) {
295             try {
296                 reader = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(this
297                         .getClass().getClassLoader().getResourceAsStream(
298                                 filename)));
299             } catch (Exception JavaDoc e) {
300                 System.err.println("File " + filename + " not found. " + e);
301                 return false;
302             }
303         }
304
305         try {
306
307             while (!(line = reader.readLine()).startsWith("#")) {
308             }
309
310             // If the current line is the transition separator
311
// We reach the next separator
312
if (line.indexOf("Transition") != -1) {
313                 while (!(line = reader.readLine()).startsWith("#")) {
314                 }
315             }
316             // If the current line is the variables separator
317
// We load properties until another separator is reached
318
if (line.indexOf("Variable") != -1) {
319                 while (!(line = reader.readLine()).startsWith("#"))
320                     loadProperty(line);
321             }
322
323             if (line.indexOf("Action") != -1) {
324                 // Read the action matrix
325

326                 // This structure contains the association between the name of
327
// the page
328
// and its action.
329
if (identifyByOrigin)
330                     actionByOrigin = new String JavaDoc[nbColumns - 2][nbColumns - 2];
331                 else
332                     action = new String JavaDoc[nbColumns - 2];
333
334                 if (identifyByOrigin) {
335
336                     for (int i = 0; i < nbColumns - 2; i++) {
337                         st = new StringTokenizer JavaDoc(reader.readLine(), "\t");
338                         st.nextToken(); // State name
339
j = 0;
340                         while (st.hasMoreTokens()) {
341                             actionByOrigin[i][j] = st.nextToken();
342                             j++;
343                         }
344                     }
345                 } else {
346
347                     for (int i = 0; i < nbColumns - 2; i++) {
348                         st = new StringTokenizer JavaDoc(reader.readLine(), "\t");
349                         String JavaDoc temp = st.nextToken(); // State name
350
action[i] = st.nextToken();
351                     }
352                 }
353             }
354
355             reader.close();
356
357         } catch (IOException JavaDoc ioe) {
358             System.err.println("An error occured while reading " + filename
359                     + ". (" + ioe.getMessage() + ")");
360             return false;
361         } catch (NoSuchElementException JavaDoc nsu) {
362             System.err.println("File format error in file " + filename
363                     + " Reason: " + nsu.getMessage());
364             return false;
365         } catch (NumberFormatException JavaDoc ne) {
366             System.err.println("Number format error in file " + filename
367                     + "Reason: " + ne.getMessage());
368             return false;
369         }
370
371         return true;
372     }
373
374     /**
375      * For debugging purpose. Trace all the structures.
376      */

377     private void displayMatrix() {
378
379         System.out.println("Listing table states: ");
380         System.out.println("--------------------------");
381         for (int i = 0; i < stateNames.length; i++) {
382             System.out.println(stateNames[i]);
383         }
384
385         System.out.println();
386
387         System.out.println("Listing transition table: ");
388         System.out.println("------------------------------");
389         for (int i = 0; i < transitions.length; i++) {
390             for (int j = 0; j < transitions[0].length; j++) {
391                 System.out.print("(" + i + "," + j + ")" + transitions[i][j]
392                         + " ");
393             }
394             System.out.println();
395         }
396
397         if (!identifyByOrigin) {
398
399             System.out.println();
400
401             System.out.println("Listing state action: ");
402             System.out.println("------------------------");
403             for (int i = 0; i < action.length; i++) {
404                 System.out.println(action[i]);
405             }
406         } else {
407
408             System.out.println();
409
410             System.out.println("Listing state action by origin: ");
411             System.out.println("-------------------------------------");
412             for (int i = 0; i < actionByOrigin.length; i++) {
413                 for (int j = 0; j < actionByOrigin[0].length; j++) {
414                     System.out.println("(" + i + "," + j + ")"
415                             + actionByOrigin[i][j]);
416                 }
417             }
418         }
419
420         System.out.println();
421
422         System.out.println("Listing Wait time: ");
423         System.out.println("-------------------");
424         for (int i = 0; i < transitionsTime.length; i++) {
425             System.out.println(transitionsTime[i]);
426         }
427
428         System.out.println();
429
430         System.out.println("Listing variables: ");
431         System.out.println("-------------------");
432         for (int i = 0; i < prop.size(); i++) {
433             System.out.println(prop.keys());
434         }
435
436     }
437
438     /**
439      * This method compute the next state calculated with the matrix data.
440      *
441      * @return The value of the next state.
442      */

443     private int nextState() {
444
445         beforeStep = currentState;
446         float step = rand.nextFloat();
447         float cumul = 0;
448         int i;
449
450         if (DEBUG) {
451             System.out.print("rand = " + step + " --- ");
452             System.out.print("previous state = " + beforeStep + " --- ");
453         }
454
455         // Determine the next state with the random value
456
for (i = 0; i < nbRows; i++) {
457             cumul = cumul + transitions[i][currentState];
458             if (step < cumul) {
459                 currentState = i;
460                 break;
461             }
462         }
463
464         if (DEBUG)
465             System.out.print("current state = " + currentState + " --- ");
466
467         // Deal with Back to previous state
468
if (currentState == nbRows - 2) {
469             isBackClicked = true;
470             if (DEBUG)
471                 System.out.println("Back...");
472             if (previousStates.empty())
473                 System.out
474                         .println("Error detected: Trying to go back but no previous state is available (currentState:"
475                                 + currentState + ", beforeStep:" + beforeStep);
476             else {
477                 try {
478                     if (useMatrixThinkTime)
479                         Thread
480                                 .sleep((long) ((float) transitionsTime[currentState]));
481                 } catch (java.lang.InterruptedException JavaDoc ie) {
482                     System.err.println("Thread "
483                             + Thread.currentThread().getName()
484                             + " has been interrupted.");
485                 }
486
487                 Integer JavaDoc previous = (Integer JavaDoc) previousStates.pop();
488                 currentState = previous.intValue();
489
490                 return currentState;
491             }
492         } else { // Add this state to history (previousStates) if needed
493
isBackClicked = false;
494             if (!isEndOfSession()) {
495                 if (DEBUG)
496                     System.out.print("Not end session --- ");
497                 // If there is no probability to go back from this state, just
498
// empty the stack
499
if (transitions[nbRows - 2][currentState] == 0) {
500                     if (DEBUG)
501                         System.out.println("no back possibility ");
502                     previousStates.removeAllElements();
503                 } else { // else add the previous state to the history just in
504
// case we go back !
505
if (DEBUG)
506                         System.out.println();
507                     previousStates.push(new Integer JavaDoc(beforeStep));
508                 }
509             } else {
510                 currentState = -1;
511                 if (DEBUG)
512                     System.out.println("End session");
513             }
514         }
515
516         if (currentState != -1) {
517             try {
518
519                 if (useMatrixThinkTime)
520                     Thread
521                             .sleep((long) ((float) transitionsTime[currentState]));
522
523             } catch (java.lang.InterruptedException JavaDoc ie) {
524                 System.err.println("Thread " + Thread.currentThread().getName()
525                         + " has been interrupted.");
526             }
527         }
528
529         return currentState;
530     }
531
532     /**
533      * Tests if the current state is the End of Session state.
534      *
535      * @return true if the current state is the end of session.
536      */

537     private boolean isEndOfSession() {
538         return currentState == nbRows - 1;
539     }
540
541     /**
542      * Return the name of the current state
543      *
544      * @return The String representing the name of the current state in the
545      * matrix
546      */

547     public String JavaDoc getCurrentStateName() {
548         return stateNames[currentState];
549     }
550
551     /**
552      * Return the time to wait for the current state
553      *
554      * @return the time to wait
555      */

556     public long getCurrentWaitingTime() {
557         return transitionsTime[currentState];
558     }
559
560     /**
561      * @return the action associated to the next state
562      */

563     public Transition getNextTransition() {
564         trans.setTransition(getStateTransition(nextState()));
565         return trans;
566     }
567
568     private void resetToInitialState() {
569         currentState = 0;
570         previousStates.removeAllElements();
571     }
572
573     private boolean isBackClicked() {
574         return isBackClicked;
575     }
576
577     /**
578      * This method transform a state value into its associated action.
579      *
580      * @param state
581      * The state to transform into action
582      * @return The action of the specified state.
583      */

584     private String JavaDoc getStateTransition(int state) {
585         // If the current state is an end of session
586
if (state == -1) {
587             resetToInitialState();
588             return null;
589         } else if (identifyByOrigin) {
590             // If the back action is invoked, then we have to invert the current
591
// state with the previous state to get the previous action
592
// properly.
593
if (isBackClicked)
594                 return actionByOrigin[beforeStep][state];
595             else
596                 return actionByOrigin[state][beforeStep];
597         } else
598             return action[state];
599     }
600
601     /**
602      * Store the variables into the properties.
603      *
604      * @param line
605      */

606     private void loadProperty(String JavaDoc line) {
607         int index = line.indexOf("=");
608         prop.setProperty(line.substring(0, index), line.substring(index + 1,
609                 line.length()));
610     }
611
612 }
Popular Tags