next up previous
Next: Related Work Up: Pluggability Previous: Pluggable reflection's benefits


Pluggability through Components

The component generator has proven useful for enabling pluggability. So far we've showed pluggability through interface conformity. Now we show an alternative approach to pluggability using components. We demonstrate this again for javadoc by applying the object-to-component transformation and automatic generator to produce ReflectionBeans. The input to the generator is Java's Reflection API; ReflectionBeans are the output.

Using ReflectionBeans instead of the reflection interface makes retargeting much easier. Third-party tools can mix and match with third-party providers of meta-information: simply specify the desired .jar file in the tool's classpath. This retargeting requires no source code change or recompilation.

ReflectionBeans act as a facade to the actual source, be it reflection, a repository, or anything else. JavaBeans may seem like overkill here, but they have the added benefit of allowing modest visual programming capabilities.

Figure [*] depicts basic cooperation among ReflectionBeans. VclassTransmitter1 is a transmitter-bean [22]: it translates from the AWT-event world to the class-event world. Specifically, it expects a text event and responds with a corresponding class event. The class event encapsulates the class whose name was received in the class event. Internally, it calls on the reflective operation Class.forName to do the job. The button Button1 is connected to the event trigger in VclassTransmitter1.

Figure: Transmit-Receive

VclassReceiver1 is a receiver-bean: it works like VclassTransmitter1 but in the opposite direction. On receiving a class event, it fires the name of the class as a text event. Entering a class name in the top text field and pressing the button makes the class name appear in the bottom text field.

This approach is overkill for just propagating a class name, but it illustrates the architecture and its bean-based implementation. A more realistic composition would have nontrivial beans on the communication path between VclassTransmitter1 and VclassReceiver1.

Figure: Using the Superclass bean

In Figure [*], a Superclass1 is inserted between those components. Superclass1 is both a class-event receiver and a class-event transmitter. It accepts and fires class events. It does not fire exactly the same event it receives, however; it is a transceiver-bean as opposed to a conduit-bean. Its operation is straightforward. It may use reflection or any other source of meta-information to find the superclass of the incoming class and transmits that superclass as its output. Now if you type a legal class name in the top field and press the button, you would see the name of its superclass in the bottom field.

Although individual beans may be simple, they can perform complex jobs in concert. In Figure [*], pressing the button after entering a class name computes the class' dependents and displays them sequentially in the bottom text field. SuperclassLoop1 composes a Superclass bean and a self-loop. Thus for each input event this composition of beans outputs multiple events, one for each of the superclasses on the path to the Object class. InterfacesLoop1 does the same for interfaces.

Figure: Dependencies

This example generates all the classes that a given class immediately depends on. When text is entered in the upper field, TextEvents are fired to VclassTransmitter1. VclassTransmitter1 reacts by preparing itself to generate and fire a ClassEvent containing a class whose name is the string received.6 The button labeled ``Dependences" is connected to the fire() method of VclassTransmitter1. When the button is pressed, VclassTransmitter1 transmits the ClassEvent if and only if the string is a legal class name.

Once the button is pressed and VclassTransmitter1 fires the ClassEvent, it is distributed to Superclass1, Interfaces1, and Fields1. Superclass1 in turn triggers a ClassEvent with the superclass of the class. Interfaces1 triggers multiple ClassEvents, one for each interface the class implements. Fields1 triggers multiple FieldEvents, one for each public field of the class. The FieldEvents are received by Type1, which fires a ClassEvent corresponding to the field's type. All the ClassEvents are subsequently merged and sent, one by one, to VclassReceiver1. Finally, VclassReceiver1 generates a TextEvent, and the class names are displayed sequentially.

We applied this approach to javadoc to make its source of reflective information pluggable. Implementing reflectdoc using beans introduces behavioral beans (counters, resetters, etc.) into the datapath to generate HTML rather than just displaying class names. There are in fact two orthogonal datapaths: one governs how reflective information is traversed, the other governs the flow of data. Our original classification [22], which assumed a single datapath, differentiated among several types of transceivers: conduit, converter, transmuter, etc. Implementing reflectdoc requires two datapaths; hence each bean is characterized by a taxonomic tuple, e.g., transmuter, conduit. To avoid a Cartesian product of bean classifications, we require that any pair of transceivers must include a conduit.7

These extensions to our taxonomy are needed to characterize some of the beans that implement javadoc's behavior, for example, regarding event synchronization. Further details are beyond the scope of this paper. The important point is that ReflectionBeans are powerful enough to express real applications.


next up previous
Next: Related Work Up: Pluggability Previous: Pluggable reflection's benefits
David H. Lorenz 2003-02-17