Java [3,23] is a simple yet powerful object-oriented language. Java classes are compiled into high-level object-oriented cross-platform bytecodes, that can be executed on Java Virtual Machines (JVM). Since the specification of the JVM [27] is open, anyone can implement it, so Java has become available on several different hardware platforms; freely-modifiable and redistributable source code for some of these implementations is available at no cost. The reflective architecture of Guaranį was implemented on top of one of these platforms, namely the Kaffe OpenVM.
In Guaranį, every Java object may be directly associated with zero or one meta-object, called the object's primary meta-object. An object that is associated with a meta-object will be called a reflective object. Every operation addressed to a reflective object is intercepted, reified (represented) as a meta-level object, and presented to the object's primary meta-object.
By operation, we mean methods and constructors invocations, monitor (synchronized) enter and exit operations, field reads and writes. Since Java arrays are objects too, array elements reads and writes, as well as array length reads, are considered operations too.
When a meta-object is presented an operation, it may reply with (i) a result for the operation, (ii) an alternate operation, to be performed instead of the one requested by the base-level, or (iii) a request for the original operation to be performed. Unless it provides a result itself, it may request to be presented the result of the operation after it is performed, or even to be able to modify this result.
Meta-objects, instances of subclasses of the class MetaObject, can be made reflective too, by associating them with other meta-objects, what leads to the so-called potentially infinite tower of meta-objects [29].
Class Composer, one of the standard specializations of MetaObject, is the key concept introduced by the meta-object protocol of Guaranį. A composer is a meta-object that delegates operations and results to other meta-objects. Composers may delegate to meta-objects sequentially, or concurrently, or following whatever policy fits the needs of a developer. A sample composer is provided that delegates operations to the elements of an array of meta-objects, and delegates results to the same meta-objects in the reverse order.
Some of the component meta-objects of a composer can be composers themselves, what leads to a hierarchical organization of the meta-objects directly or indirectly associated with a base-level object. This organization, called the object's meta-configuration, is orthogonal to the tower of meta-objects; each meta-object may have its own independent meta-configuration. Furthermore, a meta-object may belong to the meta-configuration of more than one object.
Associating an object with its primary meta-object is an operation provided by the kernel of Guaranį. In fact, this operation is so general that it allows any meta-object in a meta-configuration to be replaced with another. Any reconfiguration must be approved by the previous meta-configuration; if the base-level object was not reflective, its class is informed about the reconfiguration request, and may prevent it.
Objects created by reflective objects have their meta-configurations determined by their creator's meta-configuration. Furthermore, the meta-configuration of the class of the new object is notified before the object's constructor is invoked, so that it may try to modify the meta-configuration of its new instance. The kernel of Guaranį makes it possible to create pseudo-objects, that are uninitialized instances of a given class. These objects may be turned into real objects by invoking a constructor or initializing its fields, but it may remain a pseudo-object and be used, for example, as a proxy of an object in a separate address spaces. The meta-configuration of the class the pseudo-object belongs to is also notified, so it may modify the pseudo-object's meta-configuration, or even prevent the creation of the pseudo-object.
This notification is done by using another operation provided by the kernel of Guaranį: any instance of a class that implements the interface Message can be broadcast to (possibly) all component meta-objects of a meta-configuration of an object. Such an operation is necessary because, for security reasons, we made it impossible to obtain a reference to the primary meta-object of an object. Furthermore, we believe this helps maintaining a clear separation of concerns between the base and the meta level, just like encapsulation encourages good object-oriented design.
Guaranį provides an interface that allows arbitrary Operation objects to be created in the meta-level; even operations that would violate encapsulation can be created and performed by using this interface. However, for the sake of security, such operations must be created using OperationFactory objects, that are given to meta-objects whenever they are associated with an object. This ensures that only component meta-objects of an object's meta-configuration, and meta-level objects trusted by them, can obtain privileged access to this object. Composers may distribute restricted operation factories to meta-objects they delegate to.