SheepAspect Query Analyzer

SheepAspect-Query-Analyzer (aka SAQA, not to be confused with Sucka’) is a simple tool I built to let you quickly punch in your SAQL pointcuts, and execute them immediately against your assembly files to get instant results.

The GUI is quite plain and basic, but it does the job.

This tool will hopefully come in handy for developers to get into SAQL pointcuts and syntax. You just simply punch in your pointcut attributes on the text editor as you normally would on C#. E.g.

[SelectMethods(“Name:’Get*’ & Public”)]

You will then get instant feedbacks from this pointcut by executing it against your assemblies, which will bring back all the jointpoints it picks up (i.e.: all public methods with names starting with ‘Get’). Since it takes standard syntax of C# attributes, once you’re happy with the result, you can just copy this line straight onto your C# class.

You can type in as many pointcuts as you wish on the text-editor. You can also define aliases using ‘=’. E.g.:

[SelectMethods(“Name:’Get*’ & Public & InType:@NhConfigTypes”)]
NhConfigTypes = [SelectTypes(“Namespace: ‘NHibernate.Cfg*’”)]

Those pointcuts are equivalent to the following code on the actual C# class:

[Aspect]
public class MyAspect
{
   [SelectMethods("Name:'Get*' & Public & InType:@NhConfigTypes")]
   public void Pointcut1() {}

   [SelectTypes("Namespace:'NHibernate.Cfg*'")]
   public void NhConfigTypes(){}
}

SAQA is available for download from the latest SheepAspect trunk. SAQA will also be included as part of the next SheepAspect release.

What’s next?

  • Keyboard shortcuts
  • Ability to save the progress of your SAQA workspace
  • Ability to view and open the source-code of your joint-points in Visual Studio
  • SAQA will be able to read from SheepAspect configuration file (that will be introduced, hopefully, in the next SheepAspect major release)
  • I have NO plan to deliver any intellisense functionality, but feel free to send me a patch
Advertisements

SheepAop Is Now SheepAspect.org

I admit I didn’t spare much thought into the name when I started the project. I just simply followed the infamous Luk’s rule of project naming: “append the word ‘Sheep’ with something boringly obvious about the project”. Hence SheepAOP. It was just a random codename I picked for a project that was intended at that time as my own personal proof-of-concept on one rainy weekend. And I went slightly overboard with it without bothering myself to change to a friendlier name, and the name “SheepAop” managed to see the light of day.

It’s not a friendly name, and quite a mouthful to say, thanks to the double vowels in the acronym “AOP”. I’ve lately started develeoping an involuntary cringing habit on the sound of “SheepAOP” produced by my mouth every time I talk to people. And I hate cringing. Something has to be done about it. Changing my habit is a bit complicated, so instead I renamed the project.

So it’s official, the project is now called SheepAspect. It has found a lovely home at SheepAspect.org, and the source-code has been refactored to embrace the new name (which is obviously a breaking change). The old url (sheepaop.codeplex.com) still works fine and simply redirects you to the new address. So once again, say hi to SheepAspect, please help it feel comfortable with its new name.

SheepAop Part 5: Aspects Inheritance And Polymorphism

This Series

  1. Getting Started with SheepAOP
  2. Pointcuts and SAQL Basics
  3. Aspects Lifecycles & Instantiations
  4. Integrating with IoC containers
  5. Aspects Inheritance & Polymorphism
  6. Attributive Aspects (ala PostSharp)
  7. Unit-testing your aspects
  8. Extending SheepAop

Reusing Advices

Think back to the concurrency example from our previous post. We used the ReadWriteLockAspect to define the reading and writing operations within our ShoppingCart, and apply a read/write locking pattern onto it. Surely we can apply this same pattern to other classes where a safe concurrent access is required. We can refactor this well-tested concurrency pattern into an abstract aspect that we can reuse instead of reimplementing it when we need it again.

This gives us a perfect situation to demonstrate SheepAop’s modularity and reuse, as we refactor our ReadWriteLockAspect example into the following.

[AspectPerThis("ReadingsPointcut", "WritingsPointcut")]
public abstract class ReadWriteLockAspect
{
   protected abstract void ReadingsPointcut(); // Abstract pointcut
   protected abstract void WritingsPointcut(); // Abstract pointcut

