AspectWerkz


AspectWerkz[6] describes itself as a "dynamic, lightweight, and high-performant AOP framework for Java." Its AOP model is deeply based on the AspectJ model. It provides capabilities for runtime weaving through bytecode manipulation. Though the general model is similar to AspectJ's, aspect expression is different in that aspects, advice, and intertype declarations are written in plain Java, with aspect definitions defined using either XML or annotations. Here, we go the annotations route for two reasons. First, at the time of writing, it seems that annotations in Java are increasing in popularity (as manifest by their introduction to the Java language in Version 1.5), and second, we think that they are more accessible than the XML representations of aspects.

[6] http://aspectwerkz.codehaus.org/.

If you've dipped directly into this section without reading about how to get to AspectJ from Theme/UML, then we recommend that you review the AspectJ section. From the perspective of mapping Theme/UML to AspectWerkz, the similarities between the two models are such that the basic steps turn out to be correspondingly similar, with similar reasons for making the various implementation choices. For this reason, we take the approach of illustrating AspectWerkz's syntax here and also highlighting the interesting differences between it and AspectJ.

As we did with AspectJ, we look at the AspectWerkz approach by examining the implementation of a crosscutting theme from the Crystal Game, track-energy.

Track-energy

As a general policy for mapping to code from Theme/UML, we make an effort to provide the same kinds of encapsulations as were illustrated in the designs. As such, we like the idea of making the crosscutting theme code reusable by making it an abstract aspect and using a concrete aspect to represent the bindings to the base code. This worked well for us with AspectJ, and we take the same approach with AspectWerkz.

In general, plain Java is used to write code in AspectWerkz. In addition, a library of classes is provided that implements the AOP model that you can use primarily for introspection purposes.

Abstract Aspect

