org.ovmj.util
Class Runabout

java.lang.Object
  extended byorg.ovmj.util.Runabout

public class Runabout
extends java.lang.Object

Runabout is a fast implementation of the Walkabout which is a variant of the Visitor Pattern that does not require an accept method and uses reflection instead.

An instance of Runabout is able to walk over an arbitrary object graph using visit methods which take arguments of the specific type of the object to visit. For each node in the object graph the Runabout invokes the most appropriate visit method.

Using the Runabout typically involves subclassimg Runabout and adding a couple of visit methods. The Runabout provides a 'visitAppropriate' method which will invoke the most appropriate visit method of the current Runabout instance. If no visit method is applicable, visitAppropriate calls visitDefault() which, if not overriden, throws an exception.

The elements of the object graph typically extend the Element class, which provides a generic way to quickly invoke the Runabout on all the fields of the Element.

Note that the Runabout uses dynamic code generation and dynamic loading in order to be quickly able to invoke the appropriate visit methods. To make the dynamic code generation fast, the code inlines parts of Java class-files in binary form (ugly!).
A per-thread Cache is used to speed-up the creation of the Runabout by caching reflection, code creation and dynamic loading operations.

Restrictions: Java semantics require:

Otherwise the visitor will die with an IllegalAccessError during execution.

Author:
Christian Grothoff

Nested Class Summary
static class Runabout.Code
          Code is the generic interface that all generated classes implement.
static class Runabout.RunaboutException
          Generic Exception for problems in the Runabout.
 
Field Summary
protected  Runabout.Code noCode
          Code to invoke if no visitor is found (used to avoid scanning the hierarchy again and again).
static java.lang.String VISIT
          Name of the visit methods.
 
Constructor Summary
Runabout()
          Create a Runabout.
 
Method Summary
 void addExternalVisit(java.lang.Class cl, Runabout.Code co)
          Add a Code of a visit method to visit for a certain type which is not defined in the visitor itself.
protected  Runabout.Code getAppropriateCode(java.lang.Class c)
          Find the appropriate Code to call in the map.
protected  Runabout.Code getCodeForClass(java.lang.Class c)
          Helper method to allow subclasses to override getAppropriateCode with their own lookup mechanims.
 void visit(boolean b)
          Visit method that is called from visitAppropriate(Boolean b, Boolean.TYPE) with b.booleanValue() as the argument.
 void visit(byte b)
          Visit method that is called from visitAppropriate(Byte b, Byte.TYPE) with b.byteValue() as the argument.
 void visit(char c)
          Visit method that is called from visitAppropriate(Character c, Character.TYPE) with c.charValue() as the argument.
 void visit(double d)
          Visit method that is called from visitAppropriate(Double d, Double.TYPE) with d.doubleValue() as the argument.
 void visit(float f)
          Visit method that is called from visitAppropriate(Float f, Float.TYPE) with f.floatValue() as the argument.
 void visit(int i)
          Visit method that is called from visitAppropriate(Integer i, Integer.TYPE) with i.intValue() as the argument.
 void visit(long l)
          Visit method that is called from visitAppropriate(Long l, Long.TYPE) with l.longValue() as the argument.
 void visit(short s)
          Visit method that is called from visitAppropriate(Short s, Short.TYPE) with s.shortValue() as the argument.
 void visitAppropriate(java.lang.Object o)
          Call the appropriate visit method.
 void visitAppropriate(java.lang.Object o, java.lang.Class c)
          Call the appropriate visit method.
protected  void visitDefault(java.lang.Object o)
          Override this method to provide a default behavior when no other visit matches.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

VISIT

public static final java.lang.String VISIT
Name of the visit methods. Do not change.

See Also:
Constant Field Values

noCode

protected final Runabout.Code noCode
Code to invoke if no visitor is found (used to avoid scanning the hierarchy again and again).

Constructor Detail

Runabout

public Runabout()
Create a Runabout.

