Aspect-Oriented Programming (AOP) is an approach for realizing separation of concerns and allows different concerns to be weaved into existing applications. Concerns usually cross-cut the object-oriented structure. Whenever a concern needs to invoke some operations on objects of the given structure the problem arises, that those objects have different types, but the concern expects them to be handled in the same way. Therefore a mechanism for grouping objects of different types is needed.This paper discusses different mechanisms and proposes aspect-oriented adapters for grouping types and shows how this approach permits a higher level of flexibility and reduces the limitations of known approaches. Aspect-oriented adapters are not limited to a specific general purpose aspect language (GPAL). Nevertheless the examples in this paper are realized in AspectJ, which is by far the most popular and well-established general purpose aspect language. 1 Motivation and Problem Description Let us assume we want to make objects persistent, which are created by an existing simulation-application. As pointed out in [3] persistency is a concern and so this is a typical application of Aspect-Oriented Programming [4]. Every newly created object should be added to a persistent storage and whenever the state of a certain object changes, its representation on the store must be updated. There is no need to offer an interface for retrieving objects, because the simulation itself does not use former objects. Instead the information is used by another application which directly accesses the storage for retrieving information about the simulation. The objects to be stored are all instances of class Point. A suitable (straight-forward) solution for this problem in AspectJ [5] would be an aspect, which writes the state to the store every time an object is created and whenever its state changes (fig. 1). An instance of the aspect PersistentPoint is created for every Point instance. The aspect generates an object id (realized as an instance counter) and stores it in its attribute id. After creating a new Point the object is written to the persistent storage realized in the constructor of PersistentPoint. The state of a point changes, whenever the methods setX() or setY()are invoked. Therefore a pointcut setPC() is defined for any instance of Point receiving a set-message. Whenever this happens the corresponding pointcut method (or advice in the AspectJ terminology) is executed which reads a point's state (getX() , getY()) and updates the persistent storage. aspect PersistentPoint of eachobject(instanceof(Point)){ private static int idnum = 0; private int id = ++idnum; public PersistentPoint() { .. write new (unitialized) object to storage} pointcut setPC(Point p): instanceof(p) && (receptions(void setX(float)) || receptions(void setY(float))); after(Point p): setPC(p) { float x = p.getX()); float y = p.getY()); ...update x,y of object id} } class Point { private float x=0; private float y=0; public float getX() { return x;} public float getY() { return y;} public void setX(float x) { this.x = x;} public void setY(float y) { this.y = y;} } Figure 1: a) Class Point, b) Aspect PersistentPoint Let us assume there is another (similar) application having its own implementation of a point AnotherPoint identical to Point. The proposed solution directly depends on the class Point and cannot be used for other classes. Therefore it would be more desirable to define a persistency aspect without being limited to class Point. AspectJ supports inheritance relationships between aspects and allows to declare abstract aspects, so it seems to be a good choice to define an abstract aspect PersistentObject, which is responsible for creating the object id and reading the object's state (fig. 2, see [2] for a detailed discussion on inheritance and AOP). Its subaspects only have to define the class this aspect should be weaved to. Therefore PersistentObject contains an abstract pointcut weavedClassPC(), which has to be defined by the subaspects. We want the aspects to be instantiated for every instance of Point and AnotherPoint, so the definitions of weavedClassPC()in our concrete aspects corresponds to that. But now a new problem arises: how can the state of the object be read in the pointcut method? The intention of the aspect is to be woven to classes, having the methods getX(), getY(), setX(float) and setY(float). The set-methods are used for the pointcut definition, and the get-methods are needed by the aspect instance to read an object’s state. But although knowing those method signatures the concrete type of those classes is unknown and left to those aspects, which make the abstract pointcut concrete. Because aspects crosscut the inheritance structure of classes usually those classes do not have any common type but java.lang.Object. So it is not possible to send getter-messages to the related object, because the type is unknown and therefore a typecast is not possible.1 A pos1 We assume here general purpose aspect languages with static type checking like AspectJ or Sally [8] which are both based on the programming language Java. sibility would be to use reflection for those method calls, but that requires an enormous effort. abstract aspect PersistentObject of eachobject(weavedClassPC) { private static int idnum = 0; private int id = ++idnum; public PersistentObject() { .. write new (unitialized) object to storage} abstract pointcut weavedInstances(Object o); pointcut setPC(Object o): weavedInstances(o) && (receptions(void setX(float)) || receptions(void setY(float))); after(Object p): setPC(p) { ..write state to data storage} } aspect PersistentPoint extends PersistentObject { pointcut weavedInstances(Point p): instanceof (p); }aspect PersistentObject of eachobject(weavedClassPC) { private static int idnum = 0; private int id = ++idnum; public PersistentObject() { .. write new (unitialized) object to storage} abstract pointcut weavedInstances(Object o); pointcut setPC(Object o): weavedInstances(o) && (receptions(void setX(float)) || receptions(void setY(float))); after(Object p): setPC(p) { ..write state to data storage} } aspect PersistentPoint extends PersistentObject { pointcut weavedInstances(Point p): instanceof (p); } aspect PersistentAnotherPoint extends PersistentObject { pointcut weavedInstances (AnotherPoint p): instanceof (p); } Figure 2: abstract persistency aspect (trial) The concrete problem is, that aspect-oriented programming groups objects in another way than the predefined object-oriented structures do. So a mechanism is needed how to group objects of different types and allow to sent messages to them. In the next section we discuss approaches related to this problem and demonstrate that they do not solve this problem appropriately. Afterwards we introduce and discuss aspect-oriented adapters for grouping types and show how this approach allows a higher level of flexibility and reduce the limitations of other approaches. We will also apply the adapter to the introducing example. In the forth section we map the introducing example to aspect-oriented adapters. Finally we summarize and conclude the paper.
[1]
Ralph Johnson,et al.
design patterns elements of reusable object oriented software
,
2019
.
[2]
Cristina V. Lopes,et al.
Aspect-oriented programming
,
1999,
ECOOP Workshops.
[3]
J. V. Gurp,et al.
Separation of Concerns : A Case Study
,
2001
.
[4]
Antero Taivalsaari,et al.
On the notion of inheritance
,
1996,
CSUR.
[5]
William G. Griswold,et al.
An Overview of AspectJ
,
2001,
ECOOP.
[6]
Peter Wegner,et al.
Dimensions of object-based language design
,
1987,
OOPSLA '87.
[7]
Stefan Hanenberg,et al.
Concerning AOP and Inheritance
,
2001
.
[8]
Mira Mezini,et al.
Programming with Aspectual Components
,
1999
.
[9]
Claus H. Pedersen,et al.
Extending ordinary inheritance schemes to include generalization
,
1989,
OOPSLA '89.