   protected abstract int GetTimeout(); // Abstract method

   private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

   [Around("ReadingsPointcut")]
   public object LockRead(JoinPoint jp)
   {
      try
      {
         _lock.EnterReadLock(GetTimeout());
         return jp.Execute();
      }
      finally()
      {
         _lock.ExitReadLock();
      }
   }

   [Around("WritingsPointcut")]
   public void LockWrite(JoinPoint jp)
   {
      try
      {
         _lock.EnterWriteLock(GetTimeout());
         jp.Execute();
      }
      finally()
      {
         _lock.ExitWriteLock();
      }
   }
}

Now to apply a write/lock behavior to our ShoppingCart class, we simply extend the aspect. We just need to provide the implementation of the pointcuts. The behavior of the advice will be inheritted from the base aspect.

public class ShoppingCartLockAspect: ReadWriteLockAspect
{
   [SelectMethod("'* ShoppingCart::Get*(*)'")]
   [SelectPropertyGet("'* ShoppingCart::*'")]
   protected override void ReadingsPointcut(){}

   [SelectMethod("InType:'ShoppingCart' && Name:'AddProduct'|'RemoveProduct'")]
   protected override void WritingsPointcut(){}

   protected override int GetTimeout()
   {
      return 2000; // Timeout is 2 seconds
   }
}

Now we have used the base ReadWriteLockAspect to transform the ShoppingCart class to be thread-safe. We can reuse this same base aspect to any other target class that you intend to make thread-safe.

Tips on Pointcut Compositions: make sure you take advantage of the composability of SheepAop pointcuts when designing a reusable aspect. You can devide your pointcut into fragments to extract any reusable pattern out, and only expose a small fraction of it as abstract. As an example, our ReadWriteLockAspect can be modified to automatically apply the locks on all read/write methods and properties on the particular type that you target.

[AspectPerThis("ReadingsPointcut", "WritingsPointcut")]
public abstract class ReadWriteLockAspect
{
   [SelectMethod("'InType:@TargetClass && Name:'Get*'|'Is*' && !ReturnsVoid")]
   [SelectPropertyGet("InType:@TargetClass")]
   protected void ReadingsPointcut(){}

   [SelectMethod("InType:@TargetClass && Name:'Add*'|'Remove*'|'Set*'")]
   [SelectPropertySet("InType:@TargetClass")]
   protected void WritingsPointcut(){}

   //This is a small fragment of the pointcut that we expose as abstract
   protected abstract @TargetClass();

   /* and all the rest of it unchanged.. */
}

Now our base aspect provides a reusable template for our pointcuts, where a small fragment @TargetClass is left out as abstract to be composed to form the complete pointcut. The concrete aspect only needs to provide the implementation of this small fragment, rather than the whole pointcut expressions.

public class ShoppingCartLockAspect: ReadWriteLockAspect
{
   [SelectTypes("'ShoppingCart'")]
   protected override void TargetClass(){}

   protected override int GetTimeout()
   {
      return 2000; // Timeout is 2 seconds
   }
}

Other example

The ActorAspect example can also be refactored into an abstract class to reuse its advice behavior, but I will leave that as an exercise for the reader.

Reusing Pointcuts

In the previous example, we have used aspect inheritance to reuse a common advice behavior (read/write locking behavior) repeatedly for multiple pointcuts. Aspect inheritance can also be used to reuse common pointcut expressions repeatedly in multiple advice implementations. A common example of this is aspects for defining extensibility points in a plugin architecture.

For instance, consider you want to define an extensibility point that is triggered at the point of every bank-account transaction. So we define the following abstract aspect.

