Table of Contents
This chapter describes the transaction manager and its surrounding elements in JEUS.
The JEUS transaction manager provides various forms of transaction services to applications in the Java EE environment. The JEUS transaction manager provides services according to an application's operation requirements and connections to various resource managers. Furthermore, an application can either assign the control of a transaction to the manager or take the control of the transaction itself as needed. The transaction manager plays a central role in the transaction processing tasks working with the resource manager, application, etc.
In enterprise systems, a transaction service is the basic and important service that safely and efficiently processes large scale client requests for resources. Recently, as the types and scale of resource requests have increased, there is a need for the transaction manager to provide a unified interface and operate more safely.
The JEUS transaction manager provides compatibility with Java Transaction Service (JTS) and supports Java Transaction API (JTA). This is to provide a unified interface and functions for a client to use a transaction. For more information, refer to related API or specification documents. Transaction service is provided in many situations (clients and server applications) where an application can be used to support various forms of applications.
To provide stable services, the transaction manager must ensure the integrity of transactions even when a problem occurs. JEUS transaction manager provides transaction recovery functions that can recover transactions under various error conditions.
The following are the three elements that participate in JEUS transaction processing.
An application that receives a service
An application can access various resources through a web container, EJB container, or client container. The application itself can control the transaction by specifying the start and the end of a transaction, or the container's transaction manager can control the transaction.
The transaction management function of the application and the transaction manager that provides the transaction management interface.
The transaction manager is divided into the server transaction manager and the client transaction manager depending on where the application is running. It directly sends a request to prepare and apply a transaction to the actual resource manager.
The resource manager (e.g., database) which is affected by the actual transaction.
The resource manager accepts a request and processes it.
Each component uses JTA (standard API) for transaction processing to communicate with other components.
This section describes each component and its operation method. For basic information about transactions, refer to the related books or materials.
An application uses JEUS transaction manager to perform transaction related tasks on the resource manager.
Transaction tasks that use a single resource manager can be grouped into a single local transaction. An application starts or ends a local transaction by using the resource manager driver.
By default, JEUS transaction manager is not involved in a local transaction processing. An application can process a task as a global transaction, but when processing a simple transaction task that uses a single resource manager, it is recommended to use a local transaction which is significantly more efficient.
When an application attempts a sequence of transaction tasks using two or more resource managers, the transaction manager can group the tasks into a single global transaction. A global transaction often uses the 2 phase commit protocol to perform transaction batch jobs of the resources in use.
When the transaction manager commits a transaction, it traces the execution flow of the application and decides to perform either 1 phase commit or 2 phase commit. This decision is made according to the number and type of the resource managers used in the transaction. A JEUS transaction does not support duplicate transactions, and does not allow the mixing of two or more transactions.
An application can specify the start and end of a transaction by using the javax.transaction.UserTransaction object. The decision to commit or rollback a transaction is made entirely by an application. However, even when a commit is executed, JEUS transaction manager can still perform a rollback if the resource manager is unable to process the transaction.
In an EJB, this user managed transaction is called a Bean-Managed Transaction (BMT).
In a container managed transaction, the container decides the start and end of a transaction.
The commit, rollback, etc. of the transaction are decided entirely by the container. This transaction can only be used in an EJB by specifying the transaction attributes (NotSupported, Required, Supports, RequiresNew, Mandatory, Never) according to each bean's method.
Either a local transaction or global transaction can be used depending on how many resource managers an application uses. In addition, the configuration and application programming methods depend on which agent has the authority over the transactions.
JEUS provides two transaction managers, the server transaction manager and client transaction manager.
The server transaction manager provides all functions for managing a global transaction, while the client transaction manager only acts as the proxy of a server transaction.
The server transaction manager implements all of the Java Transaction API and is used when a server application uses a transaction.
When a global transaction is started, the server transaction manager collects all the information related to the global transaction and proceeds with the tasks acting as the transaction coordinator. Depending on the situation, the role of the server transaction manager consists of the root coordinator and sub coordinator.
Root coordinator
The transaction manager that starts the transaction. The manager where the transaction is propagated to becomes the sub coordinator.
Sub coordinator
Receives commands from the root coordinator to perform tasks. The root coordinator takes an active role in managing transactions, and the sub coordinator takes a passive role.
The client transaction manager operates as the proxy of the server transaction manager.
The server transaction manager that receives the signal from a global transaction becomes the root coordinator and collects and processes all information related to the transaction. To commit the transaction, the transaction manager sends the commit signal to the root coordinator and receives the result of the commit.
Applications can perform tasks with various resource managers. Connection managers manage connections to the resource manager.
JEUS provides four types of connection managers (JDBC Connection Manager, JMS Connection Manager, WebT Connection Manager, and Connector Manager). Connection managers report transaction related information to the transaction manager for processing a global transaction.
JDBC Resource Manager
Java Database Connectivity (JDBC) defines the connection between databases and applications for Java-based application development. Applications look up and use the JDBC resource manager from the naming server. For more information, refer to "Chapter 4. JNDI Naming Server" and "Chapter 6. DB Connection Pool and JDBC".
JMS Resource Manager
Java Message Service (JMS) is the specification that defines the queue and topic and the API used for accessing the message saved in them. For more information, refer to "JEUS MQ Guide" or the JMS specification.
Tmax (WebT) Resource Manager
Tmax is a TP-monitor developed by TmaxSoft. In JEUS, a bridge called WebT is provided for a transparent two-way service with the Tmax transaction manager. Since WebT supports a two-way call, general EJB clients can run on Tmax, and the same method can be used to call an EJB Bean on JEUS.
Java Connector Architecture (JCA) Resource Manager
As one of the JavaEE specifications, JCA provides an integrated mechanism of the JavaEE compatible platform and various EISs (Enterprise Information System). By using a connector that supports XA Transactions, an application can handle various transaction tasks as a single global transaction. For more information, refer to "JEUS JCA Guide".
This section describes how to configure JEUS transaction manager.
JEUS users can make various selections through the configurations. The configuration items greatly influence JEUS transaction manager's performance and operation. Therefore, the user should be familiarized with each item to set an appropriate value for each.
The transaction manager configurations can be set in WebAdmin or the console tool, and any additional settings can be configured as system properties.
The following describes the process of changing the configurations in WebAdmin.
Select [Servers] from the left menu of WebAdmin to go to the server list search screen.
To dynamically change the configuration, click [Lock & Edit]. For more information about the configuration modes in WebAdmin, refer to JEUS WebAdmin Guide".
Select a server on the screen to go to the server configuration screen. Select the [Basic] > [Tm Config] menu on the server configuration screen to go to the TM Config screen.
Change the transaction configuration, and click [OK]. Click [Apply Changes] from the left menu to apply the changes.
In JEUS transaction manager, a multiple number of worker threads are used to support communication with other transaction managers. The transaction manager uses the system thread pool on the server by default. The thread pool can be configured on a server where transaction and fast processing is important.
Common Thread Pool
If there are not too many but a constant level of transactions that occur and faster processing than other services is required, then use the system thread pool, which is shared by all services on the server.
The public thread pool can separately assign the thread count that can only be used by the transaction manager, in the 'Reserved Thread Num' item. The number of reserved threads for the transaction manager must be set by considering the size of the entire thread pool to make sure that it doesn't cause problems for other services.
Dedicated Thread Pool
When there are a lot of transactions and if the load fluctuates a lot, it is better to create and use a dedicated thread for the transaction manager instead of the system thread. Since the configurations for the thread pool are the same as those of the system thread pool, refer to "2.3.3. Thread Pool Configuration".
As previously described, the system thread pool or dedicated thread pool can be selected for use. However, the pool type cannot be changed during server operation. The server must be restarted to apply the modified pool type. However, with the exception of the dedicated thread pool's queue size, the pool configurations can all be dynamically changed without restarting the server.
The following describes the process of changing a thread pool in WebAdmin. The thread pool configuration can be changed in the lower part of the screen. To configure a thread pool, check the Pooling checkbox.
Configuring a Common Thread Pool
Select Pooling checkbox to configure a common thread pool. Then, set the Reserved Thread Num, and then click [OK].
Configuring a Dedicated Thread Pool
Select Dedicated to configure a dedicated thread pool. Enter the required items and then click [OK].
The following describes how to change a thread pool by using the console tool.
Common thread pool configuration
Execute modify-system-thread-pool to separately assign a number of threads from the thread pool to the transaction manager.
[DAS]domain1.adminServer>modify-system-thread-pool server1 -service transaction
-reservednum 10
Successfully performed the MODIFY operation for the transaction thread pool of the
server (server1).
Check the results using "show-system-thread-pool server1 -service transaction or
modify-system-thread-pool server1 -service transaction"
Dedicated thread pool configuration
Execute modify-service-thread-pool to use a dedicated thread for the transaction manager.
If the dedicated thread pool is configured while using the system thread pool, the server must be restarted to apply the changed configuration. If only the attributes are changed while using the dedicated thread pool, then the configuration can be applied dynamically without restarting the server.
[DAS]domain1.adminServer>modify-service-thread-pool server1 -service transaction
-min 10 -max 20
Successfully performed the MODIFY operation for The transaction thread pool of the
server (server1), but all changes were non-dynamic. They will be applied after
restarting.
Check the results using "show-service-thread-pool server1 -service transaction or
modify-service-thread-pool server1 -service transaction"
For more information about the commands, refer to JEUS Reference Book. "4.2.5.2. modify-service-thread-pool".
The JEUS transaction manager uses various timeout mechanisms for processing exceptions. The transaction manager can be tuned to be suitable for the application system by adjusting the timeout mechanism. The timeout configuration is static and requires a server restart. The configuration must be set before starting the server or the server must be restarted if it is changed while the server is running.
The following describes how to change the timeout setting in WebAdmin. A multiple number of timeout configurations can be changed from the bottom section of the Tm Config screen.
The following tables describe the configuration items.
Basic information
Advanced Options
The following describes how to change the timeout setting in the console tool.
The transaction manager's timeout setting can be changed by executing modify-transaction-manager. For more information about the command, refer to JEUS Reference Book. "4.2.12.1. modify-transaction-manager".
[DAS]domain1.adminServer>modify-transaction-manager server1 -activeTimeout 20000
Successfully performed the MODIFY operation for transaction of server (server1), but all changes were non-dynamic. They will be applied after restarting.
Check the results using "show-transaction-manager server1 or modify-transaction-manager server1"
The transaction manager is divided into the root coordinator and sub coordinator depending on its role. Since the sub coordinator gets transaction-related information from the root coordinator, it must register itself with the root coordinator and make sure that the root coordinator knows that the sub coordinator exists.
The configuration consists of the following two system properties. The user should set the properties carefully by keeping performance and safety in mind.
-Djeus.tm.forcedReg=<true or false>
Determines when the sub coordinator registers itself with the root coordinator.
Configuration Value | Description |
---|---|
true | Sub coordinator immediately registers itself when a transaction is transmitted. (default value) |
false | Sub coordinator registers itself when the resource manager connected to the sub coordinator is actually used. If set to false, the communication count between transaction managers can be reduced when there are a lot of EJB calls that do not use the resource manager registered with the sub coordinator. |
-Djeus.tm.checkReg=<true or false>
Configuration Value | Description |
---|---|
true | When the sub coordinator registers itself, it waits for an ACK from the root coordinator. If the ACK doesn't arrive within the time frame, the registration is considered as failed and any pending transactions are rolled back. (default value) |
false | When the sub coordinator registers itself, it doesn't wait for an ACK from the root coordinator. Therefore, when the registration fails due to a problem such as a network error, the sub coordinator is not notified of the problem and thus an error occurs during the commit operation. |
JEUS transaction manager joins the transaction resources of the same resource manager. This allows tasks to be performed without creating additional transaction branches and decreases the overhead. However, this method can be a problem in situations such as when Oracle OCI is used like RAC.
To prepare for such problems, set the following option to "true".
-Djeus.tm.disableJoin=true
The client transaction manager is created to allow a client application to start and end global transactions. This section describes the configurations that are related to the client.
Since the client application doesn't use the configurations in domain.xml, it adds the configuration in the application start script by using the system property format.
The client transaction manager is initialized when the client application performs a JNDI lookup. However, depending on the client application, there are situations when the transaction manager is not used. To remove any additional overhead that occurs in such situation, the following information is saved in the start script.
-Djeus.tm.not_use=true
The client transaction manager is only used in the client container. By default, the transaction manager is used in the client, but to use the server transaction manager in the client, add the following setting to the client application script. For information about the difference between the server transaction manager and client transaction manager, refer to
"7.1.2. JEUS Transaction Manager".
-Djeus.tm.version=server
The client transaction manager uses the TCP/IP port to communicate with other transaction managers.
The client transaction manager automatically finds and uses the appropriate port. To manually set the configuration, add the following setting to the client application script.
-Djeus.tm.port=<port number>
The worker thread pool setting configures the worker thread pool information.
Min
To configure this value in the client transaction manager to the number of worker threads created in the pool, add the following setting to the client start script.
-Djeus.tm.tmMin=<number of threads>
Max
To configure this value in the client transaction manager to the maximum number of threads created in the pool, add the following setting to the client start script.
-Djeus.tm.tmMax=<number of threads>
The following describes how to configure the transaction manager from a client.
Active Timeout
Timeout to commit from the start of a global transaction. If the time expires, the transaction is forcibly rolled back. (Default Value: 600000 (10min), Unit: ms)
Add the following setting to the client application script to configure this value in the client container.
-Djeus.tm.activeto=<time in milliseconds>
Prepare Timeout
The root coordinator must receive a 'prepare' signal from the sub coordinator and resource manager within this time. (Default value: 120000 (2min), Unit: ms)
If the signal is not received, then the root coordinator rolls back the global transaction.
Add the following setting to the client application script to configure this value in the client container.
-Djeus.tm.preparedto=<time in milliseconds>
Prepared Timeout
The sub coordinator must receive a global decision on whether to commit or rollback from its root coordinator within this time. (Default value: 60000 (1min), Unit: ms)
If not received within this timeout, then the sub-coordinator sends another response message for 'prepare' to the root coordinator. If it receives no global decision during the next timeout period, then it rolls back the global transaction.
Add the following setting to the client application script to configure this value in the client container.
-Djeus.tm.preparedto=<time in milliseconds>
Commit Timeout
The root coordinator receives a commit or rollback response from the sub coordinator and resource manager within this time. (Default value: 240000 (4min), Unit: ms)
If not received within this timeout, then the root coordinator records the global transaction in the "Uncompleted List" to indicate that the transaction has not been completed.
Add the following setting to the client application script to configure this value in the client container.
-Djeus.tm.committo=<time in milliseconds>
Recovery Timeout
Timeout to receive the recovery information. To recover a transaction, the transaction manager attempts to obtain the transaction information. (Default Value: 120000 (2min), Unit:ms)
The transaction is rolled back if another transaction manager does not send the recovery information within this time.
Add the following setting to the client application script to configure this value in the client container.
-Djeus.tm.recoveryto=<time in milliseconds>
Uncompleted Timeout
To complete the entire transaction processing, the transaction manager maintains a list of failed global transactions. The incomplete global transaction information is used during recovery processing and is kept until the timeout expires. Therefore, if the timeout is too short, the recovery information will be deleted more frequently, and the transaction manager won't be able to recover the integrity of the global transaction. As a result, the system administrator must process many tasks in order to recover a global transaction. (Default value: 86400000 (1day), Unit: ms)
Add the following setting to the client application script to configure this value in the client container.
-Djeus.tm.uncompletedto=<time in milliseconds>
This section describes some JEUS transaction programming examples.
The following are the 4 programming patterns.
Local transaction
Client-managed transaction
Bean-managed transaction
Container-managed transaction
Users and application programmers must first specify in what form the application is to run before starting to program. This will allow them to achieve the expected results and easily resolve any problems that may occur later.
An application can manage transaction tasks as a single transaction. A local transaction is used if a single resource manager can process the tasks. Otherwise, a global transaction must be used to manage the transaction.
Using a local transaction is an effective way to manage the transaction tasks of a single resource manager. Since a local transaction is light and fast, it is used whenever possible. The local transaction has nothing to do with JEUS transaction manager and can use all types of containers.
The following is an example of using a local transaction. Although it is a Java application, some of the code can be used in other Java EE programs such as a servlet or EJB.
[Example 7.1] <<Client.java>>
import javax.naming.*; import javax.rmi.PortableRemoteObject; import java.util.*; import javax.transaction.UserTransaction; import java.sql.*; import javax.sql.*; public class Client { private static Connection con; private static Connection getConnection() throws NamingException, SQLException { // get a JDBC connection } private static String insertCustomer(String id, String name, String phone) throws NamingException, SQLException { // insert a product entity given by the arguments to DB } private static void deleteCustomer(String id) throws NamingException, SQLException { // delete a product entity given by the arguments from DB } public static void main(String[] args) { try { // get a JDBC connection con = getConnection(); // set the autocommit attribute as false con.setAutoCommit(false); // insert customers for (int i=0 ; i<number/2 ; i++) { System.out.println("inserting customer id="+i+"c... from Client"); customers[i] = insertCustomer(i+"c", "Hong Kil Dong "+i, "000-123-1234-"+i); } System.out.println("completed inserting customers!!"); con.commit(); // delete customers for (int i=0 ; i<number/2 ; i++) { System.out.println( "deleting customerid="+customers[i]+" ... from Client"); deleteCustomer(customers[i]); } System.out.println("completed deleting customers!!"); con.commit(); } catch (NamingException ne) { System.out.println("Naming Exception caught : " + ne.getMessage()); } catch (SQLException sqle) { System.out.println("SQL Exception caught : " + sqle.getMessage()); } catch(Exception e) { try { con.rollback(); } catch (Exception ee) { System.out.println("Transaction Rollback error : " + ee.getMessage()); } System.out.println("Error caught : " + e.getMessage()); e.printStackTrace(); } finally { try { if (con!=null) con.close(); } catch (SQLException se) {} } } }
A global transaction can be used in an application of a client container (client managed transaction). The client itself manages transactions by using UserTransaction and calls EJB to process the actual task.
The following is an example of this.
Before starting a global transaction, import a javax.transaction.UserTransaction instance by looking up 'java:comp/UserTransaction'. After starting a global transaction by calling 'begin' on the instance, call the EJB bean multiple times. To commit the transaction task on the EJB Bean, call the commit method of the UserTransaction instance to notify that the transaction is complete.
The method terminates if the transaction is successfully committed. If the global transaction is not committed due to a failure, then an exception is thrown in the method. The javax.transaction.RollbackException is thrown by JEUS transaction manager to guarantee that the global transaction is rolled back. There are also other exceptions that are thrown to notify that JEUS transaction manager is attempting to rollback the global transaction due to an unexpected exception. However, not all transaction tasks of the global transaction are completely rolled back. The rollback method of the UserTransaction instance is called directly from the catch query to roll back the global transaction.
Since a standalone client does not include the concept of components, it supports 'java:/UserTransaction' in order to use another name to lookup 'java:comp/UserTransaction' in the standalone client. In practice, either java:comp/UserTransaction or java:/UserTransaction can be used to look up transactions.
[Example 7.2] <<Client.java>>
package umt; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.rmi.PortableRemoteObject; import java.util.*; import javax.transaction.UserTransaction; public class Client { public static void main(String[] args) { UserTransaction tx = null; try { InitialContext initial = new InitialContext(); ProductManager productManager = (ProductManager)initial.lookup("productmanager"); System.out.println(""); System.out.println("< Testing ProductManager EJBBean " + "Using User Managed Transaction >>"); System.out.println(""); int number = 10; String products[] = new String[number]; tx = (UserTransaction)initial.lookup("java:comp/UserTransaction"); tx.begin(); // insert products for (int i=0 ; i<number/2 ; i++) { System.out.println("inserting product id="+i+"b..."); // bean call products[i] = productManager.insertProduct(i+"b","ball pen", i*10); } for (int i=number/2 ; i<number ; i++) { System.out.println("inserting product id="+i+"f..."); products[i] = productManager.insertProduct(i+"f", "fountain pen", (i-number/3)*50); } System.out.println("completed inserting products!!"); // delete products for (int i=0 ; i<number ; i++) { System.out.println("deleting productid="+products[i]+" ..."); productManager.deleteProduct(products[i]); // bean call } System.out.println("completed deleting products!!"); tx.commit(); } catch (javax.transaction.SystemException se) { System.out.println("Transaction System Error caught : " + se.getMessage()); } catch (javax.transaction.RollbackException re) { System.out.println("Transaction Rollback Errorcaught : " + re.getMessage()); } catch(Exception e) { try { tx.rollback(); } catch (Exception ee) { System.out.println("Transaction Rollback error : " + ee.getMessage()); } System.out.println("Error caught : " + e.getMessage()); e.printStackTrace(); } } } }
The following EJB bean implements a method that executes transaction tasks. To manage global transactions in a client, the transaction type of EJB must be CMT (container-managed). Since the default value is CMT, no configuration is required. To change the configuration, change the TransactionManagerType setting as shown in the following example.
[Example 7.3] <<ProductManagerEJB.java>>
package umt;
import javax.ejb.*;
import javax.annotation.*;
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class ProductManagerEJB implements ProductManager {
....
public String insertProduct(String id, String name, double price) {
// insert a product entity given by the arguments to DB
}
public void deleteProduct(String id) {
// delete a product entity indicated by the argument from
// DB
}
.....
}
A bean managed transaction uses JTA in an application of a web container and EJB container to explicitly mark the boundaries of a global transaction. It is useful when the application needs to fine-tune the global transaction. The application can decide to rollback and commit on its own since client requests can be processed according to the execution order.
The following is an example of an application executing a global transaction in the EJB container.
In a BMT (Bean-Managed Transaction), an EJB bean processes the global transaction area. Hence, a client simply needs to call the method that performs the transaction tasks.
[Example 7.4] <<Client.java>>
package bmt; import javax.naming.*; import javax.rmi.PortableRemoteObject; import java.util.*; public class Client { public static void main(String[] args) { try { ProductManager productManager; ....... // Getting a reference to an instance of // ProductManager EJB bean. ....... productManager.transactionTest(); } catch(Exception e) { e.printStackTrace(); } } }
An EJB bean uses javax.transaction.UserTransaction to start a global transaction. It uses javax.ejb.EJBContext (since EJB is a Session Bean in this example, javax.ejb.SessionContext is used) to get a UserTransaction instance. The global transaction begins and commits through a method call.
For an EJB to run as a bean managed transaction, the TransactionManagement must be set to 'TransactionManagementType.BEAN' using an annotation.
[Example 7.5] <<ProductManagerEJB.java>>
package bmt; import javax.ejb.*; import javax.naming.*; import java.sql.*; import java.util.*; import javax.annotation.*; import javax.transaction.UserTransaction; @Stateless @TransactionManagement(TransactionManagementType.BEAN) public class ProductManagerEJB implements ProductManager { @Resource SessionContext ejbContext; public void transactionTest() { UserTransaction tx = null; try { int number = 20; String products[] = new String[number]; tx = ejbContext.getUserTransaction(); tx.begin(); // insert products for (int i=0 ; i<number/2 ; i++) { System.out.println("inserting product id="+i+"b ..."); products[i] = insertProduct(i+"b", "ball pen", i*10); } for (int i=number/2 ; i<number ; i++) { System.out.println("inserting product id="+i+"f..."); products[i] = insertProduct( i+"f", "fountain pen", (i-number/3)*50); } System.out.println("completed inserting products!!"); // delete products for (int i=0 ; i<number ; i++) { System.out.println("deleting product id="+products[i]+" ..."); deleteProduct(products[i]); } System.out.println("completed deleting products!!"); tx.commit(); } catch (javax.transaction.SystemException se) { throw new EJBException( "Transaction System Error caught : " + se.getMessage()); } catch (javax.transaction.RollbackException re) { throw new EJBException( "Transaction Rollback Error caught : " + re.getMessage()); } catch(Exception e) { try { tx.rollback(); } catch (Exception ee) { throw new EJBException( "Transaction Rollback error : " + ee.getMessage()); } throw new EJBException("Error caught : " + e.getMessage()); } } private String insertProduct(String id, String name, double price) throws NamingException, SQLException { // insert a product entity given by the arguments to DB } private void deleteProduct(String id) throws NamingException, SQLException { // delete a product entity indicated by the argument from // DB } // some EJB callback methods }
According to the Java EE specification, an application can delegate the demarcation of a global transaction to a container. A Web or EJB container manages the global transactions related to the method. An application can configure the transaction attributes for each method in the configuration file. This is the easiest way to process a global transaction.
The following is an example of a global transaction managed by an EJB container.
In the following example, a server-side EJB container is managing the global transaction tasks of the EJB in a container managed transaction.
[Example 7.6] <<Client.java>>
package bmt; import javax.naming.*; import javax.rmi.PortableRemoteObject; import java.util.*; public class Client { public static void main(String[] args) { try { ProductManager productManager; // getting a reference to an instance of // ProductManager EJB bean. productManager.transactionTest(); } catch(Exception e) { e.printStackTrace(); } } }
The advantage of using a container-managed transaction is that it prevents the developer from implementing transaction-related codes in the business logic.
As long as appropriate attributes are set in the method of an EJB bean, global transaction related tasks are all delegated to the EJB container. In the following example, the transactionTest method does not contain any transaction related codes. To notify the EJB container to run the EJB Bean as a container managed transaction, either set the TransactionManagement Annotation to TransactionManagerType.CONTAINER or don't set it to anything.
[Example 7.7] <<ProductManagerEJB.java>>
package cmt;
import javax.ejb.*;
import javax.naming.*;
import java.sql.*;
import java.util.*;
import javax.annotation.*;
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class ProductManagerEJB implements ProductManager {
public void transactionTest() {
try {
int number = 20;
String products[] = new String[number];
// insert products
for (int i=0 ; i<number/2 ; i++) {
System.out.println("inserting product id="+i+"b...");
products[i] = insertProduct(i+"b", "ball pen", i*10);
}
for (int i=number/2 ; i<number ; i++) {
System.out.println("inserting product id="+i+"f...");
products[i] = insertProduct(i+"f", "fountain pen", (i-number/3)*50);
}
System.out.println("completed inserting products!!");
// delete products
for (int i=0 ; i<number ; i++) {
System.out.println("deleting product id="+products[i]+" ...");
deleteProduct(products[i]);
}
System.out.println("completed deleting products!!");
} catch(Exception e) {
throw new EJBException("Error caught : " + e.getMessage());
}
}
private String insertProduct(String id, String name, double price)
throws NamingException, SQLException {
// insert a product entity given by the arguments to DB
}
private void deleteProduct(String id) throws NamingException,
SQLException {
// delete a product entity indicated by the argument from
// DB
}
// some EJB callback methods
}
A transaction manager can be obtained by looking up the name of java:appserver/TransactionManager from the JNDI Context. A transaction manager can start and end a transaction and provide the function that registers an XAResource or gets a transaction object. For more information, refer to Java Transaction API (JTA) specification.
The method for getting a transaction manager or UserTransaction in JEUS is compatible with Glassfish or SunOne Application Server. Therefore, the same server configuration settings can be used when a 3rd-party library like Hibernate is used.
This section describes how to recover a transaction. Transaction recovery is an important function used for supporting transaction integrity when an unpredictable error occurs.
A transaction manager must have a recovery plan for failures that can happen during a transaction. The recovery plan is focused on guaranteeing the integrity of the transactions that were in progress. The recovery plan varies depending on whether the manager is the root coordinator or the sub coordinator, and whether tasks are performed with an external task manager instead of JEUS.
The following shows the recovery process of a transaction manager.
1, 2) When a transaction manager recovers from a failure, the manager gets transaction information from the transaction log.
3) Next, it sends the recover command to a resource manager according to the log information.
4) In response, the resource manager sends the XIDs of incomplete transactions to the manager.
5) The transaction manager sends a commit or rollback command to the resource manager by using the information gathered from the XIDs and logs.
The recovery method differs slightly according to the transaction manager's role, but overall it follows the aforementioned process. A brief description of each element that participates in the recovery and related configurations are described next.
The transaction manager plays a central role in the transaction recovery. The following describes how the recovery method differs according to the role of the transaction manager.
Root Coordinator
When the transaction manager is the root coordinator, it performs operations such as[Figure 7.5].
Sub Coordinator
The sub coordinator is registered like a single resource manager to the root coordinator.
Since all decisions come from the root coordinator, the sub coordinator only performs up to the task of getting the XIDs for the resource managers and log files that are registered to the sub coordinator. After this, the XIDs are sent to the root coordinator and waits for a decision. When the decision comes from the root coordinator, the information is sent to the resource manager and completes the recovery.
Working with an External Transaction Manager
JEUS transaction manager runs as the root coordinator and an external transaction manager recognizes JEUS as a single resource manager. In this case, JEUS transaction manager performs all tasks other than making the decision. Later, when the external transaction manager sends the recover command and decision, the recovery task is completed accordingly.
In an automatic transaction recovery, if the current transaction manager shuts down abnormally in a cluster environment, another server's transaction manager automatically recovers any "indoubt" transactions. To properly execute this function, servers must be in a cluster configuration and the server that is executing the recovery must be able to access the transaction log of the failed server.
The following describes the process of configuring the automatic transaction recovery by using WebAdmin or the console tool. This configuration is applied dynamically without restarting the server.
Using WebAdmin
Select [Servers] from the left menu of WebAdmin to go to the server list screen. Then, select a server to go to the server configuration screen.
Select [Tm Config] menu on the server configuration screen to go to the transaction configuration screen. Check the [Automatic Recovery] checkbox on the configuration screen, and then click [OK].
Using the Console Tool
Execute modify-transaction-manager in the console tool to turn on the automatic transaction recovery function. For more information about the command, refer to JEUS Reference Book. "4.2.12.1. modify-transaction-manager".
[DAS]domain1.adminServer>modify-transaction-manager server1 -automaticRecovery true
Successfully performed the MODIFY operation for transaction of server (server1), but all changes were non-dynamic. They will be applied after restarting.
Check the results using "show-transaction-manager server1 or modify-transaction-manager server1"
The following are the two types of log files that are used to recover transactions.
The log that contains the transaction history.
The log of the XA resource that was used.
The log file is created in a sub directory of 'SERVER_HOME/workspace/mlog' by default. For the path of SERVER_HOME, refer to "1.5. Directory Structure". The log file path can be changed as described in the following.
For example, a public directory can be designated if it is preferable to save a log to a location where many servers can access for automatic recovery. Back up the log and then restart JEUS if a recovery related problem occurs during operation due to a transaction that doesn't need recovery.
The following describes the process of configuring recovery related log files using WebAdmin or the console tool.
Using WebAdmin
Select [Servers] from the left menu of WebAdmin to go to the server list screen.
Select [Tm Config] on the server configuration screen to go to the transaction configuration screen. Configure the necessary information in the Advanced Options section, and then click [OK].
Using the console tool
The transaction log directory can be changed by using the modify-transaction-manager command of the console tool. For more information about the command, refer to JEUS Reference Book. "4.2.12.1. modify-transaction-manager".
[DAS]domain1.adminServer>modify-transaction-manager server1 -txLogDir /Users/user1/jeus/domain1/tmlogs
Successfully performed the MODIFY operation for transaction of server (server1) ,but ALL changes were non-dynamic. They will be applied after restarting.
Check the results using "show-transaction-manager server1 or modify-transaction-manager server1"
Recovery related configurations are listed in this section. They must be added to the server's JVM configuration as system properties. For information about how to add each configuration, refer to JEUS Domain Guide. "3.6.2. Changing a Server's JVM Settings".
Recovery logging can be blocked for when the system administrator is executing recovery or when performance improvement is needed.
-Djeus.tm.noLogging=true
If recovery fails due to a problem, then the transaction manager will attempt to recover the resource again. Recovery executes once every two minutes, and the user can designate the retry count.
Add the following property to the script to set the retry count. (Default Value: 30)
-Djeus.tm.recoveryTrial=<number of trial>
If there is a transaction that needs to be recovered when a server starts, recovery is performed before the server goes into STANDBY. If there's a failed resource during recovery, then recovery is reattempted in the background.
The retry interval can be configured. (Default Value: (120000) 2min)
-Djeus.tm.recoveryInterval=<time in milliseconds>
JEUS cannot boot if a TM log file is deleted and cannot be recovered. If recovery is not needed, JEUS detects the broken file and resets and deletes all TM log files for a successful startup. (Default Value: false)
-Djeus.tm.ignore.broken.log.file=<true or false>
When the resource manager fails, the system manager uses the console tool to manually perform recovery. This is because JEUS transaction manager cannot find out whether the resource manager is again in a state where it can perform transaction processing.
After resolving the problem with the resource manager, recovery is proceeded by executing the recover-transactions command in the console tool. For more information about using the console tool, refer to JEUS Reference Book. "4.2.12.2. recover-transactions".
JEUS transaction manager provides a function that can execute the user's callback at critical points during each transaction. It cannot be used on the client, and can only be used on the server.
This requires the implementation of a profile listener for users inheriting the following interface.
[Example 7.8] <<CoordinatorProfileListener.java>>
package jeus.transaction.profile;
import jeus.transaction.info.TransactionInfo;
public interface CoordinatorProfileListener extends ProfileListener {
public void beforePrepare( TransactionInfo info );
public void afterPrepare( jeus.transaction.info.TransactionInfo info );
public void beforeSetDecision( TransactionInfo info );
public void afterSetDecision( TransactionInfo info );
public void beforeCommit( TransactionInfo info );
public void afterCommit( TransactionInfo info );
public void beforeOnePhaseCommit( TransactionInfo info );
public void afterOnePhaseCommit( TransactionInfo info );
public void beforeRollback( TransactionInfo info );
public void afterRollback( jeus.transaction.info.TransactionInfo info );
public void beforeDestroy( TransactionInfo info );
public void afterDestroy( TransactionInfo info );
public void beforeActiveTimeout( TransactionInfo info );
public void afterActiveTimeout( TransactionInfo info );
}
[Example 7.9] <<TransactionInfo.java>>
package jeus.transaction.info;
import javax.transaction.xa.Xid;
public interface TransactionInfo {
public static final int JEUS_SPECIFIC_CURRENT_FORMAT_XID = 303077;
public static final int UNSPECIFIED_TIME = -1;
/**
* Returns this transaction's XID. The returned XID is an XID of
* the internal implementation of JEUS and is serializable.
* Hereafter, when expressing this XID as a string, use XidToString.getXidHexString().
*
* @return the TX's XID implementation
*/
public Xid getXid();
/**
* Returns the transaction manager information as a string. Through this information,
* the TX's TM server information (ip, port, etc.) can be known.
*
* @return the TX's transaction manager information.
*/
public String getCoordinator();
/**
* Returns an external XID for an externally initiated TX. The returned XID is replaced
* by an XID of the internal implementation of JEUS and is serializable.
*
* @return the TX's XID implementation
*/
public Xid getExternalXid();
/**
* Returns the active timeout setting in ms.
*
* @return the active timeout setting of the TX.
*/
public long getTimeout();
/**
* Returns the time elapsed since the start of the TX in ms.
*
* @return the elapsed time of the TX.
*/
public long getElapseSinceBegin();
/**
* Returns the TX's status as a string.
*
* @return the status value of the TX as a string.
*/
public String getStatus();
/**
* Returns the XAResources enlisted in the TX as a string.
*
* @return the XAResources enlisted in the TX.
*/
public String[] getXaResources();
/**
* Returns the thread that started the TX.
* This information cannot be obtained from where TX is propagted to.
*
* @return the thread that started the TX.
*/
public Thread getBeginThread();
}
The implemented listener is configured as a system property. A space, semi colon, or comma is used as a separator for multiple listener classes.
-Djeus.tm.profile.classes="test.profile.MyCoordinatorListener1,test.profile.MyCoordinatorListener2"
An IP address is used to connect between JEUS transaction managers for communication. However, communication may not be possible between JEUS transaction managers in the NAT and external environments due to different IP bands.
This can be resolved by setting the property that maps the real IP to a virtual IP.
Refer to 'JEUS_HOME/templates/nat.properties.template' when creating an IP mapping property and configure it as a system property as shown in the following example.
-Djeus.tm.net.address-mapping-properties=<full path of properties file>