Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: gnu/java/beans/encoder/ScanEngine.java


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 }