[Aspect]
public abstract class AccountTransactionPlugin
{
   [SelectMethod(@"InType:AssignableTo:'AccountBase'
            && Name: 'Withdraw'|'Deposit'
            && ArgTypes:'Money'")]
   protected void TransactionPointcut(){}

   [Around("TransactionPointcut")]
   public void AroundTransaction(MethodJointPoint jp)
   {
      OnTransacting((Account)jp.This, (Money)jp.Args[0], ()=> jp.Execute());
   }

   protected abstract OnTransacting(Account account, Money amount, Action proceed);
}

Now that we have this extensibility point defined, a third party can provide their plugins by implementing this base-class. For example, the following plugin will add a business policy to limit transaction amounts within our banking system.


public class TransactionLimitPlugin: AccountTransactionPlugin
{
   private const int CompanyLimit = 100000;
   private const int PersonalLimit = 2000;

   protected override OnTransacting(Account account, Money amount, Account proceed)
   {
      var limit = account.Customer.IsCompany? CompanyLimit: PersonalLimit;
      if(amount > limit)
         throw new TransactionOverlimitException(amount, limit);
      proceed();
   }
}

More plugins for this specific extensibility point can be added to the system by writing more implementations of AccountTransactionPlugin (e.g. a plugin to apply transaction-fees depending on the types of the account). Typically we would have a set these abstract aspects with different pointcut-expressions, each represents different extensibility point within the system (e.g. when an order is created, when a case is raised, when a conversation occurs, etc), onto which a specific plugin can be hooked and unhooked. You can jazz up this technique by adding MEF to the mix.

Note that the domain code of our application might not be designed with plugin architecture in mind. It probably does not even aware of any extensibility system that is in place. This brings us to our next point…

Speaking of Extensibility..

Extensibility has always been a chicken-and-egg problem. Many business applications require the extensibility to accomodate rapidly changing business rules, policies, and workflows, sometimes allowing extensibility by third-party developers. To achieve this, architects are often faced with underdesign/overdesign issue. If you underdesign, you may have to make massive changes later in the development cycle. If you overdesign with excessive amount of extensibility point on every method of your application, the implementation may be burdened with code of questionable usefulness.

With AOP, you can delay making design decisions for future requirements because you can implement those extensibility points unobtrusively using aspects. You can focus on the current requirement of the system.
In this respect, AOP works in harmony with YAGNI (You aren’t gonna need it). Implementing a feature just because you may need it in the future often results in wasted effort because you won’t actually need it. With AOP, you can stick faithfully to your current requirement, and if you do need a particular kind of functionality later, you can implement it without having to make system-wide modifications

Attribute-based Aspects (ala Postsharp)

(Since this question gets asked quite a lot, I will post this section again in a separate post as a handy reference)

SheepAop is not specifically built to support attribute-based declarative approach used in Postsharp. But using the rich pointcut expressions and aspect inheritance in SheepAop, it’s quite trivial to implement our own implementation. We just simply need to write this simple abstract aspect to deliver the same attribute-based functionality.

[Aspect]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
public abstract class AroundMemberAttribute: Attribute
{
   [SelectMethods("HasCustomAttributeType:ThisAspect")]
   [SelectPropertyGets("HasCustomAttributeType:ThisAspect")]
   [SelectPropertySets("HasCustomAttributeType:ThisAspect")]
   protected void DecoratedPointcut(){}

   [Around("DecoratedPointcut")]
   public abstract object Around(JointPoint jp);
}

This aspect simply defines a pointcut that matches all methods and properties that are decorated using the concrete type of this aspect. So now we can use this base attribute to create our TransactionalAttribute as an example.

[Aspect]
public class TransactionalAttribute: AroundMemberAttribute
{
   public override object Around(JointPoint jp)
   {
      using(var tx = new TransactionScope())
      {
         var result = jp.Execute();
         tx.Complete();
         return result;
      }
   }
}

That is all it. Now you can use this attribute to decorate methods and properties that you want to make transactional. For instance:

[Aspect]
public class OrderService: IOrderService
{
   [Transactional]
   public void ProvisionOrder(Order order)
   {
      // .... whatever ...
   }
}

For your convenience, the base-aspect AroundMemberAttribute is included straight out-of-the-box within SheepAop, so you don’t have to write it every time. Another variation of the base attribute is called AroundCallAttribute. They both have equivalent functionality, but whereas AroundMemberAttributes targets the bodies of methods and properties decorated with the attribute, AroundCallAttribute targets the calling of methods, getting/setting properties, and reading/writing fields decorated with the attribute.

Summary

Inheritance is a key component in making reusable aspects in SheepAop. Since SheepAop aspects are just normal POCO classes, you can make use of the same Object-Oriented techniques such as inheritance and polymorphism that we’re all familiar with. The same techniques are also used to implement the declarative attribute-based aspects that gives a lot of convenience for many simple cases.