Thursday, August 13, 2015

Dynamically Adding a Transactable

I have run into several situations where I have to work on data that could have been modified through one of several different relationships.  It's not practical to consider each possible relationship.  What I have found that works, is to dynamically add a Transactable object.

Here is an example of adding the Transactable object.

 public class CustomMeasurement implements CustomMeasurementRemote {  
   /* ... snip ... */
   @Override
   public void save() throws MXException, RemoteException {
      if (/* condition true */) {
         getMXTransaction().add(new CustomTransactable(this));
      }
      super.save();
   }

   @Override
   public void customWork() throws MXException, RemoteException {
      // perform work that
   }
}


In this example, the custom Measurement object overrides the save method.  When it is determined that the customWork() should be performed, the CustomTransactable is added to the current transaction.  In this example, it's done in the save() method, but it can be done in any method, at any time.

The CustomTransactable looks like this:

 public class CustomTransactable implements Transactable {  
   
   private CustomMeasurement mbo;  
   
   public CustomTransactable(CustomMeasurement mbo) {  
     super();  
     this.mbo = mbo;  
   }  
   
   @Override  
   public void commitTransaction(MXTransaction arg0) throws MXException, RemoteException {  
     return;  
   }  
   
   @Override  
   public void fireEventsAfterDB(MXTransaction arg0) throws MXException, RemoteException {  
     return;  
   }  
   
   @Override  
   public void fireEventsAfterDBCommit(MXTransaction arg0) throws MXException, RemoteException {  
     MboSetRemote msr = mbo.getMboServer().getMboSet("MEASUREMENT", mbo.getUserInfo());  
     CustomMeasurementRemote mr = (CustomMeasurementRemote)msr.getMboForUniqueId(mbo.getUniqueIDValue());  
     mr.customWork();  
     msr.save();  
   }  
   
   @Override  
   public void fireEventsBeforeDB(MXTransaction arg0) throws MXException, RemoteException {  
     return;  
   }  
   
   @Override  
   public void rollbackTransaction(MXTransaction arg0) throws MXException, RemoteException {  
     return;  
   }  
   
   @Override  
   public void saveTransaction(MXTransaction arg0) throws MXException, RemoteException {  
     return;  
   }  
   
   @Override  
   public void undoTransaction(MXTransaction arg0) throws MXException, RemoteException {  
     return;  
   }  
   
   @Override  
   public boolean validateTransaction(MXTransaction arg0) throws MXException, RemoteException {  
     return true;  
   }  
 }  

The constructor takes a reference to the mbo that will be updated.

All the methods, with two exceptions, have empty stubs, but they need to be defined.

The first exception is validateTransaction() returns true.

The second exception is fireEventsAfterDBCommit().  This method is called have the data has been committed to the database.  In this example, it loads a fresh copy of the mbo from the database, calls a method to act on it, and then saves the changes back to the database.

This occurs within the same thread as the call to MboSet.save().  The call will not return until after the CustomTransactable has run.

Since the code executes after the commit, the changes will appear in a separate EAudit record, if the mbo is EAudit enabled.

Getting back to my original problem.  The code in the Mbo or in the screens updates data through one of several different relationships.  It's not easy to tell through which one in the code.  By adding the Transactable object to operate on the object after the commit, the code can use whichever relationship is most appropriate to work on the data.


No comments:

Post a Comment