<<

A Framework for the Development of Multi-Level Reflective Applications

Federico Valentino, Andrés Ramos, Claudia Marcos and Jane Pryor

ISISTAN Research Institute Fac. de Ciencias Exactas, UNICEN Pje. Arroyo Seco, B7001BBO Tandil, Bs. As., Argentina Tel/Fax: +54-2293-440362/3 E-mail: {fvalenti,aramos,cmarcos,jpryor}@exa.unicen.edu.ar URL: http://www.exa.unicen.edu.ar/~isistan

Abstract. Computational reflection has become a useful technique for developing applications that are able to observe and modify their behaviour. Reflection has evolved to the point where it is being used to address a variety of application domains. This paper presents a reflective architecture that has been developed as a framework that provides a flexible reflective mechanism for the development of a wide range of applications. This architecture supports many meta-levels, where each one may contain one or more planes. A plane groups components that deal with the same functionality, and so enhances the separation of concerns in the system. The reflective mechanism permits different types of reflection, and also incorporates the runtime handling of potential conflicts between competing system components. The design and implementation of this framework are described, and an example illustrates its characteristics.

1. Introduction

Reflective architectures provide a degree of flexibility that allows designers to adapt and add functionality to systems in a transparent fashion. Since its onset, computational reflection has been proposed and used for the solving of many different problem domains in software engineering: aspect-oriented programming [PDF99, PBC00], multi-agent systems [Zun00], concurrency programming [WY88, MMY93], distributed systems [Str93, OI94, OIT92], and others. A reflective system has the ability to reason about and act upon itself and adjust to changing conditions [Mae87]. Reflection is a technique that has gained applicability with the increasing use of object-oriented languages. In an object-oriented reflective architecture a system has more than one level: a base level consisting of the application itself, and a reflective level or meta-level that observes and introduces additional functionality that is dependent on the state of the program during . A reflective architecture therefore promotes the separation of concerns [Par72] by distinguishing and organizing the software components according to their functionality.

However, the separation of concerns offered by most reflective architectures is limited to the base and meta levels. The meta or reflective level may contain with very different functionality, such as synchronization, logging, , and so on. In consequence the benefits of an adequate separation of concerns – greater comprehension, reduced complexity, adaptability, customisability, reuse, etc. - is lost. Another limitation arises when more than one is associated to the same object, as problems of ordering, exclusion, and other conflicts may arise between them. This may be solved in a static way by following the order in which they are associated, but in some cases this will not be sufficient as their activation may depend on more complex issues. It is also important to support different reflective capabilities in order to offer greater flexibility to the developer. This would permit the design of systems where the types of reflection are applied in accordance to the functional requirements. Current reflective systems do not provide the means to adequately handle these issues. This paper describes a framework for the development of reflective systems that include flexible reflective mechanisms for the separation of concerns and for the solving of conflicts between competing metaobjects. The framework supports a multi-level architecture where groups of components that share the same basic functionality are grouped together in planes that observe and interact with each other, supporting the separation of concerns down to the code level in cases of crosscutting functionality. Different types and levels of conflicts between metaobjects have been studied and identified in this work. The framework supports the declaration and the handling of the above-mentioned categories of conflicts. The following section provides a brief description of computational reflection. Section 3 describes the concept of planes in a reflective architecture, and the next section consists of a description and categorisation of conflicts. The reflective architecture is covered in section 5, followed by an example of an application. The implementation is described in section 7, and the conclusions presented in section 8.

2. Computational Reflection

Computational reflection permits a system to observe and modify the properties of its own behaviour, specially those properties that can be observed externally. Reflection is a solution to the problem of creating applications capable of maintaining, using or changing the representation of their own designs [Mae87, DS84, Coi88]. Reflective systems are therefore capable of extending, modifying or analysing their behaviour. In conventional systems, the data that is computed represents entities that are external to the computational system. On the other hand, in reflective systems, the computation is carried out on data that represents structural and computational aspects of the same system. In an object-oriented reflective architecture, the components that represent the application and those that represent the system itself reside on two different levels: the base level and the meta level (Figure 1).

