Sunday, September 17, 2006

DataObjects.Net v4.0 components: Aspects

We're going to widely use aspects \ weaved methods in DataObjects.Net v4.0. And it seems at least some of them can be developed as independent components (earlier we planned to call them Aspector Extenders, but since it looks like we'll use PostSharp, the common name of such components is the subject of question now).

At least the following functionality will be based on aspects:
- Online transactions (transactional methods)
- Offline transactions
- Undo\Redo (business methods, rollback methods)
- Tracing.

Top three features are actually quite dependent on each other, so most likely they'll be implemented altogether.

Here is example code of famous Account class and its Transfer method (rollbackable & fully transactional both in online and offline modes):

public class Account : ... 
{
  [Persistent]
  [Indexed]
  // No proxies in v4.0; property getter & setter bodies of
  // persistent properties should also be replaced by
  // Aspector \ PostSharp.
  public double Balance {get {return 0}; set {return};}

  ...
  
  [RollbackableMethod]
  // Any rollbackable method is always [Transactional] one
  public void Transfer(Account accountTo, double amount)
  {
    if (accountTo==this)
      throw new InvalidOperationException("Accounts are the same.");
    if (amount<=0)
      throw new InvalidOperationException("Illegal amount.");
    if (Balance<amount)
      throw new InvalidOperationException("Illegal amount.");
    
    RollbackServices.ActiveMethod.Description =
      String.Format("Transferring ${0} from {1} to {2}", amount, this, accountTo);
    RollbackServices.ActiveMethod.RollbackInfo.Add("accountTo", accountTo);
    RollbackServices.ActiveMethod.RollbackInfo.Add("amount",    amount);

    accountTo.Balance += amount;
    Balance -= amount;
  }

  [RollbackMethod]
  // Internal binding to Transfer method is performed by name.
  // Any rollback method is also a [Transactional] one and
  // rollbackable one.
  [RollbackableMethod(Wrapper = true)]
  // "Wrapper" means that altough method is rollbackable, it doesn't
  // "pushes" rollback data itself, but forwards this part to other
  // rollbackable methods called from it. Such method doesn't require
  // rollback method: system should just rollback all rollbackable
  // methods called from it.
  // So generally such method only sets the description of action it
  // performs; actual job is always performed by the methods it calls.
  internal void RollbackTransfer(RollbackableMethodCallDescriptor mcd)
  {
    // It shouldn't be necessary to set
    // RollbackServices.ActiveMethod.Description, since it
    // can be easily pre-set by caller of this method, i.e.
    // by RollbackableMethodCallDescriptor.Rollback(...)
    Account accountFrom = (Account)mcd.Target;
    Account accountTo   = (Account)mcd.RollbackInfo["accountTo"];
    double  amount      = (double) mcd.RollbackInfo["amount"];
    accountTo.Transfer(accountFrom, amount);
  }
}

No comments:

Post a Comment