Chapter 12 Creating CORBA-Java Components
After the basic component implementation is in place, you can add code to perform the following advanced tasks:
Multiple instances of a component can read and update the same data--that is, share data. Only instances of the same component can share data. A component's shared data is contained in a shared object. Each piece of data is called a property and is identified by an index number. A shared object can contain any number of shared properties. An index number is an arbitrary integer that you assign to the property. Each component can have any number of properties. A property value does not persist after the server is shut down.
Because it is important to maintain the integrity of the shared data in properties, a single read or update operation on a property is atomic. Atomic means that an operation on data will complete before any other operations can access that data. Multiple reads and updates on a single property can be synchronized by locking the property.
For example, a counter that tracks how many objects have been created could be used as a shared property.
You cannot use shared variables in components that have the Automatic Failover option set, because these components cannot use local shared resources. See "Transactions tab component properties" for information on the Automatic Failover option. If you need to share data, you can store shared data in a remote database. See "Thread-safety features" for more information.
The programming sequence for implementing shared data for a component is:
You create shared objects and retrieve references to them by using the InstanceContext.getSharedObjects() method. If a shared object has already been created, this method retrieves a reference to the shared object.
This method is executed on an InstanceContext object. If your class implements the ServerBean interface, use the InstanceContext that is received as a parameter to the activate(InstanceContext, String) method. Otherwise, call the static Jaguar.getInstanceContext() method as in the example below:
InstanceContext DBctx = Jaguar.getInstanceContext();
SharedObjects sharedObj = DBctx.getSharedObjects();
You use the lock(int), lockNoWait(int), and unlock(int) methods to synchronize multiple updates to and reads from the same property value. Since a single read or update to a property is atomic, you do not have to lock a property for a single read or update operation. The lock(int) and lockNoWait(int) methods place advisory locks on properties. An advisory lock prevents another instance from locking the property but does not prevent another instance from using the get(int) and set(int, Object) methods to retrieve and update the property value.
If the property is locked, the lock(int) method waits for the lock to be released. The lockNoWait(int) method does not wait for the previous lock to be released, and execution immediately returns to the calling method. You lock a property before using the get(int) or set(int, Object) method to retrieve or update the property value. You can lock the same property more than once as long as all locks are executed from the same component instance. However, these multiple locks are not iterative and you only have to unlock the property once. You can lock a property that is not set.
The lockNoWait(int) method returns TRUE if the property was not locked and returns FALSE if the property was locked by another component instance. You can write code to respond to the return value.
Use the unlock(int) method to release a lock on a property that is locked by the same component instance. A locked property is automatically released when the component instance's method execution is completed. However, to make your application more efficient, unlock a property when you are finished updating or reading the property so that other component instances can access it right away.
In this example, a property with an index of 1 in the SharedObj shared object is locked. After reading or updating the property, it is unlocked.
sharedObj.lock(1);
...
...
sharedObj.unlock(1);
To retrieve a property value, retrieve an object reference to the property using the get(int) method and then assign the object reference to a variable with the desired datatype. get(int) takes an index that identifies the property of interest. If the property has not been initialized, the default value is null. Update the property by calling set(int, Object).
In this example, the get(int) method retrieves the object reference and assigns it to counterObj. counterObj is assigned to an intObj (with a cast). intObj is converted to the int primitive datatype and assigned to counter. After retrieval, the counter is incremented then the property is updated with the new value.
Object counterObj = sharedObj.get(1);
Integer intObj = (Integer) counterObj;
if (intObj == null)
counter = 0;
else
counter = intObj.intValue();
sharedObj.set(1, new Integer(counter + 1));
This example includes all the sample code from the preceding shared data sections.
import com.sybase.jaguar.beans.enterprise.*;
import com.sybase.jaguar.server.*;
public class JaguarBean implements ServerBean {
void countermethod () {
try {
InstanceContext ctx = Jaguar.getInstanceContext();
SharedObjects sharedObj = ctx.getSharedObjects();
sharedObj.lock(1);
Object counterObj = sharedObj.get(1);
Integer intObj = (Integer) counterObj;
if (intObj == null)
counter = 0;
else
counter = intObj.intValue();
sharedObj.set(1, new Integer(counter + 1));
sharedObj.unlock(1);
}
catch (SharedObjectException except) {
...
}
}
}
You must use a proxy to issue intercomponent calls. If you call methods in another Java component directly, Jaguar transactions and security will not work. Also, many of the Jaguar classes such as SharedObjects and InstanceContext will not work correctly in the called component if you do not invoke methods through a stub.
To invoke other components, instantiate a proxy (stub) object for the second component, then use the stub to invoke methods on the component.
To invoke methods in other components, create an ORB instance to obtain proxy objects for other components, then invoke methods on the object references. You obtain object references for other components on the same server by invoking string_to_object with the IOR string specified as Package/Component. For example, the fragment below obtains a proxy object for a component SessionInfo that is installed in the CtsSecurity package.
java.util.Properties props = new java.util.Properties();
props.put("org.omg.CORBA.ORBClass",
"com.sybase.CORBA.ORB");
ORB orb = ORB.init((java.lang.String[])null, props);
SessionInfo sessInfo =
SessionInfoHelper.narrow
(orb.string_to_object(
"CtsSecurity/SessionInfo"));
Components that were developed for Jaguar version 1.1 use the Jaguar 1.1stub interface to instantiate stubs for intercomponent calls. Appendix C, "Creating Jaguar 1.1 Java Clients" describes how to instantiate stubs in this client model.
For new development, Sybase recommends the CORBA style of instantiation for intercomponent calls. It is much simpler and your component implementation is independent of the listener port addresses for the server on which it is deployed.
When instantiating a Jaguar 1.1 stub for intercomponent calls, the following restrictions apply:
Your component may need to invoke methods on a component hosted by another vendor's CORBA server-side ORB. Sybase recommends that Java components use the Jaguar client-side ORB for all IIOP connections made from Jaguar components. See "Connecting to third-party ORBs using the Jaguar client ORB" for more information.
If your Java methods connect to remote data servers, you should use Jaguar's connection caching feature to improve performance. See Chapter 28, "Using Connection Management" for more information.
Jaguar's transactional model works only with connections obtained from the Jaguar Connection Manager. Connections that you open yourself will not be able to participate in Jaguar transactions.
Using the JDBC API, a Java component can retrieve result sets from a database. Using classes in the com.sybase.jaguar.sql package, Java components can also send these result sets to the caller. A Java component can combine the data from several result sets retrieved from databases and send that data as a single result set to a Java client. A Java component can also forward the original result set retrieved from a database.
To learn how to return result sets, see "Sending result sets with Java".
Clients can connect to a secure IIOP port using an SSL client certificate. You can issue intercomponent calls to the built-in CtsSecurity/SessionInfo component to retrieve the client certificate data, including:
This component implements CtsSecurity::SessionInfo IDL interface. HTML documentation is available for the interface in the html/ir subdirectory of your Jaguar installation. You can view it by loading the main Jaguar HTML page, then clicking the "Interface Repository" link.
The CtsSecurity::UserCredentials interface is deprecated The CtsSecurity::UserCredentials interface, which is implemented by the CtsSecurity/UserCredentials component, has been replaced by the CtsSecurity::SessionInfo interface, which provides additional functionality such as certificate parsing. Jaguar supports the CtsSecurity::UserCredentials interface for backwards compatibility. Please use the interface CtsSecurity::SessionInfo if developing new components.
The transactional state of a component instance determines:
You can set transactional state explicitly in your class implementation, or you can set the Auto demarcation/deactivation option in the Component Properties window. See "Transactions tab component properties" for information on this property.
To explicitly set transactional state, each method must call one of the jaguar.beans.enterprise.InstanceContext methods to describe the component's transactional state. Even if your component is not transactional, you should call one of these methods to explicitly specify whether the instance should be deactivated.
In classes that implement the ServerBean interface, the activate method receives a new InstanceContext object each time that Jaguar calls the ServerBean activate method. In classes that do not implement the ServerBean interface, call Jaguar.getInstanceContext() in each method that sets transactional state (do not save the object across method invocations, because it will not be valid if the component instance has been deactivated and reactivated).
To set transaction state, choose the method that reflects the state of the work that the component is contributing to the transaction, as follows:
For nontransactional components, either completeWork() or rollbackWork() deactivates the component instance. To keep the instance active, call continueWork().
Copyright © 2000 Sybase, Inc. All rights reserved. |