· The base level contains the objects that solve a problem and return information about the domain of the application or the external domain. · The meta level contains objects that carry out computation about the system that resides on the base level. The objects on the meta level are called metaobjects.

metaobjects Meta Level

Association between base level and meta-level.

Base Level

Objects at the Communication base level between objects

Fig. 1. Reflective architecture. This two level hierarchy can be generalised to include many meta-levels, becoming an N-level architecture. In this type of architecture, each level carries out different computation on the previous level. As the functionality of the meta-level is orthogonal to the base level - i.e. it crosscuts the basic functionality of the system - an association between the base and the meta-level is defined in order to determine the points at which these levels interact with each other. This association is established between the corresponding metaobject of the meta-level and one or more elements (classes, methods and/or objects) at the base level. At runtime, when an object at the base level receives a message, the reflection mechanism redirects the control to the associated metaobject. Four different reflective strategies which make up a reflection taxonomy have been identified: class reflection, method reflection, object reflection, and method- object reflection [Mar01]: - Class reflection is that which is used when all instances of a class interact with an orthogonal functionality. - When only one method or of methods of the class needs to incorporate this functionality, method reflection is used. - In some cases it is necessary to analyse a particular object of a class, where only this object is associated to a metaobject of the meta-level: object reflection is then used. - It is also possible to combine method and object reflection when reflective behaviour is added to a particular method of a specific object. This is known as method-object reflection. Another important characteristic in a reflective system is that which permits the designer to determine when and how the meta-level is invoked: before the base

object, after the base object, and omitting the invocation of the method of the base object. The framework described in this work supports the different types of reflection specified in the taxonomy. It also permits invocation of the meta-level before and/or after the base method, with or without the invocation of the base method.

3. Planes in a Reflective Architecture

The architecture of a reflective application varies according to the reflection requirements that are to be considered. In some cases it may be convenient for the architecture to have various levels, where each level observes and interacts with the others. Additionally, as there may be multiple functions at each level, the concept of planes is introduced in order to obtain a clearer separation of concerns. A plane is a set of metaobjects which carry out a specific functionality, as for example logging or synchronisation of the system. Planes will ease the handling of these groups of metaobjects, their re-use, their interaction with the rest of the system, their maintainability, and so on. The concept of plane is not to be confused with the concept of level or hierarchy of levels. A level is a more abstract entity which may contain one or more planes which observe other planes at inferior levels; this would be the case in a hierarchical structure. blo BaseLevelObserver

dbo META LEVEL 2 so DBObserver StatisticObserver

LOGGING PLANE

dbr META LEVEL 1 DBReader

pStore stud collect ProfessorStore StudentObserver DataCollector sStore STORAGE PLANE STATISTIC PLANE StudentStore

BASE LEVEL Metaobject Nicholas Anderson Advisor Mitchel Message Student Metaobject association Professor Peter Collins Invocation John BASE PLANE

Fig. 2. Reflective Architecture with Planes

The architecture supported by the framework presented in this paper may have many levels and planes organised in a heterarchical fashion, where a plane at one level may observe planes at different levels. Thus, observation and interaction between planes is not restricted. Figure 2 shows an example of a three level architecture, where Meta Level 2 contains a plane which carries out the logging of the two inferior levels, Meta Level 1 and the Base Level. Meta Level 1 contains two planes: one that implements the functionality necessary to carry out statistic calculations, and the other which is in charge of storing data in a secondary storage medium. It is to be noted that the organisation of the levels is not strictly hierarchical as one level observes more than one inferior level. The example shows that when an object at the base level receives a message, e.g. John, there are three metaobjects - stud (Statistic), sStore (Storage) and blo (Logging) – which are associated with it. This generates a potentially conflicting situation as the associated metaobjects may be competing as to the order of execution, and a different ordering renders different results. Situations such as this one lead to the need to handle potential conflicts between metaobjects. The following section describes categories and levels of conflicts and their handling by the proposed system.

