JBoss.orgCommunity Documentation
This example illustrates the concepts and the implementation details for a simple client/server example using implicit context propagation and indirect context management.
This example only includes a single unit of work within the scope of the transaction. consequently, only a one-phase commit is needed.
The client and server processes are both invoked using the implicit propagation
and
interposition
command-line options.
For the purposes of this worked example, a single method implements the
DemoInterface
interface. This method is used in the DemoClient program.
Example 6.1. idl interface
#include <idl/CosTransactions.idl>
#pragma javaPackage ""
module Demo
{
exception DemoException {};
interface DemoInterface : CosTransactions::TransactionalObject
{
void work() raises (DemoException);
};
};
This section deals with the pieces needed to implement the example interface.
The example overrides the methods of the Resource
implementation class. The
DemoResource
implementation includes the placement of
System.out.println
statements at judicious points, to highlight when a particular
method is invoked.
Only a single unit of work is included within the scope of the transaction. Therefore, the
prepare
or commit
methods should never be invoked, but the
commit_one_phase
method should be invoked.
Example 6.2. DemoResource
1 import org.omg.CosTransactions.*;
2 import org.omg.CORBA .SystemException;
3
4 public class DemoResource extends org.omg.CosTransactions .ResourcePOA
5 {
6 public Vote prepare() throws HeuristicMixed, HeuristicHazard,
7 SystemException
8 {
9 System.out.println("prepare called");
10
11 return Vote.VoteCommit;
12 }
13
14 public void rollback() throws HeuristicCommit, HeuristicMixed,
15 HeuristicHazard, SystemException
16 {
17 System.out.println("rollback called");
18 }
19
20 public void commit() throws NotPrepared, HeuristicRollback,
21 HeuristicMixed, HeuristicHazard, SystemException
22 {
23 System.out.println("commit called");
24 }
25
26 public void commit_one_phase() throws HeuristicHazard, SystemException
27 {
28 System.out.println("commit_one_phase called");
29 }
30
31 public void forget() throws SystemException
32 {
33 System.out.println("forget called");
34 }
35 }
At this stage, the Demo.idl
has been processed by the ORB’s idl compiler to generate the
necessary client and server package.
Line 14 returns the transactional context for the Current
pseudo object. After
obtaining a Control
object, you can derive the Coordinator object (line 16).
Lines 17 and 19 create a resource for the transaction, and then inform the ORB that the resource is ready to receive incoming method invocations.
Line 20 uses the Coordinator
to register a DemoResource
object
as a participant in the transaction. When the transaction terminates, the resource receives requests to commit
or rollback the updates performed as part of the transaction.
Example 6.3. Transactional implementation
1 import Demo.*;
2 import org.omg.CosTransactions.*;
3 import com.arjuna.ats.jts.*;
4 import com.arjuna.orbportability.*;
5
6 public class DemoImplementation extends Demo.DemoInterfacePOA
7 {
8 public void work() throws DemoException
9 {
10 try
11 {
12
13 Control control = OTSManager.get_current().get_control();
14
15 Coordinator coordinator = control.get_coordinator();
16 DemoResource resource = new DemoResource();
17
18 ORBManager.getPOA().objectIsReady(resource);
19 coordinator.register_resource(resource);
20
21 }
22 catch (Exception e)
23 {
24 throw new DemoException();
25 }
26 }
27
28 }
First, you need to to initialize the ORB and the POA. Lines 10 through 14 accomplish these tasks.
The servant class DemoImplementation
contains the implementation code for the
DemoInterface
interface. The servant services a particular client request. Line
16 instantiates a servant object for the subsequent servicing of client requests.
Once a servant is instantiated, connect the servant to the POA, so that it can recognize the invocations on it, and pass the invocations to the correct servant. Line 18 performs this task.
Lines 20 through to 21 registers the service through the default naming mechanism. More information about the options available can be found in the ORB Portability Guide.
If this registration is successful, line 23 outputs a sanity check
message.
Finally, line 25 places the server process into a state where it can begin to accept requests from client processes.
Example 6.4. DemoServer
1 import java.io.*;
2 import com.arjuna.orbportability.*;
3
4 public class DemoServer
5 {
6 public static void main (String[] args)
7 {
8 try
9 {
10 ORB myORB = ORB.getInstance("test").initORB(args, null);
11 RootOA myOA = OA.getRootOA(myORB).myORB.initOA();
12
13 ORBManager.setORB(myORB);
14 ORBManager.setPOA(myOA);
15
16 DemoImplementation obj = new DemoImplementation();
17
18 myOA.objectIsReady(obj);
19
20 Services serv = new Services(myORB);
21 serv.registerService(myOA.corbaReference(obj), "DemoObjReference", null);
22
23 System.out.println("Object published.");
24
25 myOA.run();
26 }
27 catch (Exception e)
28 {
29 System.err.println(e);
30 }
31 }
32 }
After the server compiles, you can use the command line options defined below to start a server process. By
specifying the usage of a filter on the command line, you can override settings in the
TransactionService.properties
file.
if you specify the interposition filter, you also imply usage of implicit context propagation.
The client, like the server, requires you to first initialize the ORB and the POA. Lines 14 through 18 accomplish these tasks.
After a server process is started, you can obtain the object reference through the default publication
mechanism used to publish it in the server. This is done in lines 20 and 21. Initially the reference is an
instance of Object
. However, to invoke a method on the servant object, you need to
narrow this instance to an instance of the DemoInterface
interface. This is
shown in line 21.
Once we have a reference to this servant object, we can start a transaction (line 23), perform a unit of work (line 25) and commit the transaction (line 27).
Example 6.5. DemoClient
1 import Demo.*;
2 import java.io.*;
3 import com.arjuna.orbportability.*;
4 import com.arjuna.ats.jts.*;
5 import org.omg.CosTransactions.*;
6 import org.omg.*;
7
8 public class DemoClient
9 {
10 public static void main(String[] args)
11 {
12 try
13 {
14 ORB myORB = ORB.getInstance("test").initORB(args, null);
15 RootOA myOA = OA.getRootOA(myORB).myORB.initOA();
16
17 ORBManager.setORB(myORB);
18 ORBManager.setPOA(myOA);
19
20 Services serv = new Services(myORB);
21 DemoInterface d = (DemoInterface) DemoInterfaceHelper.narrow(serv.getService("DemoObjReference"));
22
23 OTS.get_current().begin();
24
25 d.work();
26
27 OTS.get_current().commit(true);
28 }
29 catch (Exception e)
30 {
31 System.err.println(e);
32 }
33 }
34 }
The sequence diagram illustrates the method invocations that occur between the client and server. The following aspects are important:
You do not need to pass the transactional context as a parameter in method work
,
since you are using implicit context propagation.
Specifying the use of interposition when the client and server processes are started, by using appropriate filters and interceptors, creates an interposed coordinator that the servant process can use, negating any requirement for cross-process invocations. The interposed coordinator is automatically registered with the root coordinator at the client.
The resource that commits or rolls back modifications made to the transactional object is associated, or registered, with the interposed coordinator.
The commit
invocation in the client process calls the root coordinator. The root
coordinator calls the interposed coordinator, which in turn calls the
commit_one_phase
method for the resource.
The server process first stringifies the servant instance, and writes the servant IOR to a temporary file. The first line of output is the sanity check that the operation was successful.
In this simplified example, the coordinator object has only a single registered resource. Consequently, it
performs a commit_one_phase
operation on the resource object, instead of performing a
prepare
operation, followed by a commit
or
rollback
.
The output is identical, regardless of whether implicit context propagation or interposition is used, since interposition is essentially performance aid. Ordinarily, you may need to do a lot of marshaling between a client and server process.
These settings are defaults, and you can override them at run-time by using property variables, or in the
properties file in the etc/
directory of the installation.
Unless a CORBA object is derived from
CosTransactions::TransactionalObject
,you do not need to propagate any
context. In order to preserve distribution transparency, JBossTS defaults to always propagating a
transaction context when calling remote objects, regardless of whether they are marked as transactional
objects. You can override this by setting the
com.arjuna.ats.jts.alwaysPropagateContext
property variable to NO
.
If an object is derived from CosTransactions::TransactionalObject
, and no
client context is present when an invocation is made, JBossTS transmits a null context. Subsequent
transactions begun by the object are top-level. If a context is required, then set the
com.arjuna.ats.jts.needTranContext
property variable to YES
, in which
case JBossTS raises the TransactionRequired
exception.
JBossTS needs a persistent object store, so that it can record information about transactions in the event of
failures. If all transactions complete successfully, this object store has no entries. The default location
for this must be set using the ObjectStoreEnvironmentBean.objectStoreDir
variable in the
properties file.
If you use a separate transaction manager for Current
, its location is obtained
from the CosServices.cfg
file. CosServices.cfg
is located at runtime
by the OrbPortabilityEnvironmentBean
properties initialReferencesRoot
and initialReferencesFile
. The former is a directory, defaulting to the current working
directory. The latter is a file name, relative to the directory. The default value is
CosServices.cfg
.
Checked transactions are not enabled by default. This means that threads other than the transaction creator may
terminate the transaction, and no check is made to ensure all outstanding requests have finished prior to
transaction termination. To override this, set the JTSEnvironmentBean.checkedTransactions
property variable to YES
.
As of JBossTS 4.5, transaction timeouts are unified across all transaction components and are controlled by ArjunaCore. The old JTS configuration property com.arjuna.ats.jts.defaultTimeout still remains but is deprecated.
if a value of 0
is specified for the timeout of a top-level transaction, or no timeout is
specified, JBossTS does not impose any timeout on the transaction. To override this default timeout, set the
CoordinatorEnvironmentBean.defaultTimeout
property variable to the required timeout value
in seconds.