Method Detail

addExternalVisit

public final void addExternalVisit(java.lang.Class cl,
                                   Runabout.Code co)
Add a Code of a visit method to visit for a certain type which is not defined in the visitor itself. Note that this extention is not added to the cache for all instances but kept private to this class.

This method should only be invoked before the Runabout is used (for example in the constructor) since afterwards subtypes of cl may already be mapped to more general handlers. This method will not check this!

Parameters:
cl - the type for which to invoke this visit method
co - the code to invoke

visitAppropriate

public final void visitAppropriate(java.lang.Object o)
Call the appropriate visit method. Use this method if you are visiting a graph of objects (no primitives).

Parameters:
o - the object to visit

visitAppropriate

public void visitAppropriate(java.lang.Object o,
                             java.lang.Class c)
Call the appropriate visit method. Use this methd if the traversal may hit primitives. This is typcially the case if you walk over some graph using reflection.

Parameters:
o - the object to visit
c - the type of the object, should be equal to o.getClass() unless o is primitive (then it should describe the primitive type)

visit

public void visit(int i)
Visit method that is called from visitAppropriate(Integer i, Integer.TYPE) with i.intValue() as the argument. Override if you need to visit primitive integers.


visit

public void visit(float f)
Visit method that is called from visitAppropriate(Float f, Float.TYPE) with f.floatValue() as the argument. Override if you need to visit primitive floats.


visit

public void visit(double d)
Visit method that is called from visitAppropriate(Double d, Double.TYPE) with d.doubleValue() as the argument. Override if you need to visit primitive doubles.


visit

public void visit(long l)
Visit method that is called from visitAppropriate(Long l, Long.TYPE) with l.longValue() as the argument. Override if you need to visit primitive longs.


visit

public void visit(byte b)
Visit method that is called from visitAppropriate(Byte b, Byte.TYPE) with b.byteValue() as the argument. Override if you need to visit primitive bytes.


visit

public void visit(char c)
Visit method that is called from visitAppropriate(Character c, Character.TYPE) with c.charValue() as the argument. Override if you need to visit primitive characters.


visit

public void visit(boolean b)
Visit method that is called from visitAppropriate(Boolean b, Boolean.TYPE) with b.booleanValue() as the argument. Override if you need to visit primitive booleans.


visit

public void visit(short s)
Visit method that is called from visitAppropriate(Short s, Short.TYPE) with s.shortValue() as the argument. Override if you need to visit primitive shorts.


getAppropriateCode

protected Runabout.Code getAppropriateCode(java.lang.Class c)
Find the appropriate Code to call in the map. If no code is found, return null. This lookup strategy first attempts to find a visit method defined for the parent classes of c. If no such method exists, it attempts to find an unambiguous visit method matching any interface transitively implemented by c. If that does not exist either, null is returned. If only an ambiguous visit method exists, an exception is raised.

Parameters:
c - the class for which to find the code
Returns:
the code to run, or null if no code was found
Throws:
Runabout.RunaboutException - if the lookup would be ambiguous

getCodeForClass

protected final Runabout.Code getCodeForClass(java.lang.Class c)
Helper method to allow subclasses to override getAppropriateCode with their own lookup mechanims. getAppropriateCode must return the appropriate Code object for the resolved method. This helper method can be used to obtain the generated Code objects for the visit methods of the Runabout. If the class does not have a visit method for the specified class, the result of a previous run to getAppropriateCode for that class will be returned if getAppropriateCode was called for this class before. If there is no visit method for c and getAppropriateCode was never called for c, null is returned.

Parameters:
c - a class
Returns:
the Code to invoke visit(c) of the given class

visitDefault

protected void visitDefault(java.lang.Object o)
Override this method to provide a default behavior when no other visit matches. The Runabout semantics are to search for a visit(X) and if there is no match, call visitDefault(). As usual with the Runabout, visit(X) looks at classes before interfaces. By default, visitDefault throws an exception.