4. Conflicts between Metaobjects

An object at the base level may be associated to more than one metaobject, each of the latter having their own behavioural objective. If the task to be carried out by each metaobject is totally independent of the rest, the system will execute without any problems. However, there may be problems or conflicts if two or more of these metaobjects compete for activation. For example, a specific metaobject may have to be executed before others, or the execution of two metaobjects may produce an inconsistency and so the designer will require that only one of them be executed. In these and other cases the designer can specify the situation and the desired execution according to the type of conflict and/or the application domain, and determine the priorities and activation policy of the metaobjects. The conflicts may be classified as static or dynamic. Static conflicts can be considered as system restrictions, as they are detected when the association between the base and meta level is declared by the user. This would be the case when the same metaobject is associated twice to the same base object, or when the user wishes to declare an association between two objects of the same plane (i.e. with similar functionality). On the other hand, dynamic conflicts are detected at runtime. The designer must specify what actions must be undertaken when a given conflict arises. In the case of dynamic conflicts it is possible to describe situations that are not problematic at certain moments of execution but may be at others. For example, one may define a conflict between two metaobjects that are not yet associated to the base level (or not

associated to the same base object), and therefore do not yet present a conflictive situation but may do so in the future if they are associated to the same object. The designer must explicitly specify the conflicts it wishes the system to handle and the activation policy to follow in each case.

4.1. Categories of conflicts

The actions to be taken when a conflict is detected depend on the characteristics of the application to be developed. In some cases it will be necessary to indicate a specific order of execution of the metaobjects involved; in others, the detection of a conflict may require that one or both of the metaobjects not be executed. We have identified five different categories of activation policies to be implemented when a conflict is detected: of order, optional, exclusive, null, and context dependent. These categories constitute a taxonomy of conflicts which is described as follows: - of Order: in this type of conflicts an order of execution is established for the metaobjects involved. - Optional: in some cases it may be necessary for the system itself to decide which metaobject to execute, either according to some pre-established system of priorities or simply in a random fashion. - Exclusive: when only one particular conflicting metaobject is to be executed. - Null: for those cases in which neither of the metaobjects are to be executed. - Context Dependent: when none of the above cases satisfy the desired solution to the conflict, the designer adds code which would specify the activation of the metaobjects, and which may include an evaluation of the current context of the system.

4.2. Conflict Levels

In systems of a limited size the declaration and handling of conflicts between specific metaobjects may be sufficient. However, in more complex and large systems this may become very tedious and difficult to maintain. It is therefore important to abstract the concept of conflicts to a higher level of granularity, permitting their declaration at a level of functionality and not only between specific metaobjects. With the introduction of planes, this reflective architecture supports a more flexible handling of conflicts, easier to define and maintain. The following levels of granularity between conflicts are defined and subsequently supported by the framework: - Metaobject – metaobject: this determines a conflict between two specific metaobjects. - Metaobject - plane: it establishes a conflict between a metaobject and a plane (all the metaobjects belonging to that plane). As the structure of a plane is dynamic (the metaobjects belonging to a plane may vary), it is necessary for conflicts of this level to be verified at runtime.

- Plane - plane: this specifies a conflict between two planes, i.e. between all the metaobjects of one plane with respect to all the metaobjects of the other. As with the previous level, the conflict must be dealt with at runtime. - Metaobject - all: this permits the specification of conflicts “one to many”, where a specific metaobject has a conflict with all other metaobjects. The conflicts of this level are dealt with dynamically, as the creation or elimination of metaobjects varies the structure of the conflict.

5. Design of the Reflective Architecture of Planes

The two main components of the reflective architecture of planes are the Application and the Reflection Mechanism. The Application Mechanism contains the implementation developed by the designer: on the one hand of the functionality corresponding to the external domain (base level), and on the other hand the extended functionality that crosscuts the base level and which has the basic application as its domain (meta level). The Reflection Mechanism is the component which provides the creation and administration of associations between the different levels, together with the administration of the planes and with the handling of conflicts.

