|
|
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
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());
}
}
}
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.