1 /**
2 * .
3 * Copyright � 1999 Erich P G.
4 *
5 */
6
7 package autohit;
8
9 import java.util.Vector;
10
11 import autohit.vm.*;
12 import autohit.utils.Log;
13 import autohit.transport.Transport;
14 import autohit.transport.Response;
15 import autohit.transport.Query;
16 import autohit.verify.Verify;
17
18 import HTTPClient.NVPair;
19
20 /**
21 * A VM for a Sim. This version does not handle scope caches for headers or body
22 * elements. I'm not sure how much faster they would make the VM, so I'll wait.
23 * <p>
24 * <br>NOTES for Sim coders --------------------------------------------------<br>
25 *
26 * A string will only be resolved once, therefore a variable may only be substituted in
27 * a string once. No references to reference. :-)<br>
28 *
29 * SET. Both name and value will be resolved. All variables preceded with a '!' will be
30 * set on the registered transport. It will *not* be removed from the transport when
31 * it falls out of scope!<p>
32 * WAIT. This instruction will block the VM until the time expires. <p>
33 *
34 * <p>
35 * -----------------------------------------------------------------------<br>
36 *
37 * This VM expects the following environment variables to be set
38 * before the execute() method is called. If they aren't set, the defaults
39 * will be used.
40 * <p>
41 * <pre>
42 * VAR | DESC | DEFAULT |
43 * ------------------------------------------------------------------------
44 * $sname$ | Session name. Added to log | The Sim.name |
45 * | entries | |
46 *
47 * </pre>
48 *
49 * @see autohit.vm.VM
50 * @see autohit.Sim
51 *
52 * @author Erich P. Gatejen
53 * @version 1.0
54 * <i>Version History</i>
55 * <code>EPG - Initial - 5Jan99
56 * EPG - Ok, try again using new VM architecture. - 22Jan99</code>
57 *
58 */
59 public class SimVM extends VM {
60
61 // --- FINAL FIELDS ------------------------------------------------------
62
63 // --- FIELDS ------------------------------------------------------------
64
65 /**
66 * The Sim to execute.
67 *
68 * @see autohit.Sim
69 */
70 private Sim mySim;
71
72 /**
73 * Last response. Verification instructions will reference THIS
74 * field.
75 *
76 * @see autohit.transport.Response
77 */
78 private Response lResponse;
79
80 /**
81 * Session name. This will be appended to each logged line.
82 * <p>
83 * If a $sname$ environment var was set for this sim, it will be used.
84 * Otherwise, the Sim.name will be used.
85 */
86 private String sname;
87
88 /**
89 * The logging mechinism.
90 *
91 * @see autohit.utils.Log
92 */
93 public Log myLog;
94
95 /**
96 * The transport mechinism.
97 *
98 * @see autohit.transport.Transport
99 */
100 public Transport myTransport;
101
102 /**
103 * The verification mechinism.
104 *
105 * @see autohit.verify.Verify
106 */
107 public Verify myVerify;
108
109
110 // --- PUBLIC METHODS ----------------------------------------------------
111
112 /**
113 * Constructor. Will create the Sim VM but will not start execution; use the
114 * start() method for that.
115 * <p>
116 * This class assumes that the logging object has already been started.
117 * <p>
118 * Do NOT use the default constructor! Call this constructor.
119 *
120 * @param theSim the Sim to be executed.
121 * @param logTarget target for logging.
122 * @param myTransport transport mechanism to use. This is for future use; you
123 * can pass null to it.
124 * @param myVerify verification mechanism.
125 */
126 public SimVM(Sim theSim, Log logTarget, Transport theTransport,
127 Verify theVerify ) {
128
129 super();
130
131 mySim = theSim;
132 myLog = logTarget;
133 myTransport = theTransport;
134 myVerify = theVerify;
135 }
136
137 /**
138 * Prepare for execution of the first instruction. We need to
139 * add environment variables. DO NOT call this method directly.
140 *
141 * @throws Any exceptions it encounters.
142 */
143 public void prepare() throws Exception {
144
145 // Check for default environment variables
146 if (vars.containsKey("sname")) {
147 sname = (String)vars.get("sname");
148 } else {
149 vars.put("sname", mySim.name);
150 sname = mySim.name;
151 }
152
153 // Set stock environment vars
154 vars.put("lastVerify", "0");
155 vars.put("transCode", "0");
156
157 }
158
159 /**
160 * Implements the inherited abstract method execute(). Call this to execute
161 * a single instruction, The first call will be automatic after the inherited
162 * start() method is called. From there, the owning Object/Thread should
163 * call this method for each successive instruction to execute.
164 * <p>
165 * This method will throw a VMException(VMException.DONE) if there are
166 * no more instructions that can be executed. (The ip is past the
167 * end of the exec Vector).
168 * <p>
169 * We shall assume that a VMContext will handle
170 * threading issues.
171 * @see autohit.vm.VMContext
172 * @throws VMException
173 * @see autohit.vm.VMException
174 */
175 public void execute() throws VMException {
176
177 // Any instructions left to execute?
178 if (ip >= mySim.exec.size()) {
179 throw new VMException(VMException.DONE);
180 }
181
182 try {
183
184 VMInstruction ci = (VMInstruction)mySim.exec.get(ip);
185 // NOTES: Each instruction is responsible for advancing the
186 // ip.
187 //DEBUG
188 //System.out.println("IP = " + ip + " token=" + ci.nToken);
189
190 switch(ci.nToken) {
191
192 case VMInstruction.NOP:
193 // Just burn the cycle
194 ip++;
195 break;
196
197 case VMInstruction.GET:
198 handleGet((VMIGet)ci);
199 ip++;
200 break;
201
202 case VMInstruction.FOR:
203 handleFor((VMIFor)ci);
204 break;
205
206 case VMInstruction.WHILE:
207 handleWhile((VMIWhile)ci);
208 break;
209
210 case VMInstruction.SET:
211 handleSet((VMISet)ci);
212 ip++;
213 break;
214
215 case VMInstruction.WAIT:
216 handleWait((VMIWait)ci);
217 ip++;
218 break;
219
220 case VMInstruction.SCOPE:
221 // Just toss it on the scope stack
222 pushScope(ci);
223 ip++;
224 break;
225
226 case VMInstruction.RSCOPE:
227 // Let the VM unravel the scope stack.
228 discardScopeFrame();
229 ip++;
230 break;
231
232 case VMInstruction.HEADER:
233 // Just toss it on the scope stack
234 pushScope(ci);
235 ip++;
236 break;
237
238 case VMInstruction.IF:
239 handleIf((VMIIf)ci);
240 break;
241
242 case VMInstruction.NV:
243 // Just toss it on the scope stack
244 pushScope(ci);
245 ip++;
246 break;
247
248 case VMInstruction.JUMP:
249 // Change the instruction pointer to the target
250 VMIJump vmij = (VMIJump)ci;
251 ip = vmij.target;
252 break;
253
254 case VMInstruction.ADD:
255 handleAdd((VMIAdd)ci);
256 ip++;
257 break;
258
259 case VMInstruction.VERIFY:
260 handleVerify((VMIVerify)ci);
261 ip++;
262 break;
263
264 case VMInstruction.CRC:
265 handleCrc((VMICrc)ci);
266 ip++;
267 break;
268
269 case VMInstruction.SEEK:
270 handleSeek((VMISeek)ci);
271 ip++;
272 break;
273
274 case VMInstruction.EXEC:
275 handleExec((VMIExec)ci);
276 ip++;
277 break;
278
279 default:
280 String em = new String("Software Detected Fault: Unsupported instruction encounted by autohit.SimVM. nToken=[" + ci.nToken + "]");
281 wfLogPut(em);
282 throw new VMException(VMException.INVALID_INSTRUCTION, em);
283 }
284
285 } catch (VMException e) {
286
287 wfLogPut("!FAULT! in SimVM. Exception #" + e.numeric);
288 wfLogSub("message= " + e.getMessage());
289 throw e;
290 }
291
292 }
293
294
295 // == ===============================================================================
296 // == = INSTRUCTION HANDLERS =
297 // == ===============================================================================
298
299 private void handleSet(VMISet instr) throws VMException {
300
301 String name = instr.name;
302 String value = instr.value;
303
304 // Resolve any variables.
305 if (instr.iv) {
306 name = subVar(name);
307 value = subVar(value);
308 }
309
310 // If it isn't already in the vars, toss a reference on the scope stack.
311 if (!vars.containsKey(name)) {
312 pushScope(name);
313 }
314
315 vars.put(name, value);
316
317 // Do we need to set it with the transport?
318 if(name.charAt(0) == '!') {
319
320 try {
321 myTransport.environment(name.substring(1), value);
322
323 } catch (Exception e) {
324 throw new VMException(VMException.VARIABLE_TYPE_MISMATCH, "Empty transport environment variable");
325 }
326 }
327 }
328
329 private void handleWait(VMIWait instr) throws VMException {
330
331 String time = instr.time;
332 int numeric = 0;
333
334 // Resolve any variables.
335 if (instr.iv) {
336 time = subVar(time);
337 }
338
339 // try to get a number out of the time field
340 try {
341 numeric = Integer.parseInt(time);
342
343 } catch (Exception e) {
344 throw new VMException(VMException.VARIABLE_TYPE_MISMATCH , "Time is not a numeric. [" + time + "]");
345 }
346
347 // Wait...
348 try {
349 wfLogPut("WAIT: start=" + ticks() + " for " + numeric);
350 Thread.sleep(numeric);
351
352 } catch (Exception e) {
353 // dont care if we are interrupted.
354 }
355
356 }
357
358 private void handleGet(VMIGet instr) throws VMException {
359
360 int tstart = 0;
361 int tlen = 0;
362
363 try {
364
365 Query q = buildQuery();
366
367 if (instr.iv) {
368 q.qs = subVar(instr.qs);
369 } else {
370 q.qs = instr.qs;
371 }
372
373 tstart = this.ticks();
374 lResponse = myTransport.push(q);
375 tlen = this.ticks() - tstart;
376
377 wfLogPut("GET:" + "[s=" + tstart +
378 " l=" + tlen + "] tcode=" + lResponse.code +
379 " size=" + lResponse.cLength);
380 wfLogSub("url=" + q.qs);
381
382 vars.put("transCode", Integer.toString(lResponse.code));
383
384 } catch (Exception e) {
385
386 // Prolly should come back and make this exception more informative....
387 wfLogPut("GET: Failed do to exception! for url=");
388 wfLogSub(instr.qs);
389 wfLogSub("Exception =" + e.getMessage());
390 }
391 }
392
393 private void handleIf(VMIIf instr) throws VMException {
394
395 String e = instr.e;
396 String value = instr.value;
397
398 // Resolve any variables.
399 if (instr.iv) {
400 e = subVar(e);
401 value = subVar(value);
402 }
403
404 // Are they equal?
405 if (e.equals(value)) {
406
407 // Yes. Advance IP to next instruction
408 ip++;
409
410 } else {
411
412 // Nope. Jump over the block
413 ip = instr.target;
414 }
415 }
416
417 private void handleFor(VMIFor instr) throws VMException {
418
419 String count = instr.count;
420
421 // automatically resolve any variables.
422 count = subVar(count);
423
424 String value = (String)vars.get(count);
425
426 // Are they equal?
427 if (value.equals("0")) {
428
429 // Yes. JJump to the target
430 ip = instr.target;
431
432 } else {
433
434 // Nope. Next instruction
435 ip++;
436 }
437 }
438
439 private void handleWhile(VMIWhile instr) throws VMException {
440
441 String e = instr.e;
442 String value = instr.value;
443
444 // Resolve any variables.
445 if (instr.iv) {
446 e = subVar(e);
447 value = subVar(value);
448 }
449
450 // Are they equal?
451 if (e.equals(value)) {
452
453 // Yes. jump back and do the loop again
454 ip = instr.target;
455
456 } else {
457
458 // Nope. move out of the block
459 ip++;
460 }
461 }
462
463 private void handleAdd(VMIAdd instr) throws VMException {
464
465 String name = instr.name;
466 String value = instr.value;
467 int result = 0;
468
469 // Resolve any variables.
470 if (instr.iv) {
471 name = subVar(name);
472 value = subVar(value);
473 }
474
475 // Find the variable.
476 String varVal = (String)vars.get(name);
477 if (varVal == null) {
478 throw new VMException(VMException.VARIABLE_NOT_DEFINED , "Variable not defined for ADD. [" + name + "]");
479 }
480
481 // Try add them.
482 try {
483 result = Integer.parseInt(varVal) + Integer.parseInt(value);
484
485 } catch (Exception e) {
486 throw new VMException(VMException.VARIABLE_TYPE_MISMATCH , "Type mismatch in add. [" + varVal + "][" + value + "]");
487 }
488
489 vars.put(name, String.valueOf(result));
490 }
491
492 private void handleVerify(VMIVerify instr) throws VMException {
493
494 try {
495
496 // freshed the context
497 myVerify.fresh(lResponse);
498
499 // verify size if we must...
500 if (instr.size != VMIVerify.NO_SIZE) {
501
502 if (myVerify.size(instr.size)) {
503 wfPass("SIZE.");
504
505 } else {
506 wfFail("SIZE. difference=" + myVerify.lastDelta());
507 }
508 }
509
510 } catch (Exception e) {
511 throw new VMException(VMException.SUBSYSTEM_FAULT , "Verification Subsystem fault. Unable to freshen context. sub=" + e.getMessage());
512 }
513 }
514
515 private void handleCrc(VMICrc instr) throws VMException {
516
517 try {
518
519 if (myVerify.crc(instr.expected)) {
520
521 wfPass("CRC.");
522
523 } else {
524
525 wfFail("CRC. difference=" + myVerify.lastDelta());
526 }
527
528 } catch (Exception e) {
529 throw new VMException(VMException.SUBSYSTEM_FAULT , "Verification Subsystem fault. Unable to verify CRC. sub=" + e.getMessage());
530 }
531 }
532
533 private void handleSeek(VMISeek instr) throws VMException {
534
535 try {
536
537 if (myVerify.seek(instr.expected)) {
538
539 wfPass("SEEK.");
540
541 } else {
542
543 wfFail("SEEK. expected=" + instr.expected);
544 }
545
546 } catch (Exception e) {
547 throw new VMException(VMException.SUBSYSTEM_FAULT , "Verification Subsystem fault. Unable to verify SEEK. sub=" + e.getMessage());
548 }
549 }
550
551 private void handleExec(VMIExec instr) throws VMException {
552
553 try {
554
555 if (myVerify.exec(instr.invocation, instr.content)) {
556
557 wfPass("EXEC.");
558
559 } else {
560
561 wfFail("EXEC.");
562 }
563
564 } catch (Exception e) {
565 throw new VMException(VMException.SUBSYSTEM_FAULT , "Verification Subsystem fault. Unable to verify EXEC. sub=" + e.getMessage());
566 }
567 }
568
569
570 // == ===============================================================================
571 // == = PRIVATE METHODS =
572 // == ===============================================================================
573
574 private void wfLogPut(String text) {
575
576 myLog.put(sname + ":" + text);
577 }
578
579
580 private void wfLogSub(String text) {
581
582 myLog.putSub(sname + ":" + text);
583 }
584
585 private void wfPass(String text) {
586
587 vars.put("lastVerify", "1");
588 myLog.putSub("PASS :" + text);
589 }
590
591 private void wfFail(String text) {
592
593 vars.put("lastVerify", "0");
594 myLog.putSub("FAIL :" + text);
595 }
596
597 // Does the grunt work of looking throw the scope stack for headers and NVs
598 private Query buildQuery() throws VMException {
599
600 Vector h = new Vector();
601 Vector b = new Vector();
602
603 String name;
604 String value;
605
606 Object so;
607 VMIHeader hobj;
608 VMINV nobj;
609
610 NVPair nv;
611
612 Query q = new Query();
613
614 // Run the scope stack.
615 int size = scope.size() - 1;
616 while (size > 0) {
617
618 so = scope.elementAt(size);
619
620 if ( so instanceof VMIHeader) {
621
622 hobj = (VMIHeader)so;
623
624 name = subVar(hobj.name);
625 value = subVar(hobj.value);
626
627 nv = new NVPair(name, value);
628 h.add(nv);
629
630 } else if (so instanceof VMINV) {
631
632 nobj = (VMINV)so;
633
634 name = subVar(nobj.name);
635 value = subVar(nobj.value);
636
637 nv = new NVPair(name, value);
638 b.add(nv);
639 }
640
641 size--;
642 }
643
644 // build the Query
645 if (h.size() > 0) {
646
647 q.headers = (HTTPClient.NVPair[]) h.toArray(new NVPair[h.size()]);
648
649 } else {
650 q.headers = null;
651 }
652
653 if (b.size() > 0) {
654
655 q.body = (HTTPClient.NVPair[]) b.toArray(new NVPair[b.size()]);
656
657 } else {
658 q.body = null;
659 }
660
661 return q;
662 }
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686 }
|