/**************************************************** * Course #: COM 3362 * Name: Paul Freeman * Account name: pfreeman * * Assignment #: Homework 6, part 1 * Date: February 16, 2002 ****************************************************/ 1. Personality Implementation Description: The implementation of the personality pattern can be accomplished quite nicely in AspectJ. In AspectJ, a method with a body can be introduced into an interface, something that is not allowed in pure java. You may then call this inherited method from an instance of the implementing class. This technique allows for an easy implementation of the upstream interface, maintaining the personality pattern. The downstream interface can be declared directly in the personality interface. This maintains the requirement that all classes implementing this interface provide the method bodies for the downstream interface (i.e. the personality contains abstract method declarations). Java does not allow interface methods to be declared private. Therefore, we have not quite succeeded in completely implementing the personality pattern (i.e. clients of personalities could access the downstream interface). Again, AspectJ gives us an easy way to maintain the requirement that clients of the personality don't access the downstream interface. Since the method inserted into the personality (interface) occurs within the Aspect, we know that, at compile time, calls to the downstream interface should occur only within the Aspect itself. We can therefore decare a pointcut which describes all of the calls to the downstream interface and which also includes the AspectJ qualifier !within(Aspect). Then we can use the AspectJ static advice "declare error:" to check the pointcut at compile time, thereby enforcing the requirement that clients not access the methods of the downstream interface. We must also enforce the requirement that only the personality can implement the upstream interface. This pointcut is described in AspectJ by describing all of the execution points (i.e. the method declarations) of the upstream interface that occur within a Flier class. We must also 'and' these joinpoints with a !within(Aspect) declaration to avoid capturing the inserted method declaration within the Aspect itself. Finally, there is the requirement of the personality pattern that the popular methods follow the law of demeter. This is satisified the implementation of the popular methods themselves and is up to the person writing the popular methods to maintain. Implementation: So for example, in the Flier personality that I implemented: the upstream interface, i.e. the method Fly(int, int, int), was introduced into the Flier interface (or personality). The class Bat, which implements (personifies) Flier then has access to this method. This structure satisifies the requirement of the Personality pattern that the upstream interface (the method Fly(..)) be implemented only once by the personality, and not reimplemented in each personifying class. The methods of the downstream interface for Flier are declared within the interface Flier itself, enforcing the requirement that all classes personifying (implementing) Flier provide bodies for those methods. And within the body of the Aspect Flying, I have declared a pointcut which uses the || (or) qualifier to capture all calls to the downstream interface, and which also uses the && (and) qualifier to capture only those calls which do not occur within the Aspect Flying. This enforces that clients of a Flier personality do not access the downstream interface. And finally, within the body of the Aspect Flying, I have also declared a pointcut that uses the && qualifier to capture all of the execution points (i.e. method declatations) of the upstream interface void Fly(int, int, int) that occur within a Flier class and do not occur within the Aspect Flying itself. To demonstrate the successful use of this granularity, I have declared a method identical to the Upstream Interface within both the Main class and the Bat class. The method declaration within Main does not cause an error to be thrown at Compile time while the method declaration within Bat does. 2. Dynamic and Static Personality Implementation: Static personality implementation is described above and an example of such an implementation was done as an exercise to satisfy the first part of this assignment. Dynamic personality implementation can be implemented using around() advice in an aspect to look for all calls to an upstream interface's popular methods. Access to the target of the call could then be granted allowing us to test for a condition, and then attempt to proceed with the appropriate popular method of the personality if that condition is satisfied. That condition would need to at least entail that all the downstream interface methods actually exist, something that could be determined through java's implementation of reflection. If they do exist and the rest of the condition is satisfied, then a call to the downstream methods would occur, otherwise a call to the AspectJ proceed() method would occur causing the original method to be activated.