Frames | No Frames |
1: /* ScanEngine.java 2: -- Scans the input and generates an object tree that can be written as XML. 3: Copyright (C) 2005 Free Software Foundation, Inc. 4: 5: This file is part of GNU Classpath. 6: 7: GNU Classpath is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU Classpath is distributed in the hope that it will be useful, but 13: WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15: General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU Classpath; see the file COPYING. If not, write to the 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20: 02110-1301 USA. 21: 22: Linking this library statically or dynamically with other modules is 23: making a combined work based on this library. Thus, the terms and 24: conditions of the GNU General Public License cover the whole 25: combination. 26: 27: As a special exception, the copyright holders of this library give you 28: permission to link this library with independent modules to produce an 29: executable, regardless of the license terms of these independent 30: modules, and to copy and distribute the resulting executable under 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: 40: package gnu.java.beans.encoder; 41: 42: import java.beans.Expression; 43: import java.beans.Statement; 44: import java.io.OutputStream; 45: import java.lang.reflect.Array; 46: import java.util.HashMap; 47: import java.util.IdentityHashMap; 48: import java.util.List; 49: import java.util.Stack; 50: 51: /** <p>The <code>ScanEngine</code> is the main class of the backend of the 52: * XML persistence algorithm. It scans {@link java.beans.Expression} and 53: * {@link java.beans.Statement} instances and some raw objects via the 54: * {@link #writeObject} method and feeds it to a state machine. The 55: * state machine then constructs and object tree which is finally 56: * written as XML by a {@link Writer} implementation.</p> 57: * 58: * <p>How does it work?</p> 59: * <p>The <code>ScanEngine</code> sits below the {@link java.beans.XMLEncoder} 60: * class and is called by it exclusively. The <code>XMLEncoder</code> sends 61: * interpretive data by invoking {@link #writeExpression}, {@link #writeStatement} 62: * and {@link #writeObject}. The invocations of <code>writeExpression</code> and 63: * <code>writeStatement</code> are usually nested into each other and provide 64: * more information then necessary to generate the XML representation. 65: * Furthermore the meaning of certain <code>Expressions</code> differs 66: * depending on the enclosing elements or the inner elements have to be 67: * simply discarded.</p> 68: * 69: * <p>To cope with this state dependant nature the <code>ScanEngine</code> 70: * contains a state machine which is programmed statically (no adjustments are 71: * needed, all <code>ScanEngine</code> engines use the same setup). The 72: * <code>ScanEngine</code>'s job is to decode the <code>Expression</code>s, 73: * <code>Statement</code>s and certain objects (namely <code>String</code>, 74: * <code>null</code> objects and instances which are repeatedly provided to 75: * the encoder) into 13 low-level (event) methods, which denote the meaning of the 76: * argument. For example an <code>Expression</code> can be an array 77: * instantiation which provokes a call to {@link arrayInstantiation} or 78: * it can be a class resolution leading to a call to {@link #classResolution}. 79: * For the state machione the 13 methods are the distinct way to transit 80: * from one state to another. Whenever the <code>ScanEngine</code> calls 81: * one of the event methods the current's state successor for that event 82: * is fetched from the state machine configuration, the successpr becomes 83: * the current state and then the event method is called in the new current 84: * state. The last step allows the state instance to do something meaningful 85: * to the object tree.</p> 86: * 87: * <p>The state machine knows the concept of returning to the previous 88: * state. This is done using a stack of states which is popped every 89: * time a call to <code>writeStatement</code>, <code>writeExpression</code> 90: * in the <code>XMLEncoder</code> ends by calling the {@link #end} method. 91: * Note that due to the inheritance relationship of <code>Encoder</code> 92: * and <code>XMLEncoder</code> it is impossible for the 93: * <code>ScanEngine</code> itself to decide when an expression or statement 94: * ended. This can only be done in case of {@link #writeObject} calls because 95: * they are not nested.</p> 96: * 97: * <p>When the XML persistence mechanism reaches an object twice (and more) 98: * it should generate an XML element using the "idref" attribute and add 99: * an "id" attribute to its first instantiation. This complicates things a bit 100: * because the first instantiation will always be part of the object tree 101: * as some {@link gnu.java.beans.encoder.elements.Element} subclass instance when the 102: * second and further objects accesses are written. Therefore the {@link ObjectId} 103: * class was introduced which is shared between all the object tree elements 104: * and has the notion of an "unused" state meaning that no identification 105: * is needed. The relationship between an object and its <code>ObjectId</code> 106: * instance is stored in the <code>ScanEngine</code> and gets cleared whenever 107: * the {@link #flush} method is called. This method also writes the currently 108: * built object tree and generates the XML representation.</p> 109: * 110: * @author Robert Schuster (robertschuster@fsfe.org) 111: */ 112: public class ScanEngine 113: { 114: 115: /** Change this to true to let the ScanEngine print state transition 116: * information. 117: */ 118: boolean DEBUG = false; 119: 120: /** 121: * Stores the scanner engine states as values and their names as keys. 122: */ 123: HashMap states = new HashMap(); 124: 125: /** 126: * Stores former scanner state and makes it possible to come back to them. 127: */ 128: Stack parents = new Stack(); 129: 130: /** 131: * The currently active scanner state. 132: */ 133: ScannerState current; 134: 135: /** 136: * The root of an object tree that is later written to XML. 137: */ 138: Root root; 139: 140: /** 141: * The Writer used to generate the XML output. 142: */ 143: Writer writer; 144: 145: /** Stores the relationship between objects and their {@link ObjectId} instance. 146: */ 147: IdentityHashMap objects = new IdentityHashMap(); 148: 149: public ScanEngine(OutputStream os) 150: { 151: // TODO: Provide another Writer implementation (e.g. one that does not use 152: // the XML APIs at all). 153: writer = new StAXWriter(os); 154: root = new Root(); 155: 156: final ScannerState start = current = new GenericScannerState(root); 157: ScannerState conf; 158: 159: // Use the ReportingScannerState to debug serialization issues. 160: register(ScannerState.DEFAULT_STATE_NAME, new IgnoringScannerState()); 161: 162: register("start", start); 163: 164: // Special dead-end state where all transitions are ignored. 165: register("ignoreAll", new IgnoringScannerState()) 166: .setDefaultSuccessor("ignoreAll"); 167: 168: // Object reference, string reference, null object 169: start.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "simple"); 170: start.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "simple"); 171: start.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "simple"); 172: register("simple", new GenericScannerState(root)) 173: .setDefaultSuccessor("ignoreAll"); 174: 175: // Class resolution. 176: start.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "classRes0"); 177: register("classRes0", 178: new GenericScannerState(root)).setDefaultSuccessor("ignoreAll"); 179: 180: // Object instantiation. 181: start.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, 182: "newObj0"); 183: conf = register("newObj0", new GenericScannerState(root)); 184: conf.setDefaultSuccessor("ignoreAll"); 185: 186: // Simply use the start state to encode method invocations inside of 187: // objects. 188: conf.putSuccessor(ScannerState.TRANSITION_METHOD_INVOCATION, "start"); 189: 190: // Primitive instantiations. 191: start.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, 192: "newPrimitive0"); 193: register("newPrimitive0", 194: new GenericScannerState(root)).setDefaultSuccessor("ignoreAll"); 195: 196: // Object arrays use the ARRAY_GET transition to create setting the 197: // array values. 198: start.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION, 199: "newObjectArray"); 200: conf = register("newObjectArray", new GenericScannerState(root)); 201: conf.putSuccessor(ScannerState.TRANSITION_ARRAY_GET, "newOArrayGet"); 202: conf.putSuccessor(ScannerState.TRANSITION_ARRAY_SET, "ignoreAll"); 203: conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); 204: conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, 205: "ignoreAll"); 206: 207: // Get here when a value is set in the array. 208: register("newOArrayGet", 209: conf = new GenericScannerState(root)); 210: 211: conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, 212: "newOArrayGet_ignoreFirstInteger"); 213: 214: // "newArrayGet_ignoreFirstInteger" is set up mostly identical like the "start" 215: // state. Otherwise things would not behave the same when done inside 216: // arrays. 217: conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "simple"); 218: conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "simple"); 219: conf.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "simple"); 220: conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "classRes0"); 221: conf.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, "newObj0"); 222: conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION, 223: "newPrimitiveArray"); 224: conf.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION, 225: "newObjectArray"); 226: 227: conf = register("newOArrayGet_ignoreFirstInteger", 228: new GenericScannerState(root, 1)); 229: 230: // In non-int primitive arrays class resolutions can happen 231: // but they should be ignored. 232: conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); 233: 234: // Spurious object and string references occur when setting array 235: // elements. This suppresses them. 236: conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, 237: "ignoreAll"); 238: conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "ignoreAll"); 239: conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll"); 240: 241: conf.setDefaultSuccessor("start"); 242: 243: // Primitive arrays use the ARRAY_SET transition to create setting the 244: // array values. This turned out to be the only working solution. 245: // When primitive arrays were handled by ARRAY_GET the values in boolean 246: // arrays were always skipped. 247: start.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION, 248: "newPrimitiveArray"); 249: conf = register("newPrimitiveArray", new GenericScannerState(root)); 250: conf.putSuccessor(ScannerState.TRANSITION_ARRAY_GET, "ignoreAll"); 251: conf.putSuccessor(ScannerState.TRANSITION_ARRAY_SET, "newPArraySet"); 252: conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); 253: conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, 254: "ignoreAll"); 255: 256: conf = register("newPArraySet", new GenericScannerState(root)); 257: conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, 258: "newPArraySet_ignoreFirstInteger"); 259: 260: // Primitive arrays ignore all kinds of non-primitive object information. 261: conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, 262: "ignoreAll"); 263: conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll"); 264: conf.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "ignoreAll"); 265: conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ingoreAll"); 266: conf.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, "ignoreAll"); 267: conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION, 268: "ignoreAll"); 269: conf.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION, 270: "ignoreAll"); 271: 272: conf = register("newPArraySet_ignoreFirstInteger", 273: new GenericScannerState(root, 1)); 274: 275: // In non-int primitive arrays class resolutions can happen 276: // but they should be ignored. 277: conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); 278: 279: // Spurious object and string references occur when setting array 280: // elements. This suppresses them. 281: conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, 282: "ignoreAll"); 283: conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "ignoreAll"); 284: conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll"); 285: conf.setDefaultSuccessor("start"); 286: 287: } 288: 289: /** Registers a <code>ScannerState</code> under a certain name. 290: * 291: * @param name Name of the state 292: * @param state The <code>ScannerState</code> instance. 293: * @return The second argument. 294: */ 295: private ScannerState register(String name, ScannerState state) 296: { 297: state.init(name); 298: 299: states.put(name, state); 300: 301: return state; 302: } 303: 304: /** Generates or returns an id for the given object which can be activated 305: * later if the object is suitable. 306: * 307: * <p>Objects are unsuitable if they are an instance of a primitive wrapper 308: * or String.</p> 309: * 310: * @param value The object to retrieve an id for. 311: * @return The id for the object or <code>null</code>. 312: */ 313: private ObjectId retrieveId(Object value) 314: { 315: Class valueClass = value.getClass(); 316: ObjectId id = null; 317: 318: // Although multiple accesses to Class objects are not handled 319: // through ids we generate one for them, too. This allows us to detect 320: // second time references to such objects in the writeObject method 321: // and handle them in a special way. 322: if (valueClass != String.class 323: && valueClass.getSuperclass() != Number.class 324: && valueClass != Boolean.class) 325: { 326: if ((id = (ObjectId) objects.get(value)) == null) 327: { 328: id = new ObjectId(valueClass); 329: objects.put(value, id); 330: } 331: } 332: 333: return id; 334: } 335: 336: /** Scans the argument and calls one of event methods. See 337: * the introduction of this class for details. 338: * 339: * @param expr The expression to serialize. 340: */ 341: public void writeExpression(Expression expr) 342: { 343: String methodName = expr.getMethodName(); 344: Object[] args = expr.getArguments(); 345: Object target = expr.getTarget(); 346: Object value = null; 347: 348: try 349: { 350: value = expr.getValue(); 351: } 352: catch (Exception e) 353: { 354: throw (InternalError) 355: new InternalError( 356: "The Expression's value should be available at this point.") 357: .initCause(e); 358: } 359: 360: // TODO: What if the value is null? 361: ObjectId id; 362: Class valueClass = value.getClass(); 363: 364: if (target == Array.class) 365: { 366: if (methodName.equals("newInstance")) 367: { 368: id = retrieveId(value); 369: 370: Class ct = (Class) args[0]; 371: 372: if (ct.isPrimitive() || ct == Boolean.class || ct == Byte.class 373: || ct == Short.class || ct == Integer.class || ct == Long.class 374: || ct == Float.class || ct == Double.class) 375: primitiveArrayInstantiation(ct.getName(), 376: args[1].toString(), 377: id); 378: else 379: objectArrayInstantiation(ct.getName(), 380: args[1].toString(), 381: id); 382: 383: return; 384: } 385: else if (methodName.equals("get")) 386: { 387: arrayGet(args[1].toString()); 388: 389: // The encoder does not call the ScanEngine 390: // when an object is serialized that we already know. 391: // We test for this situation and insert the object reference 392: // manually. 393: // Since there is already a workaround for the Class class 394: // in writeObject we have to except it from this behavior. 395: id = (ObjectId) objects.get(value); 396: if (id != null && valueClass != Class.class) 397: { 398: objectReference(id); 399: end(); 400: } 401: 402: return; 403: } 404: else if (methodName.equals("set")) 405: { 406: arraySet(args[1].toString()); 407: return; 408: } 409: } 410: 411: id = retrieveId(value); 412: 413: if (target instanceof Class) 414: { 415: if (methodName.equals("new")) 416: { 417: Class targetClass = (Class) target; 418: 419: // All primitive types have short-hand forms for their 420: // constructors. 421: if (valueClass == Boolean.class) 422: primitiveInstantiation("boolean", args[0].toString()); 423: else if (valueClass == Byte.class) 424: primitiveInstantiation("byte", args[0].toString()); 425: else if (valueClass == Short.class) 426: primitiveInstantiation("short", args[0].toString()); 427: else if (valueClass == Integer.class) 428: primitiveInstantiation("int", args[0].toString()); 429: else if (valueClass == Long.class) 430: primitiveInstantiation("long", args[0].toString()); 431: else if (valueClass == Float.class) 432: primitiveInstantiation("float", args[0].toString()); 433: else if (valueClass == Double.class) 434: primitiveInstantiation("double", args[0].toString()); 435: else 436: objectInstantiation(targetClass.getName(), id); 437: 438: return; 439: } 440: else if (value instanceof Class) 441: { 442: String className = ((Class) value).getName(); 443: 444: // At this point we know that some *static* method will be called. 445: 446: if (methodName.equals("forName")) 447: { 448: // However "Class.forName" represents class resolution and has a 449: // special syntax. 450: classResolution(className); 451: return; 452: } 453: else if (methodName.equals("getField")) 454: { 455: // The same goes for "Class.getField". 456: // Note: The name of the wanted field is given in 457: // the argument array. 458: staticFieldAccess(className, args[0].toString()); 459: return; 460: } 461: else 462: { 463: // If nothing fits it is just a static method 464: // invocation which we decode as such. 465: staticMethodInvocation(className, methodName); 466: return; 467: } 468: } 469: } 470: else if (target instanceof List) 471: { 472: // Special behavior for indexed get and set method for list-style 473: // classes. 474: // The arguments are in the args array but we need them as subelements. 475: if (methodName.equals("get")) 476: { 477: listGet(); 478: return; 479: } 480: else if (methodName.equals("set")) 481: { 482: listSet(); 483: return; 484: } 485: } 486: 487: // If nothing else could be used then this is a normal 488: // method invocation. 489: methodInvocation(methodName); 490: } 491: 492: /** 493: * Ends the current state and returns to the last one. 494: */ 495: public void end() 496: { 497: current.end(); 498: 499: if (DEBUG) System.err.print("back from " + current.getName()); 500: 501: ScannerState oldCurrent = current; 502: current = (ScannerState) parents.pop(); 503: 504: if (DEBUG) System.err.println(" to " + current.getName()); 505: } 506: 507: /** 508: * Returns to the last state and deletes the last element in the object tree. 509: */ 510: public void revoke() 511: { 512: ScannerState oldCurrent = current; 513: current = (ScannerState) parents.pop(); 514: 515: root.deleteLast(); 516: } 517: 518: /** Scans the argument and calls one of event methods. See 519: * the introduction of this class for details. 520: * 521: * @param stmt The statement to serialize. 522: */ 523: public void writeStatement(Statement stmt) 524: { 525: // This is a simplified version of writeExpression. Everything 526: // that would not create something that is embedded in a <void> tag 527: // is left out (instantiation, getters, ...). 528: // TODO: Is this the right thing to do? 529: 530: String methodName = stmt.getMethodName(); 531: Object target = stmt.getTarget(); 532: Object[] args = stmt.getArguments(); 533: 534: if (target == Array.class && methodName.equals("set")) 535: { 536: arraySet(args[1].toString()); 537: return; 538: } 539: 540: if (target instanceof List) 541: { 542: if (methodName.equals("set")) 543: { 544: listSet(); 545: return; 546: } 547: } 548: 549: // If nothing else could be used then this is a normal 550: // method invocation. 551: methodInvocation(methodName); 552: } 553: 554: /** Scans the argument and calls one of event methods. See 555: * the introduction of this class for details. 556: * 557: * @param o The object to serialize. 558: */ 559: public boolean writeObject(Object o) 560: { 561: ObjectId id = null; 562: 563: if (o == null) 564: { 565: // Handle null objects which have a special syntax. 566: nullObject(); 567: end(); 568: } 569: else if (o.getClass() == String.class) 570: { 571: // Handle strings which are treated extremely special 572: // in the encoder (they are never converted into a 573: // Expression). 574: stringReference((String) o); 575: end(); 576: } 577: else if ((id = (ObjectId) objects.get(o)) != null) 578: { 579: // Multiple references to a Class object do not generate 580: // an object reference but we use the id to detect that 581: // situation. 582: if (o.getClass() == Class.class) 583: { 584: classResolution(((Class) o).getName()); 585: end(); 586: return false; 587: } 588: 589: // If our object has a corresponding ObjectId instance 590: // then generate an objectReference. This will 591: // initialize the id (= brings it in the "used" state) 592: // when this is the first referal. 593: objectReference(id); 594: end(); 595: return false; 596: } 597: 598: return true; 599: } 600: 601: /** 602: * Writes the currently constructed object tree out as 603: * XML and clears the object to {@link ObjectId} relations. 604: */ 605: public void flush() 606: { 607: // Make all references unreachable. That means we have to generate 608: // new object ids. 609: objects.clear(); 610: 611: root.traverse(writer); 612: } 613: 614: /** Writes the final bits if the object tree and closes the stream 615: * afterwards. 616: */ 617: public void close() 618: { 619: flush(); 620: root.close(writer); 621: } 622: 623: /** 624: * Does a transition from one state to another using the given event. 625: * 626: * <p>This involves saving the current state, retrieving it's 627: * successor and setting it as the current state.</p> 628: * 629: * @param transition One of {@link ScannerStates]'s transition constants. 630: */ 631: private void transition(int transition) 632: { 633: parents.push(current); 634: 635: String stateName = current.getSuccessor(transition); 636: 637: if (DEBUG) 638: { 639: System.err.println("from state: " + current.getName() + "\n\troute: " 640: + ScannerState.transitionNames[transition] 641: + "\n\t\tto state: " 642: + stateName); 643: } 644: 645: ScannerState newState = (ScannerState) states.get(stateName); 646: 647: newState.enter(new Context(current.getName(), current.getCalls())); 648: 649: assert (newState != null) : "State '" + stateName + "' was not defined."; 650: 651: current = newState; 652: } 653: 654: /** Event method that denotes a (non-static) method invocation. 655: * 656: * <p>More details about this method can be found in this 657: * class' introduction.</p> 658: * 659: * @param methodName The name of the method which is called. 660: */ 661: void methodInvocation(String methodName) 662: { 663: transition(ScannerState.TRANSITION_METHOD_INVOCATION); 664: 665: current.methodInvocation(methodName); 666: } 667: 668: /** Event method that denotes a static method invocation. 669: * 670: * <p>More details about this method can be found in this 671: * class' introduction.</p> 672: * 673: * @param methodName The name of the method which is called. 674: * @param className The name of the class in which the method is called. 675: */ 676: void staticMethodInvocation(String className, String methodName) 677: { 678: transition(ScannerState.TRANSITION_STATIC_METHOD_INVOCATION); 679: 680: current.staticMethodInvocation(className, methodName); 681: } 682: 683: /** Event method that denotes the retrieval of a static field's value. 684: * 685: * <p>More details about this method can be found in this 686: * class' introduction.</p> 687: * 688: * @param fieldName The name of the field whose value is retrieved. 689: * @param className The name of the class in which the method is called. 690: */ 691: void staticFieldAccess(String className, String fieldName) 692: { 693: transition(ScannerState.TRANSITION_STATIC_FIELD_ACCESS); 694: 695: current.staticFieldAccess(className, fieldName); 696: } 697: 698: /** Event method that denotes the resolution of a class. 699: * 700: * <p>More details about this method can be found in this 701: * class' introduction.</p> 702: * 703: * @param className The name of the class in which the method is called. 704: */ 705: void classResolution(String className) 706: { 707: transition(ScannerState.TRANSITION_CLASS_RESOLUTION); 708: 709: current.classResolution(className); 710: } 711: 712: /** Event method that denotes the instantiation of an object. 713: * 714: * <p>More details about this method can be found in this 715: * class' introduction.</p> 716: * 717: * @param className The name of the class in which the method is called. 718: * @param objectId An ObjectId instance which can be activated later. 719: */ 720: void objectInstantiation(String className, ObjectId objectId) 721: { 722: transition(ScannerState.TRANSITION_OBJECT_INSTANTIATION); 723: 724: current.objectInstantiation(className, objectId); 725: } 726: 727: /** Event method that denotes the instantiation of a primitive. 728: * 729: * <p>More details about this method can be found in this 730: * class' introduction.</p> 731: * 732: * @param primitiveName One of "boolean, "byte", "short", "int", "long" 733: * , "float" or "double" 734: * @param valueAsString The value of the primitive as a String. 735: */ 736: void primitiveInstantiation(String primitiveName, String valueAsString) 737: { 738: transition(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION); 739: 740: current.primitiveInstantiation(primitiveName, valueAsString); 741: } 742: 743: /** Event method that denotes the instantiation of an object array. 744: * 745: * <p>More details about this method can be found in this 746: * class' introduction.</p> 747: * 748: * @param arrayClassName The array's class name. 749: * @param objectId An ObjectId instance which can be activated later. 750: * @param lengthAsString The array's length as String. 751: */ 752: void objectArrayInstantiation(String arrayClassName, String lengthAsString, 753: ObjectId objectId) 754: { 755: transition(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION); 756: 757: current.objectArrayInstantiation(arrayClassName, lengthAsString, objectId); 758: } 759: 760: /** Event method that denotes the instantiation of a primitive array. 761: * 762: * <p>More details about this method can be found in this 763: * class' introduction.</p> 764: * 765: * @param arrayClassName The array's class name. 766: * @param objectId An ObjectId instance which can be activated later. 767: * @param lengthAsString The array's length as String. 768: */ 769: void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, 770: ObjectId objectId) 771: { 772: transition(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION); 773: 774: current.objectArrayInstantiation(arrayClassName, lengthAsString, objectId); 775: } 776: 777: /** Event method that denotes the setting of a value in an array. 778: * 779: * <p>More details about this method can be found in this 780: * class' introduction.</p> 781: * 782: * @param indexAsString The index to as a String. 783: */ 784: void arraySet(String indexAsString) 785: { 786: transition(ScannerState.TRANSITION_ARRAY_SET); 787: 788: current.arraySet(indexAsString); 789: } 790: 791: /** Event method that denotes the retrieval of a value in an array. 792: * 793: * <p>More details about this method can be found in this 794: * class' introduction.</p> 795: * 796: * @param indexAsString The index to as a String. 797: */ 798: void arrayGet(String indexAsString) 799: { 800: transition(ScannerState.TRANSITION_ARRAY_GET); 801: 802: current.arrayGet(indexAsString); 803: } 804: 805: /** Event method that denotes the setting of a value in a list. 806: * 807: * <p>More details about this method can be found in this 808: * class' introduction.</p> 809: */ 810: void listSet() 811: { 812: transition(ScannerState.TRANSITION_LIST_SET); 813: 814: current.listSet(); 815: } 816: 817: /** Event method that denotes the retrieval of a value in a list. 818: * 819: * <p>More details about this method can be found in this 820: * class' introduction.</p> 821: */ 822: void listGet() 823: { 824: transition(ScannerState.TRANSITION_LIST_GET); 825: 826: current.listGet(); 827: } 828: 829: /** Event method that denotes the null value. 830: */ 831: void nullObject() 832: { 833: transition(ScannerState.TRANSITION_NULL_OBJECT); 834: 835: current.nullObject(); 836: } 837: 838: /** Event method that denotes a string. 839: * 840: * @param string The string that should be written. 841: */ 842: void stringReference(String string) 843: { 844: transition(ScannerState.TRANSITION_STRING_REFERENCE); 845: 846: current.stringReference(string); 847: } 848: 849: /** Event method that denotes a reference to an existing object. 850: * 851: * @param id The ObjectId to be used. 852: */ 853: void objectReference(ObjectId id) 854: { 855: transition(ScannerState.TRANSITION_OBJECT_REFERENCE); 856: 857: current.objectReference(id); 858: } 859: 860: }