Reflection Mechanism Application

2-1, 6 Reflection (4,8) Meta Taxonomy Level 2-2, 5 1, 7 Conflict( - 2,6) Taxonomy (5,9)

3, 4 Base Plane Manager Level

Fig. 3. Reflective Architecture

Figure 3 shows the main components of the reflective architecture of planes and with handling of conflicts:

- Reflection Taxonomy: it administrates the associations between the levels (base / meta or meta / meta). It is also in charge of intercepting the messages that are sent to objects and of activating the corresponding associated metaobjects. - Conflict Taxonomy: it controls and administrates the activation of metaobjects and planes when a conflict is detected. - Plane Manager: it administrates the different planes and so offers a greater level of abstraction for the handling of components with a specific functionality. The basic of the architecture is the following (as seen in Figure 3): 1. An object of the base level receives a message which is intercepted by Reflection Taxonomy. 2. The component Reflection Taxonomy verifies if the base level object has associated metaobjects, and then makes up the list of all the metaobjects that should be activated. It then carries out two activities: 2.1. It verifies if the associated metaobjects are to be activated before, after, or before and after the base level method. 2.2. It sends the list of metaobjects to be activated to the Conflict Taxonomy component. 3. Conflict Taxonomy identifies the conflicts between those metaobjects and invokes the Plane Manager. 4. Plane Manager returns to Conflict Taxonomy the information on the planes corresponding to the metaobjects to be activated. 5. Conflict Taxonomy reorganises and returns to Reflection Taxonomy the ordered list of metaobjects, after identifying and solving the conflicts. 6. Reflection Taxonomy invokes each metaobject according to the established order. 7. Reflection Taxonomy returns the control to the base level.

6. Example

An example is described in order to illustrate the proposed architecture. This example has different types of conflicts and of of reflection, it uses various planes and is organised on three levels. Figure 2 shows the positioning of the planes and their interaction. The application consists of part of the functionality of an educational establishment. This establishment has students and a staff of professors. Statistical information on the students is to be calculated, and for this reason a sample was taken. The application has three levels, where the first level (base level) contains instances of STUDENT, PROFESSOR and ADVISOR classes. Two planes can be seen at Meta Level 1. One is in charge of storing students and professors in a data base. The second plane carries out the statistics according to the behaviour of the base level, having to interact with the data base in order to obtain certain information. The objective of Meta Level 2 is to log the activities of the inferior levels.

This example requires different types of reflection. The LOGGING plane carries out class reflection on the other planes, as it has to observe everything that occurs. The STATISTIC plane does class reflection on some of the students due to the fact that it is only interested on a sample of them. The STORING plane carries out method reflection on the respective set and get methods of the STUDENT and PROFESSOR classes. Figure 2 only shows part of the contents of the planes; not all the objects of a plane observe or are observed by others. At the base level we can see three instances of the Student class: John, Peter and Nicholas, where the first two are part of the sample used for the statistics. The figure also shows two instances of the Professor class, Collins and Anderson, and one instance of the Advisor class, Mitchell. The STATISTIC plane contains the metaobject stud (StudentObserver), which observes the students selected for the sample. The STORING plane has two metaobjects, sStore that observes students and pStore for professors. Lastly, the LOGGING plane has three metaobjects - blo, so, and dbo – where each one observes one of the planes at inferior levels. Figure 4 shows the code which carries out the reflective associations and the handling of the planes of the example architecture.

1

2

