Source code for /engineering/autohit-1998/autohit/SimVM.javaOriginal file SimVM.java
   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 }