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 }