Fig. 4. Reflective associations and the handling of the planes First of all, the metaobjects and planes of the application are declared (1). The PlaneManager has been designed based on the Singleton pattern in order to permit global access to an object and to make sure there is only one instance of it. The necessary reflective associations are then declared; the example uses class, object and method reflection. The associations require the following parameters: the object to be observed, the metaobject that will observe it, and the moment in which the metaobject will be activated (2) (i.e. if the meta level is to be activated before, after, or before and after the invocation of the original base method). An evident conflictive situation is when an instance of the Student class which has been selected for the statistic sample receives a message to set or get the value of a variable. In this case, three metaobjects compete in the activation order. The metaobject stud (STATISTIC) is active because the instance is one of those selected for the sample; the metaobject sStore (STORING) is active because it carries out method

reflection on the set and get methods of the Student and Professor classes; and the metaobject blo (LOGGING) is active because it carries out class reflection on all classes of the base level. A design decision is that logging is to be carried out lastly, and that the statistical calculations are to be done after the data are stored in the data base. This is in order to work with up-to-date information. Figure 5 shows the declaration of the order conflicts which correspond to the order of activation of metaobjects which must be followed, when the above conflictive situation occurs.

1 2

Fig. 5. Conflict Declarations. In order to make sure that the conflict described is valid for all metaobjects of the LOGGING plane, a conflict is declared for the plane. As it is necessary for the LOGGING plane to execute after all other planes, a one-to-many conflict between planes is declared in inverse order (1). So that all metaobjects of the STORING plane are executed before any metaobject of the STATISTIC plane, a conflict at the plane level is declared. In this case the relation is one-to-one (2). The previous situation can also be represented by means of the following reverse order conflict: ReverseOrderConflict.between(“Statistic”,“Storing”); Lastly, figure 6 describes the sequence of execution of the metaobjects associated to the base object John (Student@a38f21) when it receives the message setAdress(); this is the order after the designer has declared the reflective associations and the above-mentioned conflicts. Section A contains the messages which confirm the creation of planes, reflective associations and conflicts between metaobjects. Section B shows the order of activation of the metaobjects when the method setAddress() of object John is invoked. In this case all the metaobjects are executed

before the base object method, because all the reflective associations used the before parameter (see Figure 4). The metaobject sStore (StudentStore@a7c18993) belonging to the STORING plane is activated first, then the metaobject stud (StudentObserver@a6cd5372) belonging to the STATISTIC plane, and lastly the metaobject blo (BaseLevelObserver@d5c43332) from the LOGGING plane, according to the order pre-established by the conflicts declared by the designer.

A

B

Fig. 6. Execution Sequence

7. Implementation

The reflective architecture described in the previous sections can be materialised in any that supports metaobjects. However, as current wide- spread programming languages do not provide metaobject support, they must be extended in order to do so. In order to add reflective characteristics, some changes must be carried out in the kernel or language compiler. The modified language must provide the infrastructure for the interception of messages, for the activation of the metaobjects that administer those messages, and for continuing the normal execution of the object that received the original message. The traditional manner in which compiled languages such as ++ or Java are extended is by means of the pre-processing of source code. This pre-processing adds the interception mechanism to the original code, such that the metaobjects are notified of the messages sent at the base level and they then carry out their specific computation. This implies, for example, the substitution of class, method and variable names with names that the reflection mechanism can handle. When a new association between the base and meta level is declared, the original class is modified and recompiled, with the consequent transformation of the original source code.

Additionally, this type of extension limits the runtime handling of situations and the flexibility of the system which reflective techniques aim to achieve. The reflective architecture has been implemented in Java, using JMOP [Zun00] to introduce the reflective mechanism, and extending the design of RefPat [Mar01] in order to introduce the concept of planes and treatment of conflicts [PBC00]. Each time an application class is loaded JMOP creates a new class which has access to the original one. The new class redefines the methods by adding a prefix, and the content of the original methods is simply an invocation to the reflection manager. Consequently, each time a base level object receives a message, the reflection manager is invoked. This manager verifies if the message (object / class) is to be reflected, and in that case it provides the list of associated metaobjects to be activated. This list is sent to the conflict manager. The conflict manager administers the conflicts declared by the designer (represented by a directed graph), and it reorganizes and returns the ordered list of metaobjects to the reflection manager. The latter invokes the metaobjects according to the established order, and returns control to the original base method. When the designer declares a reflective association, the system verifies and solves the static conflicts. In order to carry out this verification, it may require the collaboration of the plane manager, e.g., to control that the conflict being declared does not involve metaobjects of the same plane. The limitation that metaobjects on the same plane cannot be associated, is based on the fact that only different planes which each implement an independent functionality actually crosscut each other. Interaction between metaobjects on the same plane should be programmed by means of traditional invocations. The implementation of the framework in Java described above has been used for the development of the application mentioned in section 6, and can be instantiated in order to develop a wide variety of reflective applications.

