Run-Time Type Identification Computational Reflection

Chapter 7 • Software Components 257 String toString; The return types Constructor, Field, and Method are defined in the package java.lang.reflect .

7.3.2 Reification

For the meta-level to be able to reflect on several objects, especially if they are instances of different classes, it must be given information regarding the internal structure of objects. This meta-level object must be able to find out what are the methods implemented by an object, as well as the fields attributes defined by this object. Such base-level representation, that is available for the meta-level, is called structural meta-information. The representation, in form of objects, of abstract language concepts, such as classes and methods, is called reification. Base-level behavior, however, cannot be completely modeled by reifying only structural aspects of objects. Interactions between objects must also be materialized as objects, so that meta-level objects can inspect and possibly alter them. This is achieved by intercepting base-level operations such as method invocations, field value inquiries or assignments, creating operation objects that represent them, and transferring control to the meta level, as shown in Figure 7-3. In addition to receiving reified base-level operations from the reflective kernel, meta-level objects should also be able to create operation objects, and this should be reflected in the base level as the execution of such operations. A reflective kernel is responsible for implementing an interception mechanism. The method invocation is reified as an operation object and passed for the callee’s meta-object to reflect upon handle. Eventually, the meta-object requests the kernel to deliver the operation to the callee’s replication object, by returning control as in the diagram or performing some special meta-level action. Finally, the result of the operation is reified and presented to the meta-object. caller kernel op : Operation res : Result handleop : MetaObject methodarg obj : Object methodarg result createobj, method, arg op result createop, result res handleres Figure 7-3. Reifying an operation. See text for explanation. Ivan Marsic • Rutgers University 258 Show example of reflection using DISCIPLE Commands in Manifold Reflection enables dynamic run-time evolution of programming systems, transforming programs statically at compile-time to add and manage such features as concurrency, distribution, persistence, or object systems, or allowing expert systems to reason about and adapt their own behavior. In a reflective application, the base level implements the main functionality of an application, while the meta level is usually reserved for the implementation of management requirements, such as persistence [28,34], location transparency [26], replication [8,18], fault tolerance [1,2,9,10] and atomic actions [35,37]. Reflection has also been shown to be useful in the development of distributed systems [6,20,36,40,41] and for simplifying library protocols [38]. http:www.dcc.unicamp.br~olivaguaranadocsdesign-htmlnode6.htmltransparency A recent small project in Squeak by Henrik Gedenryd to develop a Universal Composition system for programs. It essentially involves a graph of meta-objects describing source- composition operations which can be eagerly or lazily statically or dynamically driven, resulting in partial evaluation or forms of dynamic composition such as Aspect-Oriented Programming AOP.

7.3.3 Automatic Component Binding

Components can be seen as pieces of a jigsaw puzzle, like molecular binding—certain molecule can bind only a molecule of a corresponding type.

7.4 State Persistence for Transport

A class is defined by the Java bytecode and this is all that is necessary to create a fresh new instance of the class. As the new instance object interacts with their objects, its state changes. The variables assume certain values. If we want a new instance resume from this state rather than from the fresh initial state, we need a mechanism to extract the object state. The mechanism is known as object serialization or in the CORBA jargon it is called object externalization [OMG- CORBA-Services]. Object serialization process transforms the object graph structure into a linear sequence of bytes, essentially a byte array. The array can be stored on a physical support or sent over the network. The object that can be serialized should implement the interface java.io.Serializable. The object essentially implements the methods writeObject and readObject. These methods define how to convert the component attributes, which represented by programmer- defined data types, to a one-dimensional bytestream. When restoring the object, we need to have its class bytecode because class definition is not stored in the serialized state. If the receiving process does not know the objects class, it will throw the java.io.SerializationError exception. This may be a problem if we are Chapter 7 • Software Components 259 sending the object to a server which is running all the time and cannot load new classes, so its class loader cannot know about the newly defined class. The solution is to use the method: byte[] getBytes; which is available on every java.lang.Object object, i.e., on every Java object. The method returns a byte array—a primitive data type, which can be used by the server to reconstruct the object there. JAR file contains: • Manifest file • Classes next to the class name, there is a Boolean variable “bean” which can be true or false • Bean customizers Beans provide for a form of state migration since the bean state can be “canned” serialized and restored on a remote machine unlike an applet which always starts in an initial state after landing on a remote machine. However, this is not object migration since the execution state program counters for all threads would need to be suspended and resumed. Persistency is more meant to preserve the state that resulted from external entities interacting with the bean, rather than the state of the execution, which would be possible to resume on another machine.

7.5 A Component Framework

Here I present a component framework that I designed, which is inspired by several component frameworks existing in research laboratories. Compared to JavaBeans, this framework is more radical in enforcing the component encapsulation and uniformity of communication with it.

7.5.1 Port Interconnections

Options for component wiring are illustrated in Figure 7-4. The ports of different components can be connected directly, one-on-one. In the simplest case, output port of a component directly connects to an input port of another component. Another useful analogy is wire, which is a broadcast medium to which multiple ports can be connected. Similar effect could be achieved by the Publisher-Subscriber pattern see Section 4.1 above, but the Wire abstraction appears to be more elegant in the context of components and ports. In the spirit of object-oriented encapsulation, components as defined here share nothing—they have no shared state variables. The communication is entirely via messages. Of course, communication via ports is limited to the inter-component communication. Components contain one or more objects, which mutually communicate via regular method calls. Similarly, components make calls to the runtime environment and vice versa, via method calls. The only requirement that is enforced is that components communicate with each other via ports only.