Example: Implementing methods from the Compensable interface

The CompensableCommand interface declares the getCompensatingCommand method that the application programmer must implement.

Method from the CompensableCommand interface in the ModifyCheckingAccountCmdImpl class

The following code example shows the implementation for the ModifyCheckingAccountCmd command. The implementation simply returns an instance of the ModifyCheckingAccountCompensatorCmd command that is associated with the current command.

public class ModifyCheckingAccountCmdImpl extends TargetableCommandImpl
implements ModifyCheckingAccountCmd
{
...
// Method from CompensableCommand interface
public Command getCompensatingCommand() throws CommandException {
modifyCheckingAccountCompensatorCmd =
new ModifyCheckingAccountCompensatorCmd(this);
return (Command)modifyCheckingAccountCompensatorCmd;
}
}

Writing the compensating command

An application that uses a compensable command requires two separate commands: the primary command (declared as a CompensableCommand) and the compensating command. In the example application, the primary command is declared in the ModifyCheckingAccountCmd interface and implemented in the ModifyCheckingAccountCmdImpl class. Because this command is also a compensable command, there is a second command associated with it that is designed to undo its work. When you create a compensable command, you also have to write the compensating command.

Writing a compensating command can require exactly the same steps as writing the original command: writing the interface and providing an implementation class. In some cases, it may be simpler. For example, the command to compensate for the ModifyCheckingAccountCmd does not require any methods beyond those defined for the original command, so it does not need an interface. The compensating command, called ModifyCheckingAccountCompensatorCmd, simply needs to be implemented in a class that extends the TargetableCommandImpl class. This class must:
  • Provide a way to instantiate the command; the example uses a constructor.
  • Implement the three required methods: isReadyToCallExecute and reset—both from the Command interface and performExecute—from the TargetableCommand interface.
The following code example shows the structure of the implementation class, its variables (references to the original command and to the relevant checking account), and the constructor. The constructor simply instantiates the references to the primary command and account.
...
public class ModifyCheckingAccountCompensatorCmd extends TargetableCommandImpl
{
public ModifyCheckingAccountCmdImpl modifyCheckingAccountCmdImpl;
public CheckingAccount checkingAccount;
public ModifyCheckingAccountCompensatorCmd(
ModifyCheckingAccountCmdImpl originalCmd)
{
// Get an instance of the original command
modifyCheckingAccountCmdImpl = originalCmd;
// Get the relevant account
checkingAccount = originalCmd.getCheckingAccount();
}
// Methods from the Command and Targetable Command interfaces
....
}

The performExecute method verifies that the actual checking-account balance is consistent with what the original command returns. If so, it replaces the current balance with the previously stored balance by using the ModifyCheckingAccountCmd command. Finally, it saves the most-recent balances in case the compensating command needs to be undone. The reset method has no work to do.

The following code example shows the implementation of the inherited methods. The implementation of the isReadyToCallExecute method ensures that the checkingAccount variable has been instantiated.
...
public class ModifyCheckingAccountCompensatorCmd extends TargetableCommandImpl
{
// Variables and constructor
....
// Methods from the Command and TargetableCommand interfaces
public boolean isReadyToCallExecute() {
if (checkingAccount != null)
return true;
else
return false;
}
public void performExecute() throws CommandException
{
try {
ModifyCheckingAccountCmdImpl originalCmd =
modifyCheckingAccountCmdImpl;
// Retrieve the checking account modified by the original command
CheckingAccount checkingAccount = originalCmd.getCheckingAccount();
if (modifyCheckingAccountCmdImpl.balance ==
checkingAccount.getBalance()) {
// Reset the values on the original command
checkingAccount.setBalance(originalCmd.oldBalance);
float temp = modifyCheckingAccountCmdImpl.balance;
originalCmd.balance = originalCmd.oldBalance;
originalCmd.oldBalance = temp;
}
else {
// Balances are inconsistent, so we cannot compensate
throw new CommandException(
"Object modified since this command ran.");
}
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
public void reset() {}
}



Related tasks
Implementing command interfaces
Reference topic Reference topic    

Terms and conditions for information centers | Feedback

Last updatedLast updated: Aug 31, 2013 1:23:07 AM CDT
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=pix&product=was-nd-dist&topic=rcmd_compensablecmdint
File name: rcmd_compensablecmdint.html