| /* ScanEngine.java |
| -- Scans the input and generates an object tree that can be written as XML. |
| Copyright (C) 2005 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package gnu.java.beans.encoder; |
| |
| import java.beans.Expression; |
| import java.beans.Statement; |
| import java.io.OutputStream; |
| import java.lang.reflect.Array; |
| import java.util.HashMap; |
| import java.util.IdentityHashMap; |
| import java.util.List; |
| import java.util.Stack; |
| |
| /** <p>The <code>ScanEngine</code> is the main class of the backend of the |
| * XML persistence algorithm. It scans {@link java.beans.Expression} and |
| * {@link java.beans.Statement} instances and some raw objects via the |
| * {@link #writeObject} method and feeds it to a state machine. The |
| * state machine then constructs and object tree which is finally |
| * written as XML by a {@link Writer} implementation.</p> |
| * |
| * <p>How does it work?</p> |
| * <p>The <code>ScanEngine</code> sits below the {@link java.beans.XMLEncoder} |
| * class and is called by it exclusively. The <code>XMLEncoder</code> sends |
| * interpretive data by invoking {@link #writeExpression}, {@link #writeStatement} |
| * and {@link #writeObject}. The invocations of <code>writeExpression</code> and |
| * <code>writeStatement</code> are usually nested into each other and provide |
| * more information then necessary to generate the XML representation. |
| * Furthermore the meaning of certain <code>Expressions</code> differs |
| * depending on the enclosing elements or the inner elements have to be |
| * simply discarded.</p> |
| * |
| * <p>To cope with this state dependant nature the <code>ScanEngine</code> |
| * contains a state machine which is programmed statically (no adjustments are |
| * needed, all <code>ScanEngine</code> engines use the same setup). The |
| * <code>ScanEngine</code>'s job is to decode the <code>Expression</code>s, |
| * <code>Statement</code>s and certain objects (namely <code>String</code>, |
| * <code>null</code> objects and instances which are repeatedly provided to |
| * the encoder) into 13 low-level (event) methods, which denote the meaning of the |
| * argument. For example an <code>Expression</code> can be an array |
| * instantiation which provokes a call to {@link arrayInstantiation} or |
| * it can be a class resolution leading to a call to {@link #classResolution}. |
| * For the state machione the 13 methods are the distinct way to transit |
| * from one state to another. Whenever the <code>ScanEngine</code> calls |
| * one of the event methods the current's state successor for that event |
| * is fetched from the state machine configuration, the successpr becomes |
| * the current state and then the event method is called in the new current |
| * state. The last step allows the state instance to do something meaningful |
| * to the object tree.</p> |
| * |
| * <p>The state machine knows the concept of returning to the previous |
| * state. This is done using a stack of states which is popped every |
| * time a call to <code>writeStatement</code>, <code>writeExpression</code> |
| * in the <code>XMLEncoder</code> ends by calling the {@link #end} method. |
| * Note that due to the inheritance relationship of <code>Encoder</code> |
| * and <code>XMLEncoder</code> it is impossible for the |
| * <code>ScanEngine</code> itself to decide when an expression or statement |
| * ended. This can only be done in case of {@link #writeObject} calls because |
| * they are not nested.</p> |
| * |
| * <p>When the XML persistence mechanism reaches an object twice (and more) |
| * it should generate an XML element using the "idref" attribute and add |
| * an "id" attribute to its first instantiation. This complicates things a bit |
| * because the first instantiation will always be part of the object tree |
| * as some {@link gnu.java.beans.encoder.elements.Element} subclass instance when the |
| * second and further objects accesses are written. Therefore the {@link ObjectId} |
| * class was introduced which is shared between all the object tree elements |
| * and has the notion of an "unused" state meaning that no identification |
| * is needed. The relationship between an object and its <code>ObjectId</code> |
| * instance is stored in the <code>ScanEngine</code> and gets cleared whenever |
| * the {@link #flush} method is called. This method also writes the currently |
| * built object tree and generates the XML representation.</p> |
| * |
| * @author Robert Schuster (robertschuster@fsfe.org) |
| */ |
| public class ScanEngine |
| { |
| |
| /** Change this to true to let the ScanEngine print state transition |
| * information. |
| */ |
| boolean DEBUG = false; |
| |
| /** |
| * Stores the scanner engine states as values and their names as keys. |
| */ |
| HashMap states = new HashMap(); |
| |
| /** |
| * Stores former scanner state and makes it possible to come back to them. |
| */ |
| Stack parents = new Stack(); |
| |
| /** |
| * The currently active scanner state. |
| */ |
| ScannerState current; |
| |
| /** |
| * The root of an object tree that is later written to XML. |
| */ |
| Root root; |
| |
| /** |
| * The Writer used to generate the XML output. |
| */ |
| Writer writer; |
| |
| /** Stores the relationship between objects and their {@link ObjectId} instance. |
| */ |
| IdentityHashMap objects = new IdentityHashMap(); |
| |
| public ScanEngine(OutputStream os) |
| { |
| // TODO: Provide another Writer implementation (e.g. one that does not use |
| // the XML APIs at all). |
| writer = new StAXWriter(os); |
| root = new Root(); |
| |
| final ScannerState start = current = new GenericScannerState(root);; |
| ScannerState conf; |
| |
| // Use the ReportingScannerState to debug serialization issues. |
| register(ScannerState.DEFAULT_STATE_NAME, new IgnoringScannerState()); |
| |
| register("start", start); |
| |
| // Special dead-end state where all transitions are ignored. |
| register("ignoreAll", new IgnoringScannerState()) |
| .setDefaultSuccessor("ignoreAll"); |
| |
| // Object reference, string reference, null object |
| start.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "simple"); |
| start.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "simple"); |
| start.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "simple"); |
| register("simple", new GenericScannerState(root)) |
| .setDefaultSuccessor("ignoreAll"); |
| |
| // Class resolution. |
| start.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "classRes0"); |
| register("classRes0", |
| new GenericScannerState(root)).setDefaultSuccessor("ignoreAll"); |
| |
| // Object instantiation. |
| start.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, |
| "newObj0"); |
| conf = register("newObj0", new GenericScannerState(root)); |
| conf.setDefaultSuccessor("ignoreAll"); |
| |
| // Simply use the start state to encode method invocations inside of |
| // objects. |
| conf.putSuccessor(ScannerState.TRANSITION_METHOD_INVOCATION, "start"); |
| |
| // Primitive instantiations. |
| start.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, |
| "newPrimitive0"); |
| register("newPrimitive0", |
| new GenericScannerState(root)).setDefaultSuccessor("ignoreAll"); |
| |
| // Object arrays use the ARRAY_GET transition to create setting the |
| // array values. |
| start.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION, |
| "newObjectArray"); |
| conf = register("newObjectArray", new GenericScannerState(root)); |
| conf.putSuccessor(ScannerState.TRANSITION_ARRAY_GET, "newOArrayGet"); |
| conf.putSuccessor(ScannerState.TRANSITION_ARRAY_SET, "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, |
| "ignoreAll"); |
| |
| // Get here when a value is set in the array. |
| register("newOArrayGet", |
| conf = new GenericScannerState(root)); |
| |
| conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, |
| "newOArrayGet_ignoreFirstInteger"); |
| |
| // "newArrayGet_ignoreFirstInteger" is set up mostly identical like the "start" |
| // state. Otherwise things would not behave the same when done inside |
| // arrays. |
| conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "simple"); |
| conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "simple"); |
| conf.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "simple"); |
| conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "classRes0"); |
| conf.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, "newObj0"); |
| conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION, |
| "newPrimitiveArray"); |
| conf.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION, |
| "newObjectArray"); |
| |
| conf = register("newOArrayGet_ignoreFirstInteger", |
| new GenericScannerState(root, 1)); |
| |
| // In non-int primitive arrays class resolutions can happen |
| // but they should be ignored. |
| conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); |
| |
| // Spurious object and string references occur when setting array |
| // elements. This suppresses them. |
| conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, |
| "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll"); |
| |
| conf.setDefaultSuccessor("start"); |
| |
| // Primitive arrays use the ARRAY_SET transition to create setting the |
| // array values. This turned out to be the only working solution. |
| // When primitive arrays were handled by ARRAY_GET the values in boolean |
| // arrays were always skipped. |
| start.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION, |
| "newPrimitiveArray"); |
| conf = register("newPrimitiveArray", new GenericScannerState(root)); |
| conf.putSuccessor(ScannerState.TRANSITION_ARRAY_GET, "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_ARRAY_SET, "newPArraySet"); |
| conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, |
| "ignoreAll"); |
| |
| conf = register("newPArraySet", new GenericScannerState(root)); |
| conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, |
| "newPArraySet_ignoreFirstInteger"); |
| |
| // Primitive arrays ignore all kinds of non-primitive object information. |
| conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, |
| "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ingoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION, |
| "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION, |
| "ignoreAll"); |
| |
| conf = register("newPArraySet_ignoreFirstInteger", |
| new GenericScannerState(root, 1)); |
| |
| // In non-int primitive arrays class resolutions can happen |
| // but they should be ignored. |
| conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); |
| |
| // Spurious object and string references occur when setting array |
| // elements. This suppresses them. |
| conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, |
| "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "ignoreAll"); |
| conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll"); |
| conf.setDefaultSuccessor("start"); |
| |
| } |
| |
| /** Registers a <code>ScannerState</code> under a certain name. |
| * |
| * @param name Name of the state |
| * @param state The <code>ScannerState</code> instance. |
| * @return The second argument. |
| */ |
| private ScannerState register(String name, ScannerState state) |
| { |
| state.init(name); |
| |
| states.put(name, state); |
| |
| return state; |
| } |
| |
| /** Generates or returns an id for the given object which can be activated |
| * later if the object is suitable. |
| * |
| * <p>Objects are unsuitable if they are an instance of a primitive wrapper |
| * or String.</p> |
| * |
| * @param value The object to retrieve an id for. |
| * @return The id for the object or <code>null</code>. |
| */ |
| private ObjectId retrieveId(Object value) |
| { |
| Class valueClass = value.getClass(); |
| ObjectId id = null; |
| |
| // Although multiple accesses to Class objects are not handled |
| // through ids we generate one for them, too. This allows us to detect |
| // second time references to such objects in the writeObject method |
| // and handle them in a special way. |
| if (valueClass != String.class |
| && valueClass.getSuperclass() != Number.class |
| && valueClass != Boolean.class) |
| { |
| if ((id = (ObjectId) objects.get(value)) == null) |
| { |
| id = new ObjectId(valueClass); |
| objects.put(value, id); |
| } |
| } |
| |
| return id; |
| } |
| |
| /** Scans the argument and calls one of event methods. See |
| * the introduction of this class for details. |
| * |
| * @param expr The expression to serialize. |
| */ |
| public void writeExpression(Expression expr) |
| { |
| String methodName = expr.getMethodName(); |
| Object[] args = expr.getArguments(); |
| Object target = expr.getTarget(); |
| Object value = null; |
| |
| try |
| { |
| value = expr.getValue(); |
| } |
| catch (Exception e) |
| { |
| throw (InternalError) |
| new InternalError( |
| "The Expression's value should be available at this point.") |
| .initCause(e); |
| } |
| |
| // TODO: What if the value is null? |
| ObjectId id; |
| Class valueClass = value.getClass(); |
| |
| if (target == Array.class) |
| { |
| if (methodName.equals("newInstance")) |
| { |
| id = retrieveId(value); |
| |
| Class ct = (Class) args[0]; |
| |
| if (ct.isPrimitive() || ct == Boolean.class || ct == Byte.class |
| || ct == Short.class || ct == Integer.class || ct == Long.class |
| || ct == Float.class || ct == Double.class) |
| primitiveArrayInstantiation(ct.getName(), |
| args[1].toString(), |
| id); |
| else |
| objectArrayInstantiation(ct.getName(), |
| args[1].toString(), |
| id); |
| |
| return; |
| } |
| else if (methodName.equals("get")) |
| { |
| arrayGet(args[1].toString()); |
| |
| // The encoder does not call the ScanEngine |
| // when an object is serialized that we already know. |
| // We test for this situation and insert the object reference |
| // manually. |
| // Since there is already a workaround for the Class class |
| // in writeObject we have to except it from this behavior. |
| id = (ObjectId) objects.get(value); |
| if (id != null && valueClass != Class.class) |
| { |
| objectReference(id); |
| end(); |
| } |
| |
| return; |
| } |
| else if (methodName.equals("set")) |
| { |
| arraySet(args[1].toString()); |
| return; |
| } |
| } |
| |
| id = retrieveId(value); |
| |
| if (target instanceof Class) |
| { |
| if (methodName.equals("new")) |
| { |
| Class targetClass = (Class) target; |
| |
| // All primitive types have short-hand forms for their |
| // constructors. |
| if (valueClass == Boolean.class) |
| primitiveInstantiation("boolean", args[0].toString()); |
| else if (valueClass == Byte.class) |
| primitiveInstantiation("byte", args[0].toString()); |
| else if (valueClass == Short.class) |
| primitiveInstantiation("short", args[0].toString()); |
| else if (valueClass == Integer.class) |
| primitiveInstantiation("int", args[0].toString()); |
| else if (valueClass == Long.class) |
| primitiveInstantiation("long", args[0].toString()); |
| else if (valueClass == Float.class) |
| primitiveInstantiation("float", args[0].toString()); |
| else if (valueClass == Double.class) |
| primitiveInstantiation("double", args[0].toString()); |
| else |
| objectInstantiation(targetClass.getName(), id); |
| |
| return; |
| } |
| else if (value instanceof Class) |
| { |
| String className = ((Class) value).getName(); |
| |
| // At this point we know that some *static* method will be called. |
| |
| if (methodName.equals("forName")) |
| { |
| // However "Class.forName" represents class resolution and has a |
| // special syntax. |
| classResolution(className); |
| return; |
| } |
| else if (methodName.equals("getField")) |
| { |
| // The same goes for "Class.getField". |
| // Note: The name of the wanted field is given in |
| // the argument array. |
| staticFieldAccess(className, args[0].toString()); |
| return; |
| } |
| else |
| { |
| // If nothing fits it is just a static method |
| // invocation which we decode as such. |
| staticMethodInvocation(className, methodName); |
| return; |
| } |
| } |
| } |
| else if (target instanceof List) |
| { |
| // Special behavior for indexed get and set method for list-style |
| // classes. |
| // The arguments are in the args array but we need them as subelements. |
| if (methodName.equals("get")) |
| { |
| listGet(); |
| return; |
| } |
| else if (methodName.equals("set")) |
| { |
| listSet(); |
| return; |
| } |
| } |
| |
| // If nothing else could be used then this is a normal |
| // method invocation. |
| methodInvocation(methodName); |
| } |
| |
| /** |
| * Ends the current state and returns to the last one. |
| */ |
| public void end() |
| { |
| current.end(); |
| |
| if (DEBUG) System.err.print("back from " + current.getName()); |
| |
| ScannerState oldCurrent = current; |
| current = (ScannerState) parents.pop(); |
| |
| if (DEBUG) System.err.println(" to " + current.getName()); |
| } |
| |
| /** |
| * Returns to the last state and deletes the last element in the object tree. |
| */ |
| public void revoke() |
| { |
| ScannerState oldCurrent = current; |
| current = (ScannerState) parents.pop(); |
| |
| root.deleteLast(); |
| } |
| |
| /** Scans the argument and calls one of event methods. See |
| * the introduction of this class for details. |
| * |
| * @param stmt The statement to serialize. |
| */ |
| public void writeStatement(Statement stmt) |
| { |
| // This is a simplified version of writeExpression. Everything |
| // that would not create something that is embedded in a <void> tag |
| // is left out (instantiation, getters, ...). |
| // TODO: Is this the right thing to do? |
| |
| String methodName = stmt.getMethodName(); |
| Object target = stmt.getTarget(); |
| Object[] args = stmt.getArguments(); |
| |
| if (target == Array.class && methodName.equals("set")) |
| { |
| arraySet(args[1].toString()); |
| return; |
| } |
| |
| if (target instanceof List) |
| { |
| if (methodName.equals("set")) |
| { |
| listSet(); |
| return; |
| } |
| } |
| |
| // If nothing else could be used then this is a normal |
| // method invocation. |
| methodInvocation(methodName); |
| } |
| |
| /** Scans the argument and calls one of event methods. See |
| * the introduction of this class for details. |
| * |
| * @param o The object to serialize. |
| */ |
| public boolean writeObject(Object o) |
| { |
| ObjectId id = null; |
| |
| if (o == null) |
| { |
| // Handle null objects which have a special syntax. |
| nullObject(); |
| end(); |
| } |
| else if (o.getClass() == String.class) |
| { |
| // Handle strings which are treated extremely special |
| // in the encoder (they are never converted into a |
| // Expression). |
| stringReference((String) o); |
| end(); |
| } |
| else if ((id = (ObjectId) objects.get(o)) != null) |
| { |
| // Multiple references to a Class object do not generate |
| // an object reference but we use the id to detect that |
| // situation. |
| if (o.getClass() == Class.class) |
| { |
| classResolution(((Class) o).getName()); |
| end(); |
| return false; |
| } |
| |
| // If our object has a corresponding ObjectId instance |
| // then generate an objectReference. This will |
| // initialize the id (= brings it in the "used" state) |
| // when this is the first referal. |
| objectReference(id); |
| end(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Writes the currently constructed object tree out as |
| * XML and clears the object to {@link ObjectId} relations. |
| */ |
| public void flush() |
| { |
| // Make all references unreachable. That means we have to generate |
| // new object ids. |
| objects.clear(); |
| |
| root.traverse(writer); |
| } |
| |
| /** Writes the final bits if the object tree and closes the stream |
| * afterwards. |
| */ |
| public void close() |
| { |
| flush(); |
| root.close(writer); |
| } |
| |
| /** |
| * Does a transition from one state to another using the given event. |
| * |
| * <p>This involves saving the current state, retrieving it's |
| * successor and setting it as the current state.</p> |
| * |
| * @param transition One of {@link ScannerStates]'s transition constants. |
| */ |
| private void transition(int transition) |
| { |
| parents.push(current); |
| |
| String stateName = current.getSuccessor(transition); |
| |
| if (DEBUG) |
| { |
| System.err.println("from state: " + current.getName() + "\n\troute: " |
| + ScannerState.transitionNames[transition] |
| + "\n\t\tto state: " |
| + stateName); |
| } |
| |
| ScannerState newState = (ScannerState) states.get(stateName); |
| |
| newState.enter(new Context(current.getName(), current.getCalls())); |
| |
| assert (newState != null) : "State '" + stateName + "' was not defined."; |
| |
| current = newState; |
| } |
| |
| /** Event method that denotes a (non-static) method invocation. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| * |
| * @param methodName The name of the method which is called. |
| */ |
| void methodInvocation(String methodName) |
| { |
| transition(ScannerState.TRANSITION_METHOD_INVOCATION); |
| |
| current.methodInvocation(methodName); |
| } |
| |
| /** Event method that denotes a static method invocation. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| * |
| * @param methodName The name of the method which is called. |
| * @param className The name of the class in which the method is called. |
| */ |
| void staticMethodInvocation(String className, String methodName) |
| { |
| transition(ScannerState.TRANSITION_STATIC_METHOD_INVOCATION); |
| |
| current.staticMethodInvocation(className, methodName); |
| } |
| |
| /** Event method that denotes the retrieval of a static field's value. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| * |
| * @param fieldName The name of the field whose value is retrieved. |
| * @param className The name of the class in which the method is called. |
| */ |
| void staticFieldAccess(String className, String fieldName) |
| { |
| transition(ScannerState.TRANSITION_STATIC_FIELD_ACCESS); |
| |
| current.staticFieldAccess(className, fieldName); |
| } |
| |
| /** Event method that denotes the resolution of a class. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| * |
| * @param className The name of the class in which the method is called. |
| */ |
| void classResolution(String className) |
| { |
| transition(ScannerState.TRANSITION_CLASS_RESOLUTION); |
| |
| current.classResolution(className); |
| } |
| |
| /** Event method that denotes the instantiation of an object. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| * |
| * @param className The name of the class in which the method is called. |
| * @param objectId An ObjectId instance which can be activated later. |
| */ |
| void objectInstantiation(String className, ObjectId objectId) |
| { |
| transition(ScannerState.TRANSITION_OBJECT_INSTANTIATION); |
| |
| current.objectInstantiation(className, objectId); |
| } |
| |
| /** Event method that denotes the instantiation of a primitive. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| * |
| * @param primitiveName One of "boolean, "byte", "short", "int", "long" |
| * , "float" or "double" |
| * @param valueAsString The value of the primitive as a String. |
| */ |
| void primitiveInstantiation(String primitiveName, String valueAsString) |
| { |
| transition(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION); |
| |
| current.primitiveInstantiation(primitiveName, valueAsString); |
| } |
| |
| /** Event method that denotes the instantiation of an object array. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| * |
| * @param arrayClassName The array's class name. |
| * @param objectId An ObjectId instance which can be activated later. |
| * @param lengthAsString The array's length as String. |
| */ |
| void objectArrayInstantiation(String arrayClassName, String lengthAsString, |
| ObjectId objectId) |
| { |
| transition(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION); |
| |
| current.objectArrayInstantiation(arrayClassName, lengthAsString, objectId); |
| } |
| |
| /** Event method that denotes the instantiation of a primitive array. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| * |
| * @param arrayClassName The array's class name. |
| * @param objectId An ObjectId instance which can be activated later. |
| * @param lengthAsString The array's length as String. |
| */ |
| void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, |
| ObjectId objectId) |
| { |
| transition(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION); |
| |
| current.objectArrayInstantiation(arrayClassName, lengthAsString, objectId); |
| } |
| |
| /** Event method that denotes the setting of a value in an array. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| * |
| * @param indexAsString The index to as a String. |
| */ |
| void arraySet(String indexAsString) |
| { |
| transition(ScannerState.TRANSITION_ARRAY_SET); |
| |
| current.arraySet(indexAsString); |
| } |
| |
| /** Event method that denotes the retrieval of a value in an array. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| * |
| * @param indexAsString The index to as a String. |
| */ |
| void arrayGet(String indexAsString) |
| { |
| transition(ScannerState.TRANSITION_ARRAY_GET); |
| |
| current.arrayGet(indexAsString); |
| } |
| |
| /** Event method that denotes the setting of a value in a list. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| */ |
| void listSet() |
| { |
| transition(ScannerState.TRANSITION_LIST_SET); |
| |
| current.listSet(); |
| } |
| |
| /** Event method that denotes the retrieval of a value in a list. |
| * |
| * <p>More details about this method can be found in this |
| * class' introduction.</p> |
| */ |
| void listGet() |
| { |
| transition(ScannerState.TRANSITION_LIST_GET); |
| |
| current.listGet(); |
| } |
| |
| /** Event method that denotes the null value. |
| */ |
| void nullObject() |
| { |
| transition(ScannerState.TRANSITION_NULL_OBJECT); |
| |
| current.nullObject(); |
| } |
| |
| /** Event method that denotes a string. |
| * |
| * @param string The string that should be written. |
| */ |
| void stringReference(String string) |
| { |
| transition(ScannerState.TRANSITION_STRING_REFERENCE); |
| |
| current.stringReference(string); |
| } |
| |
| /** Event method that denotes a reference to an existing object. |
| * |
| * @param id The ObjectId to be used. |
| */ |
| void objectReference(ObjectId id) |
| { |
| transition(ScannerState.TRANSITION_OBJECT_REFERENCE); |
| |
| current.objectReference(id); |
| } |
| |
| } |