Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

J2SE 1.4 breathes new life into the CORBA community, Part 3

Create enterprise-level apps with the POA

  • Print
  • Feedback

Page 4 of 7

For multithreaded systems, the POA makes several guarantees to prevent race situations from occurring. For example, at any given instant, either the incarnate() or etherialize() method (but not both) will execute on a given servant activator. Additionally, only one thread can execute inside a servant activator at any given time. And finally, if a servant is being etherialized, all requests for that servant will queue up until the etherialize() method completes.

Here is an example servant activator implementation that registers with the AccountPOA:

package bank;
import org.omg.CORBA.*;
import org.omg.PortableServer.*;
public class AccountServerActivatorImpl extends org.omg.PortableServer.ServantActivatorPOA
{
  public Servant incarnate(byte[] oid, POA adapter) throws ForwardRequest
  {
    // First check the DB to make sure account exists.
    // Then create an accountimpl and return.
    System.out.println("(AccountServerActivatorImpl) Returning an Account Object for account number " 
                         + new String(oid));
    try
    {
      DBUtils.getBalance(new String(oid));
    }
    catch(Exception e)
    {
      System.out.println("(AccountServerActivatorImpl) Oops... Invalid account number " 
                         + new String(oid));
      throw new org.omg.CORBA.OBJECT_NOT_EXIST();
    }
    return new AccountImpl(new String(oid));
  }
  public void etherealize(byte[] oid, POA adapter, Servant serv,
          boolean cleanup_in_progress, boolean remaining_activations)
  {
  }
}


The etherealize() method does nothing since no cleanup is necessary. Remember the closeAccount() method in the bank servant: it calls the static removeAccount() method on DBUtils. Could I have put the removeAccount() method call in the etherialize() method? That way, when the deactivate_object() call eventually leads to the etherealize() call, the account information would drop from the database. Assuming that I could live with the latency in the account removal, that approach would be perfect, right? No, not really; because object deactivation is not the only time etherealize() is called. etherealize() will also be called when AccountPOA is shutting down, and we definitely don't want to delete all the accounts when AccountPOA shuts down!

In addition to the etherealize() method, all servant activators must implement an incarnate() method. In our case, incarnate() checks to see if the account exists in the database, and, if the check passes, it creates an account servant instance (shown below) and returns it to the POA. As mentioned before, the POA will add this reference to the active object map and forward the client request to it.

// The account servant implementation
package bank;
public class AccountImpl extends bank.AccountPOA
{
  private String _accNum;
  public AccountImpl(String accNum)
  {
    this._accNum = accNum;
  }
  public float balance()
  {
    try
    {
      return DBUtils.getBalance(_accNum);
    }
    catch(Exception e)
    {
      return (float)-1.0;
    }
  }
  public String accountNumber()
  {
    return _accNum;
  }
  public bank.AccountType accountType ()
  {
    try
    {
      return DBUtils.getAccountType(_accNum);
    }
    catch(Exception e)
    {
      return AccountType.NIL;
    }
  }
  public void deposit (float amt) throws bank.InvalidOperationException, bank.UnknownException
  {
    if(amt <= (float)0.0)
     throw new InvalidOperationException("Invalid deposit amount of " + amt + " dollars.");
    float balance = balance();
    if(balance < 0)
      throw new bank.UnknownException("Could not retrieve balance for Account " + _accNum);
    balance += amt;
    try
    {
      DBUtils.setBalance(_accNum,balance);
    }
    catch(Exception e)
    {
      throw new bank.UnknownException(e.getMessage());
    }
  }
  public void withdraw (float amt) throws bank.InvalidOperationException, bank.UnknownException
  {
    if(amt <= (float)0.0)
     throw new InvalidOperationException("Invalid withdrawal amount of " + amt + " dollars.");
    float balance = balance();
    if(balance < 0)
      throw new bank.UnknownException("Could not retrieve balance for Account " + _accNum);
    if(amt > balance)
      throw new InvalidOperationException("Cannot withdraw more than account balance.");
    balance = balance() - amt;
    // Update the balance
    try
    {
      DBUtils.setBalance(_accNum,balance);
    }
    catch(Exception e)
    {
      throw new bank.UnknownException(e.getMessage());
    }
  }
}


Use a servant locator

When the POA has the NON_RETAIN policy, it uses servant managers called servant locators. Remember, the NON_RETAIN policy implies that the POA will not maintain the association between the servant instance and an activated object in the active object map. When the POA receives a request, it will extract the object ID from the request and always invoke the preinvoke() method on the registered servant locator. preinvoke() returns a servant to the POA, and the POA forwards the request to that servant. Once the request processes, the POA invokes the postinvoke() method on the servant locator, passing in the servant as one of the parameters. postinvoke() performs any clean up, and the servant ceases to exist as far as the POA is concerned.

  • Print
  • Feedback

Resources