The Reflector has two pre-defined blocks that can be used straight up without any further configuration.
Example of including the Complete block in a larger block;
<container name="myapplication" > <classloader> : </classloader> <component name="MyComponent" type="com.mycompany.myproject.MyComponent" /> <include artifact="block:metro/facilities/reflector/metro-reflector-blocks-complete#SNAPSHOT" /> </container>
Group | Name | Purpose |
---|---|---|
metro/facilities/reflector | metro-reflector-blocks-complete | The Complete block consist of everything need when you don't have the HTTP Facility available and used elsewhere in the system. It starts the HTTP Facility on port 8080 with a normal socket listener and registers the composition model as a root object in the Reflector. |
metro/facilities/reflector | metro-reflector-blocks-standard |
The Standard block is intended for use when you want it to attach
itself to an existing HTTP Facility running on any port. By default,
the Reflector will lookup 'any' HttpContext , so it is
not defined which context it will add itself to. If you need better
control, you need to use the 'manual assembly' features of Merlin.
|
If you want to have your own root objects, you look up the Reflector
and call the addRootObject( String name, Object object )
method, either directly from your component, or preferably from a
separate component that does the registration.
/** * @avalon.dependency type="org.apache.metro.facilities.reflector.ReflectorService" * key="reflector" * @avalon.dependency type="com.mycompany.myproject.MyApplication" * key="app" */ public void service( ServiceManager man ) throws ServiceException { MyApplication app = (MyApplication) man.lookup( "app" ); ReflectorService reflector = (ReflectorService) man.lookup( "reflector" ); reflector.addRootObject( app ); }
There are sometimes reasons to use the Reflector programmatically and not using it as a troubleshooting tool only. For instance, let's say that you define the entire application with events, and that you want to enable that the user can subscribe to changes via mail. You can then utilize the Reflector to provide for a fairly understandable object model, i.e. the dot-notation, and have a mail application register itself at each of the objects defined in the mail. Another example of use is a report generator, which has its fields defined with the dot-notation of the objects that are the live data in the form.
The ReflectorService
interface is fairly easy to
understand and has many convenience methods to make these sorts
of applications easier to write.
There might be reason to handle the containment of certain types
differently than the standard ObjectTypeHandler
. Reasons
for this varies, but typically it would be that there are additional
information in the class or interface that you want to view or change.
You create a TypeHandler
and implement each of the
methods.
Method signature | Description |
---|---|
boolean isDefault(); |
All implementations should return false, unless the purpose is
to provide a new default behaviour, instead of the
ObjectTypeHandler . This method is only called once
upon startup.
|
String[] getNames( Object container ) throws ReflectionException; |
This method should return an array of all the members of the class. This determines which members are available in the type the TypeHandler handles. This method is called for every object introspected by the Reflector. The names returned will be used as input in the methods below (i.e. the membername argument). |
Class getClass( Object container, String membername ) throws ReflectionException; |
Return the Class of the member. The Class returned must be the type of the reference, and not the Class of the object assigned to the reference. In case of JavaBeans get methods, the Class returned equals the return type of the get method. If the Class of the object assigned to the reference is returned, then assignment of new objects to the same reference will be required to be the same class or a subclass of the Class returned from this method. |
Object getMemberObject( Object container, String membername ) throws ReflectionException; |
Return the object with the given membername. |
void setMemberObject( Object container, String membername, Object value ) throws ReflectionException; |
Assignment of a new value to a member. For primitive types and the subclasses of Number, the value (or true/false in case of boolean) can either be the numeric object, or a string with the value in it. For Number types a Double object will be created and assigned. For all other types, you can pass a String with the fully qualified class name, and a new object of that class will be instantiated and assigned, provided that the class can be found through the classloader hierarchy and that it has a default (i.e. empty) constructor. |
boolean isSettable( Object container, String memberName ) throws ReflectionException; |
This method should return true if it is possible
to modify the member, i.e. call the setMemberObject
method.
|