8. Conclusions

This paper has described a framework that supports the development of systems with a multi-level reflective architecture. The main characteristics of this architecture are the flexibility of its reflective mechanism and the heterarchical structure of meta- levels. Additionally, it supports planes as groups of components that share the same basic functionality, permitting a wide range of interaction between planes and their components. As the architecture supports association of objects with multiple metaobjects which may therefore compete for activation, different categories and levels of conflicts have been studied and defined. Subsequently, the system supports the declaration and runtime handling of these types of conflicts. The framework is currently being documented in order to allow a more wide- spread use in the development of applications. A tool for the instantiation of the framework is being developed in order to facilitate this process, and to permit its implementation in different programming languages.

Additionally, different applications are being developed in order to test and evaluate the framework in different domains.

9. References

[Coi88] P. Cointe. A Tutorial Introduction to Architecture as provided by Class Oriented Languages. Proceedings of the International Conference on Fifth Generation Computer Systems, ICOT editor, pages 592-608, 1988. [DS84] J. Des Riveres and B. Smith. The Implementation of Procedurally Reflective Languages. Proc. of the 1984 ACM Symposium on Lisp and , pages 331-347, August 1984. [Mae87] P. Maes. Concepts and Experiments in Computational Reflection. In N.K. Meyrowitz, pages 147-155. [Mar01] C. Marcos. Patrones de Diseño como Entidades de Primera Clase. PhD. thesis. Universidad Nacional del Centro de la Provincia de Buenos Aires (UNCPBA), Facultad de Ciencias Exactas, Instituto de Sistemas ISISTAN, Abril 2001. [MMY93] H. Masuhara, S. Matsouka, and A. Yonezawa. Designing an OO Reflective Language for Massively-Parallel Processors. Proc. of Workshop OOPSLA'93. [OI94] H. Okamura and Y. Ishihawa. Object Location Control using Meta-Level Programming. In M. Tokoro and R. Pareschi. [OIT92] H. Okamura, Y. Ishikawa, and M. Tokoro. AL-1/: A Distributed Programming System with Multi-Model Reflection Framework. Proc. of the IMSA'92. International Workshop on Reflection and Metalevel Architecture. November 1992. [Par72] D.L.Parnas. On the criteria to be used in decomposing systems into modules. Communications of the ACM, 15(12):1053-1058, December 1972. [PDF99] R.Pawlak, L.Duchien and G.Florin. An Automatic Aspect Weaver with a Language. In the Second International Conference on Metalevel Architectures and Reflection. St-Malo, France. July 1999. [PBC00] J.Pryor, N.Bastán and M.Campo. A Reflective Approach to Support Aspect Oriented Programming in Java. In Proceedings of ASSE’2000, 29 JAIIO. Buenos Aires, Argentina, September 2000. [Str93] R. Stroud. Transparency and Reflection in Distributed Systems. ACM Operating Systems Review 27(2), April 1993. [WY88] T. Watanabe and A. Yonezawa. Reflection in an Object Oriented Concurrent Language. In N.K. Meyrowitz, pages 306-315. [Zun00] A.Zunino, Brainstorm/J: un framework para agentes inteligentes. Master's Degree Dissertation. Universidad Nacional del Centro, Instituto de Sistemas ISISTAN. April 2000.