An abstract aspect is written as an abstract class, as follows:

 import org.codehaus.aspectwerkz.joinpoint.JoinPoint; abstract class TrackEnergy { // aspect code goes here. } 

Intertype Declarations

Intertype declarations in AspectWerkz are dealt with as inner classes and interfaces. The EnergyEntityI and GameI interfaces to match the classes in the track-energy theme are illustrated in Listing 7-9, lines 1 to 8 and 10 to 15, respectively. The Energy class in the track-energy theme is an active class that periodically responds to an event to lose energy, which is implemented as a thread. This means that the corresponding interface, EnergyEntityI, should extend Java's Runnable interface.

Listing 7-9. Interfaces for Track-Energy
 1    package ie.tcd.cs.dsg.aosd.theme.game; 2 3    public interface EnergyEntityI extends Runnable { 4       public void setChangeAmount(int changeAmount); 5       public void changeEnergy(int changeAmount); 6       public void loseEnergy(); 7       public GameI getGame(); 8    } 9 10   package ie.tcd.cs.dsg.aosd.theme.game; 11 12   public interface GameI { 13     boolean isPlayerInLocation(); 14     void getEnergy(String name, EnergyEntityI energyEntity); 15   } 

Listing 7-10 illustrates the abstract inner classes to capture the structure and behavior defined for the Energy class (lines 142) and the Game class (lines 4361) in the track-energy theme. These classes implement the relevant interfaces previously defined, with EnergyAbstract also implementing a run() method for threads. Notice, in particular, that both classes have a variable m_info of type CrossCuttingInfo (lines 3 and 45). In AspectWerkz, the CrossCuttingInfo class has a number of useful methods for introspection on the runtime execution of the system. Particularly for the track-energy theme, the concrete aspect classes need to use this object to obtain a reference to the currently executing object at runtime. We have two examples of this in Listing 7-10. The getGame() method in EnergyAbstract calls getMixinTargetInstance() (lines 2829) to obtain the required instance, as does the isPlayerInLocation() method on line 58. In order to work with a CrossCuttingInfo object, AspectWerkz mandates a constructor that takes one CrossCuttingInfo as its only parameter (see lines 45 and 4647).

Listing 7-10. Inner Classes for Track-Energy
 1    public static abstract class EnergyAbstract implements EnergyEntityI 2    { 3    protected final CrossCuttingInfo m_info; 4    public EnergyAbstract(final CrossCuttingInfo info) { 5       m_info = info; 6    } 7    // attributes 8    private int duration = 5; 9    private int energyUnit = 10; 10   private int changeAmount = 1; 11   GameI game; 12 13      // methods 14   public GameI getGame() 15   {  return game; } 16 17   public void setChangeAmount(int a) 18   {  changeAmount = a; } 19 20   public void changeEnergy(int e) 21   {  energyUnit = energyUnit + e;  } 22 23   public void loseEnergy() 24   {  energyUnit = energyUnit - changeAmount; } 25 26   public GameI getGame() 27   { 28      EnergyEntityI player = 29            EnergyEntityI)m_info.getMixinTargetInstance(this); 30      GameI game = (GameI)player.getGame(); 31      return game; 32   } 33   public void run() 34   { 35      try { 36         loseEnergy(); 37         Thread.sleep(5000); 38      } catch (InterruptedException e) { 39         // Log or notify exception occured 40      } 41   } 42 } 43 public static abstract class GameAbstract implements GameI 44 { 45      protected final CrossCuttingInfo m_info; 46   public GameAbstract(final CrossCuttingInfo info) { 47      m_info = info; 48   } 49   public void getEnergy(String name, EnergyEntityI energyEntity) 50   { 51      if(name.equals("completeWizardErrand")) 52      {  energyEntity.changeEnergy(4);} 53      else if(name.equals("completeWarriorTest")) 54      {  energyEntity.changeEnergy(3);} 55      //. . . and so on 56   } 57   public boolean isPlayerInLocation() { 58      GameI game = (GameI)m_info.getMixinTargetInstance(this); 59      return game.isPlayerInLocation(); 60   } 61   } 

Pointcuts and Advice

In AspectWerkz, pointcuts and advice are defined using a combination of annotations for pointcut naming and by enforcing that a JoinPoint object is passed to the advice. The JoinPoint class is part of AspectWerkz and implements the specification of particular points of execution in the code (or joinpoints). Using this instance, you can get static information and runtime type information about the current joinpoint.

The following code illustrates the moveLocation pointcut and the after advice. The annotation @After indicates that the code should be executed after execution of the joinpoint. The pointcut is named as moveLocation directly following the @After annotation. We also see an example of runtime information being requested from the joinPoint instance in the call to getTarget(), which returns the object in which the joinpoint is executing.

 @After moveLocation    public void moveLocation(JoinPoint joinPoint)    {       EnergyEntityI energyEntity = (EnergyEntityI)joinPoint.getTarget();       GameI game = energyEntity.getGame();       if(game.isPlayerInLocation())       { energyEntity.setChangeAmount(2); }       else       { energyEntity.setChangeAmount(1); }    } 

The following code illustrates the remaining two pointcuts and advice for track-energy: energyAction and joinGame. These are similar in form to the moveLocation pointcut. You can see how the joinPoint object was used again to get the name of the currently executing method with a call to getSignature().getName().

 @After energyAction public void energyAction(JoinPoint joinPoint) {    String currentActionName = joinPoint.getSignature().getName();    EnergyEntityI energyEntity = (EnergyEntityI)joinPoint.getTarget();    GameI game = energyEntity.getGame();    game.getEnergy(currentActionName, energyEntity); } @After joinGame  public void joinGame(JoinPoint joinPoint) {    EnergyEntityI energyEntity = (EnergyEntityI)joinPoint.getTarget();    Thread energyLossThread = new Thread(energyEntity);    energyLossThread.start(); } 

Concrete Aspect

Now that we've implemented an abstract class that represents the abstract aspect, we need to provide concrete implementations to capture the bindings defined in the bind[] attachment to the crosscutting theme. In addition to a standard extension of the abstract class, we implement concrete pointcuts, and concrete inner classes.

Concrete Pointcuts

Concrete pointcuts are defined using the @Expression annotation followed directly by a declaration of the pointcut as AspectWerkz type Pointcut. The @Expression annotation has expressiveness similar to AspectJ's in terms of the types of joinpoints that can be definedin this case, we use the execution of bound methods for each of our concrete pointcuts, as follows:

 @Expression execution (* Player.joinGame(..)) Pointcut joinGame; @Expression execution (* Player.setLocation(..)) Pointcut moveLocation; @Expression execution (* Player.incrementCrystals(..)) ||       execution (* Player.addCrystals(..)) ||       execution (* Player.completeWarriorTest(..)) ||       execution (* Player.completeWizardErrand(..)) Pointcut energyAction; 

The bind[] attachment on the composition relationship to Theme/UML's track-energy theme tells you which concrete methods to use.

Concrete Intertype Declarations

You now need to provide concrete implementations for the abstract inner classes that AspectWerkz uses to provide intertype declarations. The following code shows an implementation of EnergyIntroduction that extends EnergyAbstract and of GameIntroduction that extends GameAbstract. Notice that an @Introduce within annotation specifies that the EnergyIntroduction class should be "introduced" to the base Player classin other words, EnergyIntroduction's methods and variables are added to the Player class. Another annotation specifies that the GameIntroduction class should be introduced to the base Game class. As they do with AspectJ, the Theme/UML designs help you decide which classes these are by looking at the bind[] attachment (in the case of Player), or by using the class with the same name in the base program (in the case of Game), or by looking at other explicit a composition relationships that indicate matching.

 @Introduce within(ie.tcd.cs.dsg.aosd.theme.game.Player)            deploymentModel=perInstance public static class EnergyIntroduction extends EnergyAbstract {    public EnergyIntroduction(final CrossCuttingInfo info) {       super(info);    } } @Introduce within(ie.tcd.cs.dsg.aosd.theme.game.Game)            deploymentModel=perInstance public static class GameIntroduction extends GameAbstract {    public GameIntroduction(final CrossCuttingInfo info) {       super(info);    } } 

We now have all we need to provide concrete implementations for the aspect's abstract class, as illustrated in its entirety in Listing 7-11.

Listing 7-11. Concrete Aspect for Track-Energy
 package ie.tcd.cs.dsg.aosd.theme.game; import org.codehaus.aspectwerkz.CrossCuttingInfo; import org.codehaus.aspectwerkz.Pointcut; public class ConcreteTrackEnergy extends TrackEnergy {  @Expression execution (* Player.joinGame(..))  Pointcut joinGame;  @Expression execution (* Player.setLocation(..))  Pointcut moveLocation;  @Expression execution (* Player.incrementCrystals(..)) ||        execution (* Player.addCrystals(..)) ||        execution (* Player.completeWarriorTest(..)) ||        execution (* Player.completeWizardErrand(..)) Pointcut energyAction; @Introduce within(ie.tcd.cs.dsg.aosd.theme.game.Player)            deploymentModel=perInstance  public static class EnergyIntroduction extends EnergyAbstract {     public EnergyIntroduction(final CrossCuttingInfo info) {        super(info);     }  }  @Introduce within(ie.tcd.cs.dsg.aosd.theme.game.Game)             deploymentModel=perInstance  public static class GameIntroduction extends GameAbstract {     public GameIntroduction(final CrossCuttingInfo info) {        super(info);     }  } } 

Deployment Descriptor

Finally, an XML deployment descriptor is required to deploy the aspect classes into your system. Following is an example for the Crystal Game. Notice the order in which aspects are specifiedthis is similar to AspectJ's declare precedence list in that crosscutting behavior from ConcreteP2PCommunication is executed before any from ConcreteTrackEnergy.

 <!DOCTYPE aspectwerkz PUBLIC "-//AspectWerkz//DTD 1.0//EN" "http://aspectwerkz.codehaus.org/dtd/aspectwerkz.dtd"> <aspectwerkz> <system >    <package name="ie.tcd.cs.dsg.aosd.theme.game">       <aspect                            deployment-model="perClass"/>       <aspect                            deployment-model="perClass"/>    </package> </system> </aspectwerkz> 



Aspect-Oriented Analysis and Design(c) The Theme Approach
Aspect-Oriented Analysis and Design: The Theme Approach
ISBN: 0321246748
EAN: 2147483647
Year: 2006
Pages: 109

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net