Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Developer's Guide

- Previous: Part II Developing Applications and Application Components
- Next: Appendix A Deployment Descriptor Files

# Part III Using Services and APIs

# Chapter 11 Using the JDBC API for Database Access

This chapter describes how to use the JavaTM Database Connectivity (JDBCTM) API for database access with the Sun Java System Application Server. This chapter also provides high level JDBC implementation instructions for servlets and EJBTM components using the Application Server. The Application Server supports the JDBC 3.0 API, which encompasses the JDBC 2.0 Optional Package API.

The JDBC specifications are available at `http://java.sun.com/products/jdbc/download.html`.

A useful JDBC tutorial is located at `http://java.sun.com/docs/books/tutorial/jdbc/index.html`.

For explanations of two-tier and three-tier database access models, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

Note –

The Application Server does not support connection pooling or transactions for an application’s database access if it does not use standard J2EETM `DataSource` objects.

This chapter discusses the following topics:

- General Steps for Creating a JDBC Resource

- Creating Applications That Use the JDBC API

- Configurations for Specific JDBC Drivers

# General Steps for Creating a JDBC Resource

To prepare a JDBC resource for use in J2EE applications deployed to the Application Server, perform the following tasks:

- Integrating the JDBC Driver

- Creating a Connection Pool

- Testing a Connection Pool

- Creating a JDBC Resource

For information about how to configure some specific JDBC drivers, see the Configurations for Specific JDBC Drivers.

## Integrating the JDBC Driver

To use JDBC features, you must choose a JDBC driver to work with the Application Server, then you must set up the driver. This section covers these topics:

- Supported Database Drivers

- Making the JDBC Driver JAR Files Accessible

### Supported Database Drivers

Supported JDBC drivers are those that have been fully tested by Sun. For a list of the JDBC drivers currently supported by the Application Server, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Release Notes. For configurations of supported and other drivers, see Configurations for Specific JDBC Drivers.

Note –

Because the drivers and databases supported by the Application Server are constantly being updated, and because database vendors continue to upgrade their products, always check with Sun technical support for the latest database support information.

### Making the JDBC Driver JAR Files Accessible

To integrate the JDBC driver into a Application Server domain, copy the JAR files into the domain-dir`/lib/ext` directory, then restart the server. This makes classes accessible to any application or module across the domain. For more information about Application Server classloaders, see Classloaders.

## Creating a Connection Pool

When you create a connection pool that uses JDBC technology (a JDBC connection pool) in the Application Server, you can define many of the characteristics of your database connections.

You can create a JDBC connection pool in one of these ways:

- In the Administration Console, open the Resources component, open the JDBC component, and select Connection Pools. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

- Use the `asadmin create-jdbc-connection-pool` command. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual.

## Testing a Connection Pool

You can test a JDBC connection pool for usability in one of these ways:

- In the Administration Console, open the Resources component, open the JDBC component, select Connection Pools, and select the connection pool you want to test. Then select the Ping button in the top right corner of the page. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

- Use the `asadmin ping-connection-pool` command. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual

Both these commands fail and display an error message unless they successfully connect to the connection pool.

For information about how to tune a connection pool, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Performance Tuning Guide.

## Creating a JDBC Resource

A JDBC resource, also called a data source, lets you make connections to a database using `getConnection()`. Create a JDBC resource in one of these ways:

- In the Administration Console, open the Resources component, open the JDBC component, and select JDBC Resources. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

- Use the `asadmin create-jdbc-resource` command. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual.

# Creating Applications That Use the JDBC API

An application that uses the JDBC API is an application that looks up and connects to one or more databases. This section covers these topics:

- Sharing Connections

- Obtaining a Physical Connection from a Wrapped Connection

- Using Non-Transactional Connections

- Using JDBC Transaction Isolation Levels

## Sharing Connections

When multiple connections acquired by an application use the same JDBC resource, the connection pool provides connection sharing within the same transaction scope. For example, suppose Bean A starts a transaction and obtains a connection, then calls a method in Bean B. If Bean B acquires a connection to the same JDBC resource with the same sign-on information, and if Bean A completes the transaction, the connection can be shared.

Connections obtained through a resource are shared only if the resource reference declared by the J2EE component allows it to be shareable. This is specified in a component’s deployment descriptor by setting the `res-sharing-scope` element to `Shareable` for the particular resource reference. To turn off connection sharing, set `res-sharing-scope` to `Unshareable`.

For general information about connections and JDBC URLs, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

## Obtaining a Physical Connection from a Wrapped Connection

The `DataSource` implementation in the Application Server provides a `getConnection` method that retrieves the JDBC driver’s `SQLConnection` from the Application Server’s `Connection` wrapper. The method signature is as follows:

    public java.sql.Connection getConnection(java.sql.Connection con)
    throws java.sql.SQLException

For example:

    InitialContext ctx = new InitialContext();
    com.sun.appserv.DataSource ds = (com.sun.appserv.DataSource)
       ctx.lookup("jdbc/MyBase");
    Connection con = ds.getConnection();
    Connection drivercon = ds.getConnection(con);
    // Do db operations.
    con.close();

## Using Non-Transactional Connections

The `DataSource` implementation in the Application Server provides a `getNonTxConnection` method, which retrieves a JDBC connection that is not in the scope of any transaction. There are two variants, as follows:

    public java.sql.Connection getNonTxConnection() throws java.sql.SQLException

    public java.sql.Connection getNonTxConnection(String user, String password)
    throws java.sql.SQLException

Another way to get a non-transactional connection is to create a resource with the JNDI name ending in `__nontx`. This forces all connections looked up using this resource to be non transactional.

Typically, a connection is enlisted in the context of the transaction in which a `getConnection` call is invoked. However, a non-transactional connection is not enlisted in a transaction context even if a transaction is in progress.

The main advantage of using non-transactional connections is that the overhead incurred in enlisting and delisting connections in transaction contexts is avoided. However, use such connections carefully. For example, if a non-transactional connection is used to query the database while a transaction is in progress that modifies the database, the query retrieves the unmodified data in the database. This is because the in-progress transaction hasn’t committed. For another example, if a non-transactional connection modifies the database and a transaction that is running simultaneously rolls back, the changes made by the non-transactional connection are not rolled back.

Here is a typical use case for a non-transactional connection: a component that is updating a database in a transaction context spanning over several iterations of a loop can refresh cached data by using a non-transactional connection to read data before the transaction commits.

## Using JDBC Transaction Isolation Levels

For general information about transactions, see Chapter 12, Using the Transaction Serviceand the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide. For information about last agent optimization, which can improve performance, see Transaction Scope.

Not all database vendors support all transaction isolation levels available in the JDBC API. The Application Server permits specifying any isolation level your database supports. The following table defines transaction isolation levels.

Table 11–1 Transaction Isolation Levels

Transaction Isolation Level | Description
--- | ---
`TRANSACTION_READ_UNCOMMITTED` | Dirty reads, non-repeatable reads and phantom reads can occur.
`TRANSACTION_READ_COMMITTED` | Dirty reads are prevented; non-repeatable reads and phantom reads can occur.
`TRANSACTION_REPEATABLE_READ` | Dirty reads and non-repeatable reads are prevented; phantom reads can occur.
`TRANSACTION_SERIALIZABLE` | Dirty reads, non-repeatable reads and phantom reads are prevented.

Note that you cannot call `setTransactionIsolation()` during a transaction.

You can set the default transaction isolation level for a JDBC connection pool. For details, see Creating a Connection Pool.

To verify that a level is supported by your database management system, test your database programmatically using the `supportsTransactionIsolationLevel()` method in `java.sql.DatabaseMetaData`, as shown in the following example:

    java.sql.DatabaseMetaData db;
    if (db.supportsTransactionIsolationLevel(TRANSACTION_SERIALIZABLE)
       { Connection.setTransactionIsolation(TRANSACTION_SERIALIZABLE); }

For more information about these isolation levels and what they mean, see the JDBC 3.0 API specification.

Note –

Applications that change the isolation level on a pooled connection programmatically risk polluting the pool, which can lead to errors.

# Configurations for Specific JDBC Drivers

Application Server 8.1 is designed to support connectivity to any database management system with a corresponding JDBC driver. The following JDBC driver and database combinations are supported. These combinations have been tested with Application Server 8.1 and are found to be J2EE compatible. They are also supported for CMP.

- PointBase Type 4 Driver

- Sun Java System JDBC Driver for DB2 Databases

- Sun Java System JDBC Driver for Oracle 8.1.7 and 9.x Databases

- Sun Java System JDBC Driver for Microsoft SQL Server Databases

- Sun Java System JDBC Driver for Sybase Databases

- IBM DB2 8.1 Type 2 Driver

- JConnect Type 4 Driver for Sybase ASE 12.5 Databases

For an up to date list of currently supported JDBC drivers, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Release Notes.

Other JDBC drivers can be used with Application Server 8.1, but J2EE compliance tests have not been completed with these drivers. Although Sun offers no product support for these drivers, Sun offers limited support of the use of these drivers with Application Server 8.1.

- Inet Oraxo JDBC Driver for Oracle 8.1.7 and 9.x Databases

- Inet Merlia JDBC Driver for Microsoft SQL Server Databases

- Inet Sybelux JDBC Driver for Sybase Databases

- Oracle Thin Type 4 Driver for Oracle 8.1.7 and 9.x Databases

- OCI Oracle Type 2 Driver for Oracle 8.1.7 and 9.x Databases

- IBM Informix Type 4 Driver

- MM MySQL Type 4 Driver

- CloudScape 5.1 Type 4 Driver

For details about how to integrate a JDBC driver and how to use the Administration Console or the command line interface to implement the configuration, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

Note –

An Oracle database user running the `capture-schema` command needs ANALYZE ANY TABLE privileges if that user does not own the schema. These privileges are granted to the user by the database administrator. For information about `capture-schema`, see Using the capture-schema Utility.

## PointBase Type 4 Driver

The PointBase JDBC driver is included with the Application Server by default, except for the Solaris bundled installation, which does not include PointBase. Therefore, unless you have the Solaris bundled installation, you do not need to integrate this JDBC driver with the Application Server.

PointBase is intended for evaluation use only, not for production or deployment use.

The JAR file for the PointBase driver is `pbclient.jar`.

Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `PointBase`

- DataSource Classname:Specify one of the following:

      com.pointbase.jdbc.jdbcDataSource
      com.pointbase.xa.xaDataSource

- Properties:

  - `user` - Specify the database user.

  - `password` - Specify the database password.

  - `databaseName` - Specify the URL of the database. The syntax is as follows:

        jdbc:pointbase:server://server:port/dbname,new

## Sun Java System JDBC Driver for DB2 Databases

The JAR files for this driver are `smbase.jar`, `smdb2.jar`, and `smutil.jar`. Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `DB2`

- DataSource Classname: `com.sun.sql.jdbcx.db2.DB2DataSource`

- Properties:

  - `serverName` - Specify the host name or IP address of the database server.

  - `portNumber` - Specify the port number of the database server.

  - `databaseName` - Set as appropriate.

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

- URL: `jdbc:sun:db2://`serverName`:`portNumber`;databaseName=`databaseName

## Sun Java System JDBC Driver for Oracle 8.1.7 and 9.x Databases

The JAR files for this driver are `smbase.jar`, `smoracle.jar`, and `smutil.jar`. Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `Oracle`

- DataSource Classname: `com.sun.sql.jdbcx.oracle.OracleDataSource`

- Properties:

  - `serverName` - Specify the host name or IP address of the database server.

  - `portNumber` - Specify the port number of the database server.

  - `SID` - Set as appropriate.

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

- URL: `jdbc:sun:oracle://`serverName`[:`portNumber`][;SID=`databaseName`]`

## Sun Java System JDBC Driver for Microsoft SQL Server Databases

The JAR files for this driver are `smbase.jar`, `smsqlserver.jar`, and `smutil.jar`. Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `mssql`

- DataSource Classname: `com.sun.sql.jdbcx.sqlserver.SQLServerDataSource`

- Properties:

  - `serverName` - Specify the host name or IP address and the port of the database server.

  - `portNumber` - Specify the port number of the database server.

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

  - `selectMethod` - Set to `cursor`.

- URL: `jdbc:sun:sqlserver://`serverName`[:`portNumber`]`

## Sun Java System JDBC Driver for Sybase Databases

The JAR files for this driver are `smbase.jar`, `smsybase.jar`, and `smutil.jar`. Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `Sybase`

- DataSource Classname: `com.sun.sql.jdbcx.sybase.SybaseDataSource`

- Properties:

  - `serverName` - Specify the host name or IP address of the database server.

  - `portNumber` - Specify the port number of the database server.

  - `databaseName` - Set as appropriate. This is optional.

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

- URL: `jdbc:sun:sybase://`serverName`[:`portNumber`]`

## IBM DB2 8.1 Type 2 Driver

The JAR files for the DB2 driver are `db2jcc.jar`, `db2jcc_license_cu.jar`, and `db2java.zip`. Set environment variables as follows:

    LD_LIBRARY_PATH=/usr/db2user/sqllib/lib:${j2ee.home}/lib
    DB2DIR=/opt/IBM/db2/V8.1
    DB2INSTANCE=db2user
    INSTHOME=/usr/db2user
    VWSPATH=/usr/db2user/sqllib
    THREADS_FLAG=native

Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `DB2`

- DataSource Classname: `com.ibm.db2.jcc.DB2SimpleDataSource`

- Properties:

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

  - `databaseName` - Set as appropriate.

  - `driverType` - Set to `2`.

  - `deferPrepares` - Set to `false`.

## JConnect Type 4 Driver for Sybase ASE 12.5 Databases

The JAR file for the Sybase driver is `jconn2.jar`. Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `Sybase`

- DataSource Classname:Specify one of the following:

      com.sybase.jdbc2.jdbc.SybDataSource
      com.sybase.jdbc2.jdbc.SybXADataSource

- Properties:

  - `serverName` - Specify the host name or IP address of the database server.

  - `portNumber` - Specify the port number of the database server.

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

  - `databaseName` - Set as appropriate. Do not specify the complete URL, only the database name.

  - `BE_AS_JDBC_COMPLIANT_AS_POSSIBLE` - Set to `true`.

  - `FAKE_METADATA` - Set to `true`.

## Inet Oraxo JDBC Driver for Oracle 8.1.7 and 9.x Databases

The JAR file for the Inet Oracle driver is `Oranxo.jar`. Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `Oracle`

- DataSource Classname: `com.inet.ora.OraDataSource`

- Properties:

  - `user` - Specify the database user.

  - `password` - Specify the database password.

  - `serviceName` - Specify the URL of the database. The syntax is as follows:

        jdbc:inetora:server:port:dbname

    For example:

        jdbc:inetora:localhost:1521:payrolldb

    In this example,`localhost` is the host name of the machine running the Oracle server, `1521` is the Oracle server’s port number, and `payrolldb` is the SID of the database. For more information about the syntax of the database URL, see the Oracle documentation.

  - `serverName` - Specify the host name or IP address of the database server.

  - `port` - Specify the port number of the database server.

  - `streamstolob` - If the size of BLOB or CLOB data types exceeds 4 KB and this driver is used for CMP, this property must be set to `true`.

  - `xa-driver-does-not-support-non-tx-operations` - Set to the value `true`. Optional: only needed if both non-XA and XA connections are retrieved from the same connection pool. Might degrade performance.

    As an alternative to setting this property, you can create two connection pools, one for non-XA connections and one for XA connections.

## Inet Merlia JDBC Driver for Microsoft SQL Server Databases

The JAR file for the Inet Microsoft SQL Server driver is `Merlia.jar`. Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `mssql`

- DataSource Classname: `com.inet.tds.TdsDataSource`

- Properties:

  - `serverName` - Specify the host name or IP address and the port of the database server.

  - `port` - Specify the port number of the database server.

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

## Inet Sybelux JDBC Driver for Sybase Databases

The JAR file for the Inet Sybase driver is `Sybelux.jar`. Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `Sybase`

- DataSource Classname: `com.inet.syb.SybDataSource`

- Properties:

  - `serverName` - Specify the host name or IP address of the database server.

  - `portNumber` - Specify the port number of the database server.

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

  - `databaseName` - Set as appropriate. Do not specify the complete URL, only the database name.

## Oracle Thin Type 4 Driver for Oracle 8.1.7 and 9.x Databases

The JAR file for the Oracle driver is `ojdbc14.jar`. Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `Oracle`

- DataSource Classname:Specify one of the following:

      oracle.jdbc.pool.OracleDataSource
      oracle.jdbc.xa.client.OracleXADataSource

- Properties:

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

  - `URL` - Specify the complete database URL using the following syntax:

        jdbc:oracle:thin:[user/password]@host[:port]/service

    For example:

        jdbc:oracle:thin:@localhost:1521:customer_db

  - `xa-driver-does-not-support-non-tx-operations` - Set to the value `true`. Optional: only needed if both non-XA and XA connections are retrieved from the same connection pool. Might degrade performance.

    As an alternative to setting this property, you can create two connection pools, one for non-XA connections and one for XA connections.

  Note –

  You must set the `oracle-xa-recovery-workaround` property in the Transaction Service for recovery of global transactions to work correctly. For details, see Transaction Scope.

  When using this driver, it is not possible to insert more than 2000 bytes of data into a column. To circumvent this problem, use the OCI driver (JDBC type 2).

## OCI Oracle Type 2 Driver for Oracle 8.1.7 and 9.x Databases

The JAR file for the OCI Oracle driver is `ojdbc14.jar`. Make sure that the shared library is available through LD_LIBRARY_PATH and that the ORACLE_HOME property is set. Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `Oracle`

- DataSource Classname:Specify one of the following:

      oracle.jdbc.pool.OracleDataSource
      oracle.jdbc.xa.client.OracleXADataSource

- Properties:

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

  - `URL` - Specify the complete database URL using the following syntax:

        jdbc:oracle:oci:[user/password]@host[:port]/service

    For example:

        jdbc:oracle:oci:@localhost:1521:customer_db

  - `xa-driver-does-not-support-non-tx-operations` - Set to the value `true`. Optional: only needed if both non-XA and XA connections are retrieved from the same connection pool. Might degrade performance.

    As an alternative to setting this property, you can create two connection pools, one for non-XA connections and one for XA connections.

## IBM Informix Type 4 Driver

Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `Informix`

- DataSource Classname:Specify one of the following:

      com.informix.jdbcx.IfxDataSource
      com.informix.jdbcx.IfxXADataSource

- Properties:

  - `serverName` - Specify the Informix database server name.

  - `portNumber` - Specify the port number of the database server.

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

  - `databaseName` - Set as appropriate. This is optional.

  - `IfxIFXHost` - Specify the host name or IP address of the database server.

## MM MySQL Type 4 Driver

Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `mysql`

- DataSource Classname: one of the following:

      com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
      com.mysql.jdbc.jdbc2.optional.MysqlXaConnectionPoolDataSource

- Properties:

  - `serverName` - Specify the host name or IP address of the database server.

  - `port` - Specify the port number of the database server.

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

  - `databaseName` - Set as appropriate.

  - `URL` - If you are using global transactions, you can set this property instead of `serverName`, `port`, and `databaseName`.

    The MM MySQL Type 4 driver doesn’t provide a method to set the required `relaxAutoCommit` property, so you must set it indirectly by setting the `URL` property:

        jdbc:mysql://host:port/database?relaxAutoCommit="true"

## CloudScape 5.1 Type 4 Driver

The JAR files for the CloudScape driver are `db2j.jar`, `db2jtools.jar`, `db2jcview.jar`, `jh.jar`, `db2jcc.jar`, and `db2jnet.jar`. Configure the connection pool using the following settings:

- Name: Use this name when you configure the JDBC resource later.

- Resource Type: Specify the appropriate value.

- Database Vendor: `Cloudscape`

- DataSource Classname: `com.ibm.db2.jcc.DB2DataSource`

- Properties:

  - `user` - Set as appropriate.

  - `password` - Set as appropriate.

  - `databaseName` - Set as appropriate.

# Chapter 12 Using the Transaction Service

The J2EE platform provides several abstractions that simplify development of dependable transaction processing for applications. This chapter discusses J2EE transactions and transaction support in the Sun Java System Application Server.

This chapter contains the following sections:

- Transaction Resource Managers

- Transaction Scope

- Configuring the Transaction Service

- Transaction Logging

For more information about the JavaTM Transaction API (JTA) and Java Transaction Service (JTS), see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide and the following sites: `http://java.sun.com/products/jta/` and `http://java.sun.com/products/jts/`.

You might also want to read the chapter on transactions in the J2EE 1.4 Tutorial at `http://java.sun.com/j2ee/1.4/docs/tutorial/doc/index.html`.

# Transaction Resource Managers

There are three types of transaction resource managers:

- Databases - Use of transactions prevents databases from being left in inconsistent states due to incomplete updates. For information about JDBC transaction isolation levels, see Using JDBC Transaction Isolation Levels.

  The Application Server supports a variety of JDBCTM XA drivers. For a list of the JDBC drivers currently supported by the Application Server, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Release Notes. For configurations of supported and other drivers, see Configurations for Specific JDBC Drivers.

- Java Message Service (JMS) Providers - Use of transactions ensures that messages are reliably delivered. The Application Server is integrated with Sun Java System Message Queue, a fully capable JMS provider. For more information about transactions and the JMS API, see Chapter 14, Using the Java Message Service.

- J2EETM Connector Architecture (CA) components - Use of transactions prevents legacy EIS systems from being left in inconsistent states due to incomplete updates. For more information about connectors, see Chapter 9, Developing Connectors.

For details about how transaction resource managers, the transaction service, and applications interact, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

Note –

In the Application Server, the transaction manager is a privileged interface. However, applications can access `UserTransaction`. For more information, see Naming Environment for J2EE Application Components.

# Transaction Scope

A local transaction involves only one non-XA resource and requires that all participating application components execute within one process. Local transaction optimization is specific to the resource manager and is transparent to the J2EE application.

In the Application Server, a JDBC resource is non-XA if it meets any of the following criteria:

- In the JDBC connection pool configuration, the DataSource class does not implement the `javax.sql.XADataSource` interface.

- The Global Transaction Support box is not checked, or the Resource Type setting does not exist or is not set to `javax.sql.XADataSource`.

A transaction remains local if the following conditions remain true:

- One and only one non-XA resource is used. If any additional non-XA resource is used, the transaction is aborted.

- No transaction importing or exporting occurs.

Transactions that involve multiple resources or multiple participant processes are distributed or global transactions. A global transaction can involve one non-XA resource if last agent optimization is enabled. Otherwise, all resourced must be XA. The `use-last-agent-optimization` property is set to `true` by default. For details about how to set this property, see Configuring the Transaction Service.

If only one XA resource is used in a transaction, one-phase commit occurs, otherwise the transaction is coordinated with a two-phase commit protocol.

A two-phase commit protocol between the transaction manager and all the resources enlisted for a transaction ensures that either all the resource managers commit the transaction or they all abort. When the application requests the commitment of a transaction, the transaction manager issues a `PREPARE_TO_COMMIT` request to all the resource managers involved. Each of these resources can in turn send a reply indicating whether it is ready for commit (`PREPARED`) or not (`NO`). Only when all the resource managers are ready for a commit does the transaction manager issue a commit request (`COMMIT`) to all the resource managers. Otherwise, the transaction manager issues a rollback request (`ABORT`) and the transaction is rolled back.

The Application Server provides workarounds for some known issues with the recovery implementations of the following JDBC drivers. These workarounds are used unless explicitly disabled.

- Oracle thin driver - The `XAResource.recover` method repeatedly returns the same set of in-doubt Xids regardless of the input flag. According to the XA specifications, the Transaction Manager initially calls this method with TMSTARTSCAN and then with TMNOFLAGS repeatedly until no Xids are returned. The `XAResource.commit` method also has some issues.

  To disable the Application Server workaround, set the `oracle-xa-recovery-workaround` property value to `false`. For details about how to set this property, see Configuring the Transaction Service.

Note –

These workarounds do not imply support for any particular JDBC driver.

# Configuring the Transaction Service

You can configure the transaction service in the Application Server in the following ways:

- To configure the transaction service using the Administration Console, open the Transaction Service component under the relevant configuration. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

- To configure the transaction service, use the `asadmin set` command to set the following attributes:

      server.transaction-service.automatic-recovery = false
      server.transaction-service.heuristic-decision = rollback
      server.transaction-service.keypoint-interval = 2048
      server.transaction-service.retry-timeout-in-seconds = 600
      server.transaction-service.timeout-in-seconds = 0
      server.transaction-service.tx-log-dir = domain-dir/logs

  You can also set these properties:

      server.transaction-service.property.oracle-xa-recovery-workaround = false
      server.transaction-service.property.disable-distributed-transaction-logging = false
      server.transaction-service.property.xaresource-txn-timeout = 600
      server.transaction-service.property.pending-txn-cleanup-interval = 60
      server.transaction-service.property.use-last-agent-optimization = true

  You can use the `asadmin get` command to list all the transaction service attributes and properties. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual.

# Transaction Logging

The transaction service writes transactional activity into transaction logs so that transactions can be recovered. You can control transaction logging in these ways:

- Set the location of the transaction log files using the Transaction Log Location setting in the Administration Console, or set the `tx-log-dir` attribute using the `asadmin set` command.

- Turn off transaction logging by setting the `disable-distributed-transaction-logging` property to `true`. Do this only if performance is more important than transaction recovery.

# Chapter 13 Using the Java Naming and Directory Interface

A naming service maintains a set of bindings, which relate names to objects. The J2EETM naming service is based on the Java Naming and Directory InterfaceTM (JNDI) API. The JNDI API allows application components and clients to look up distributed resources, services, and EJBTM components. For general information about the JNDI API, see `http://java.sun.com/products/jndi/`.

You can also see the JNDI tutorial at `http://java.sun.com/products/jndi/tutorial/`.

This chapter contains the following sections:

- Accessing the Naming Context

- Configuring Resources

- Mapping References

# Accessing the Naming Context

The Application Server provides a naming environment, or context, which is compliant with standard J2EE 1.4 requirements. A `Context` object provides the methods for binding names to objects, unbinding names from objects, renaming objects, and listing the bindings. The `InitialContext` is the handle to the J2EE naming service that application components and clients use for lookups.

The JNDI API also provides subcontext functionality. Much like a directory in a file system, a subcontext is a context within a context. This hierarchical structure permits better organization of information. For naming services that support subcontexts, the `Context` class also provides methods for creating and destroying subcontexts.

The rest of this section covers these topics:

- Naming Environment for J2EE Application Components

- Accessing EJB Components Using the CosNaming Naming Context

- Accessing EJB Components in a Remote Application Server

- Naming Environment for Lifecycle Modules

Note –

Each resource within a server instance must have a unique name. However, two resources in different server instances or different domains can have the same name.

## Naming Environment for J2EE Application Components

The namespace for objects looked up in a J2EE environment is organized into different subcontexts, with the standard prefix `java:comp/env`.

The following table describes standard JNDI subcontexts for connection factories in the Application Server.

Table 13–1 Standard JNDI Subcontexts for Connection Factories

Resource Manager | Connection Factory Type | JNDI Subcontext
--- | --- | ---
JDBCTM | `javax.sql.DataSource` | `java:comp/env/jdbc`
Transaction Service | `javax.transaction.UserTransaction` | `java:comp/UserTransaction`
JMS | `javax.jms.TopicConnectionFactory` `javax.jms.QueueConnectionFactory` | `java:comp/env/jms`
JavaMailTM | `javax.mail.Session` | `java:comp/env/mail`
URL | `java.net.URL` | `java:comp/env/url`
Connector | `javax.resource.cci.ConnectionFactory` | `java:comp/env/eis`

## Accessing EJB Components Using the CosNaming Naming Context

The preferred way of accessing the naming service, even in code that runs outside of a J2EE container, is to use the no-argument `InitialContext` constructor. However, if EJB client code explicitly instantiates an `InitialContext` that points to the CosNaming naming service, it is necessary to set these properties in the client JVM when accessing EJB components:

    -Djavax.rmi.CORBA.UtilClass=com.sun.corba.ee.impl.javax.rmi.CORBA.Util
    -Dorg.omg.CORBA.ORBClass=com.sun.corba.ee.impl.orb.ORBImpl
    -Dorg.omg.CORBA.ORBSingletonClass=com.sun.corba.ee.impl.orb.ORBSingleton
    -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory

## Accessing EJB Components in a Remote Application Server

The recommended approach for looking up an EJB component in a remote Application Server from a client that is a servlet or EJB component is to use the Interoperable Naming Service syntax. Host and port information is prepended to any global JNDI names and is automatically resolved during the lookup. The syntax for an interoperable global name is as follows:

    corbaname:iiop:host:port#a/b/name

This makes the programming model for accessing EJB components in another Application Server exactly the same as accessing them in the same server. The deployer can change the way the EJB components are physically distributed without having to change the code.

For J2EE components, the code still performs a `java:comp/env` lookup on an EJB reference. The only difference is that the deployer maps the `ejb-reference` element to an interoperable name in an Application Server deployment descriptor file instead of a simple global JNDI name.

For example, suppose a servlet looks up an EJB reference using `java:comp/env/ejb/Foo`, and the target EJB component has a global JNDI name of `a/b/Foo`.

The `ejb-ref` element in `sun-web.xml` looks like this:

    <ejb-ref>
       <ejb-ref-name>ejb/Foo</ejb-ref-name>
       <jndi-name>corbaname:iiop:host:port#a/b/Foo</jndi-name>
    <ejb-ref>

The code looks like this:

    Context ic = new InitialContext();
    Object o = ic.lookup("java:comp/env/ejb/Foo");

For a client that doesn’t run within a J2EE container, the code just uses the interoperable global name instead of the simple global JNDI name. For example:

    Context ic = new InitialContext();
    Object o = ic.lookup("corbaname:iiop:host:port#a/b/Foo");

Objects stored in the interoperable naming context and component-specific (`java:comp/env`) naming contexts are transient. On each server startup or application reloading, all relevant objects are re-bound to the namespace.

## Naming Environment for Lifecycle Modules

Lifecycle listener modules provide a means of running short or long duration Java-based tasks within the application server environment, such as instantiation of singletons or RMI servers. These modules are automatically initiated at server startup and are notified at various phases of the server life cycle. For details about lifecycle modules, see Chapter 10, Developing Lifecycle Listeners.

The configured properties for a lifecycle module are passed as properties during server initialization (the `INIT_EVENT`). The initial JNDI naming context is not available until server initialization is complete. A lifecycle module can get the `InitialContext` for lookups using the method `LifecycleEventContext.``getInitialContext()` during, and only during, the `STARTUP_EVENT`, `READY_EVENT`, or `SHUTDOWN_EVENT` server life cycle events.

# Configuring Resources

The Application Server exposes the following special resources in the naming environment. Full administration details are provided in the following sections:

- External JNDI Resources

- Custom Resources

## External JNDI Resources

An external JNDI resource defines custom JNDI contexts and implements the `javax.naming.spi.InitialContextFactory` interface. There is no specific JNDI parent context for external JNDI resources, except for the standard `java:comp/env/`.

Create an external JNDI resource in one of these ways:

- To create an external JNDI resource using the Administration Console, open the Resources component, open the JNDI component, and select External Resources. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

- To create an external JNDI resource, use the `asadmin create-jndi-resource` command. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual.

## Custom Resources

A custom resource specifies a custom server-wide resource object factory that implements the `javax.naming.spi.ObjectFactory` interface. There is no specific JNDI parent context for external JNDI resources, except for the standard `java:comp/env/`.

Create a custom resource in one of these ways:

- To create a custom resource using the Administration Console, open the Resources component, open the JNDI component, and select Custom Resources. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

- To create a custom resource, use the `asadmin create-custom-resource` command. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual.

# Mapping References

The following XML elements map JNDI names configured in the Application Server to resource references in application client, EJB, and web application components:

- `resource-env-ref` - Maps the `resource-env-ref` element in the corresponding J2EE XML file to the absolute JNDI name configured in the Application Server.

- `resource-ref` - Maps the `resource-ref` element in the corresponding J2EE XML file to the absolute JNDI name configured in the Application Server.

- `ejb-ref` - Maps the `ejb-ref` element in the corresponding J2EE XML file to the absolute JNDI name configured in the Application Server.

JNDI names for EJB components must be unique. For example, appending the application name and the module name to the EJB name is one way to guarantee unique names. In this case, `mycompany.pkging.pkgingEJB.MyEJB` would be the JNDI name for an EJB in the module `pkgingEJB.jar`, which is packaged in the `pkging.ear` application.

These elements are part of the `sun-web-app.xml`, `sun-ejb-ref.xml`, and `sun-application-client.xml` deployment descriptor files. For more information about how these elements behave in each of the deployment descriptor files, see Appendix A, Deployment Descriptor Files.

The rest of this section uses an example of a JDBC resource lookup to describe how to reference resource factories. The same principle is applicable to all resources (such as JMS destinations, JavaMail sessions, and so on).

The `resource-ref` element in the `sun-web-app.xml` deployment descriptor file maps the JNDI name of a resource reference to the `resource-ref` element in the `web-app.xml` J2EE deployment descriptor file.

The resource lookup in the application code looks like this:

    InitialContext ic = new InitialContext();
    String dsName = "java:comp/env/jdbc/HelloDbDs";
    DataSource ds = (javax.sql.DataSource)ic.lookup(dsName);
    Connection connection = ds.getConnection();

The resource being queried is listed in the `res-ref-name` element of the `web.xml` file as follows:

    <resource-ref>
       <description>DataSource Reference</description>
       <res-ref-name>jdbc/HelloDbDs</res-ref-name>
       <res-type>javax.sql.DataSource</res-type>
       <res-auth>Container</res-auth>
    </resource-ref>

The `resource-ref` section in a Application Server specific deployment descriptor, for example `sun-web.xml`, maps the `res-ref-name` (the name being queried in the application code) to the JNDI name of the JDBC resource. The JNDI name is the same as the name of the JDBC resource as defined in the resource file when the resource is created.

    <resource-ref>
       <res-ref-name>jdbc/HelloDbDs</res-ref-name>
       <jndi-name>jdbc/HelloDbDataSource</jndi-name>
    </resource-ref>

The JNDI name in the Application Server specific deployment descriptor must match the JNDI name you assigned to the resource when you created and configured it.

# Chapter 14 Using the Java Message Service

This chapter describes how to use the JavaTM Message Service (JMS) API. The Sun Java System Application Server has a fully integrated JMS provider: the Sun Java System Message Queue software.

For general information about the JMS API, see the J2EE 1.4 Tutorial at `http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JMS.html#wp84181`.

For detailed information about JMS concepts and JMS support in the Application Server, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

This chapter contains the following sections:

- The JMS Provider

- Message Queue Resource Adapter

- Administration of the JMS Service

- Restarting the JMS Client After JMS Configuration

- JMS Connection Features

- Load-Balanced Message Inflow

- Transactions and Non-Persistent Messages

- ConnectionFactory Authentication

- Message Queue varhome Directory

- Delivering SOAP Messages Using the JMS API

# The JMS Provider

The Application Server support for JMS messaging, in general, and for message-driven beans, in particular, requires messaging middleware that implements the JMS specification: a JMS provider. The Application Server uses the Sun Java System Message Queue software as its native JMS provider. The Message Queue software is tightly integrated into theApplication Server, providing transparent JMS messaging support. This support is known within Application Server as the JMS Service. The JMS Service requires only minimal administration.

The relationship of the Message Queue software to the Application Server can be one of these types: `LOCAL` or `REMOTE`. The results of these choices and their interactions with clustering are as follows:

- If the type is `LOCAL`, the Message Queue broker starts when the Application Server starts. This is the default for a stand-alone Application Server instance.

  To create a 1:1 relationship between Application Server instances and Message Queue brokers, set the type to `LOCAL` and give each Application Server instance a different default JMS host. You can do this regardless of whether clusters are defined in the Application Server or the Message Queue software.

- If the type is `REMOTE`, the Message Queue broker must be started separately. This is the default if clusters are defined in the Application Server. For information about starting the broker, see the Sun Java System Message Queue 3 2005Q4 Administration Guide.

For more information about setting the type and the default JMS host, see Configuring the JMS Service.

For more information about the Message Queue software, refer to the documentation at `http://docs.sun.com/app/docs/coll/1307.1`.

For general information about the JMS API, see the JMS web page at `http://java.sun.com/products/jms/index.html`.

# Message Queue Resource Adapter

The Sun Java System Message Queue software is integrated into the Application Server using a resource adapter that is compliant with the Connector 1.5 specification. The module name of this system resource adapter is `jmsra`. Every JMS resource is converted to a corresponding connector resource of this resource adapter as follows:

- Connection Factory: A connector connection pool with a `max-pool-size` of `250` and a corresponding connector resource.

- Destination (Topic or Queue): A connector administered object.

You can use connector configuration tools to manage JMS resources. For more information, see Chapter 9, Developing Connectors.

# Administration of the JMS Service

To configure the JMS Service and prepare JMS resources for use in applications deployed to the Application Server, you must perform these tasks:

- Configuring the JMS Service

- The Default JMS Host

- Creating JMS Hosts

- Checking Whether the JMS Provider Is Running

- Creating Physical Destinations

- Creating JMS Resources: Destinations and Connection Factories

For more information about JMS administration tasks, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide and the Sun Java System Message Queue 3 2005Q4 Administration Guide.

## Configuring the JMS Service

The JMS Service configuration is available to all inbound and outbound connections pertaining to the Application Server cluster or instance. You can edit the JMS Service configuration in the following ways:

- To edit the JMS Service configuration using the Administration Console, open the Java Message Service component under the relevant configuration. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

- To configure the JMS service, use the `asadmin set` command to set the following attributes:

      server.jms-service.init-timeout-in-seconds = 60
      server.jms-service.type = LOCAL
      server.jms-service.start-args =
      server.jms-service.default-jms-host = default_JMS_host
      server.jms-service.reconnect-interval-in-seconds = 60
      server.jms-service.reconnect-attempts = 3
      server.jms-service.reconnect-enabled = true
      server.jms-service.addresslist-behavior = random
      server.jms-service.addresslist-iterations = 3
      server.jms-service.mq-scheme = mq
      server.jms-service.mq-service = jms

  You can also set these properties:

      server.jms-service.property.instance-name = imqbroker
      server.jms-service.property.instance-name-suffix =
      server.jms-service.property.append-version = false

  You can use the `asadmin get` command to list all the JMS service attributes and properties. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual.

You can override the JMS Service configuration using JMS connection factory settings. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

Note –

The Application Server instance must be restarted after configuration of the JMS Service.

## The Default JMS Host

A JMS host refers to a Sun Java System Message Queue broker. A default JMS host for the JMS service is provided, named `default_JMS_host`. This is the JMS host that the Application Server instance starts when the JMS Service type is configured as `LOCAL`.

If you have created a multi-broker cluster in the Message Queue software, delete the default JMS host, then add the Message Queue cluster’s brokers as JMS hosts. In this case, the default JMS host becomes the first JMS host in the `AddressList`. (For more information about the `AddressList`, see JMS Connection Features. You can also explicitly set the default JMS host; see Configuring the JMS Service.

When the Application Server uses a Message Queue cluster, it executes Message Queue specific commands on the default JMS host. For example, when a physical destination is created for a Message Queue cluster of three brokers, the command to create the physical destination is executed on the default JMS host, but the physical destination is used by all three brokers in the cluster.

## Creating JMS Hosts

You can create additional JMS hosts in the following ways:

- Use the Administration Console. Open the Java Message Service component under the relevant configuration, then select the JMS Hosts component. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

- Use the `asadmin create-jms-host` command. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual.

## Checking Whether the JMS Provider Is Running

You can use the `asadmin jms-ping` command to check whether a Sun Java System Message Queue instance is running. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual.

## Creating Physical Destinations

Produced messages are delivered for routing and subsequent delivery to consumers using physical destinations in the JMS provider. A physical destination is identified and encapsulated by an administered object (a `Topic` or `Queue` destination resource) that an application component uses to specify the destination of messages it is producing and the source of messages it is consuming.

If a message-driven bean is deployed and the physical destination it listens to doesn’t exist, the Application Server automatically creates the physical destination and sets the value of the property `maxNumActiveConsumers` to `-1` (see Load-Balanced Message Inflow). However, it is good practice to create the physical destination beforehand.

You can create a JMS physical destination in the following ways:

- Use the Administration Console. Open the Resources component, open the JMS Resources component, then select Physical Destinations. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

- Use the `asadmin create-jmsdest` command. This command acts on the default JMS host of its target. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual.

To create a destination resource, see Creating JMS Resources: Destinations and Connection Factories.

## Creating JMS Resources: Destinations and Connection Factories

You can create two kinds of JMS resources in the Application Server:

- Connection Factories: administered objects that implement the `ConnectionFactory`, `QueueConnectionFactory`, or `TopicConnectionFactory` interfaces.

- Destination Resources: administered objects that implement the `Queue` or `Topic` interfaces.

In either case, the steps for creating a JMS resource are the same. You can create a JMS resource in the following ways:

- To create a JMS resource using the Administration Console, open the Resources component, then open the JMS Resources component. Click Connection Factories to create a connection factory, or click Destination Resources to create a queue or topic. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

- To create a JMS resource, use the `asadmin create-jms-resource` command. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual.

Note –

When a `Queue` is automatically created for a message-driven bean deployed to an Application Server cluster, the value of the property `maxNumActiveConsumers` is set to `-1` so that multiple consumers can access the `Queue` at the same time. For more information, see Load-Balanced Message Inflow.

All JMS resource properties that used to work with version 7 of the Application Server are supported for backward compatibility.

# Restarting the JMS Client After JMS Configuration

When a JMS client accesses a JMS administered object for the first time, the client JVM retrieves the JMS service configuration from the Application Server. Further changes to the configuration are not available to the client JVM until the client is restarted.

# JMS Connection Features

The Sun Java System Message Queue software supports the following JMS connection features:

- Connection Pooling

- Connection Failover

Both these features use the `AddressList` configuration, which is populated with the hosts and ports of the JMS hosts defined in the Application Server. The `AddressList` is updated whenever a JMS host configuration changes. The `AddressList` is inherited by any JMS resource when it is created and by any MDB when it is deployed.

Note –

In the Sun Java System Message Queue software, the `AddressList` property is called `imqAddressList`.

## Connection Pooling

The Application Server pools JMS connections automatically.

To dynamically modify connection pool properties using the Administration Console, go to either the Connection Factories page (see Creating JMS Resources: Destinations and Connection Factories) or the Connector Connection Pools page (see Deploying and Configuring a Stand-Alone Connector Module).

To use the command line, use the `asadmin create-connector-connection-pool` command to manage the pool (see Deploying and Configuring a Stand-Alone Connector Module.

The `addresslist-behavior` JMS service attribute is set to `random` by default. This means that each `ManagedConnection` (physical connection) created from the `ManagedConnectionFactory` selects its primary broker in a random way from the `AddressList`.

When a JMS connection pool is created, there is one `ManagedConnectionFactory` instance associated with it. If you configure the `AddressList` as a `ManagedConnectionFactory` property, the `AddressList` configuration in the `ManagedConnectionFactory` takes precedence over the one defined in the Application Server.

## Connection Failover

To specify whether the Application Server tries to reconnect to the primary broker if the connection is lost, set the `reconnect-enabled` attribute in the JMS service. To specify the number of retries and the time between retries, set the `reconnect-attempts` and `reconnect-interval-in-seconds` attributes, respectively.

If reconnection is enabled and the primary broker goes down, the Application Server tries to reconnect to another broker in the `AddressList`. The `AddressList` is updated whenever a JMS host configuration changes. The logic for scanning is decided by two JMS service attributes, `addresslist-behavior` and `addresslist-iterations`.

You can override these settings using JMS connection factory settings. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

The Sun Java System Message Queue software transparently transfers the load to another broker when the failover occurs. JMS semantics are maintained during failover.

# Load-Balanced Message Inflow

You can configure `ActivationSpec` properties of the `jmsra` resource adapter in the `sun-ejb-jar.xml` file for a message-driven bean using activation-config-property elements. Whenever a message-driven bean (`EndPointFactory`) is deployed, the connector runtime engine finds these properties and configures them accordingly in the resource adapter.

The Application Server transparently enables messages to be delivered in random fashion to message-driven beans having same `ClientID`. The `ClientID` is required for durable subscribers.

For nondurable subscribers in which the `ClientID` is not configured, all instances of a specific message-driven bean that subscribe to same topic are considered equal. When a message-driven bean is deployed to multiple instances of the Application Server, only one of the message-driven beans receives the message. If multiple distinct message-driven beans subscribe to same topic, one instance of each message-driven bean receives a copy of the message.

To support multiple consumers using the same queue, set the `maxNumActiveConsumers` property of the physical destination to a large value. If this property is set, the Sun Java System Message Queue software allows multiple message-driven beans to consume messages from same queue. The message is delivered randomly to the message-driven beans. If `maxNumActiveConsumers` is set to `-1`, there is no limit to the number of consumers.

The following sample application demonstrates load-balanced message inflow:

    install-dir/samples/ee-samples/failover/apps/mqfailover

# Transactions and Non-Persistent Messages

During transaction recovery, non-persistent messages might be lost. If the broker fails between the transaction manager’s prepare and commit operations, any non-persistent message in the transaction is lost and cannot be delivered. A message that is not saved to a persistent store is not available for transaction recovery.

# ConnectionFactory Authentication

If your web, EJB, or client module has `res-auth` set to `Container`, but you use the `ConnectionFactory.createConnection("user","password")` method to get a connection, the Application Server searches the container for authentication information before using the supplied user and password. Version 7 of the Application Server threw an exception in this situation.

# Message Queue varhome Directory

The Sun Java System Message Queue software uses a default directory for storing data such as persistent messages and its log file. This directory is called `varhome`. The Application Server uses domain-dir`/imq` as the `varhome` directory if the type of relationship between the Application Server and the Message Queue software is `LOCAL` or `EMBEDDED`. If the relationship type is `REMOTE`, the Message Queue software determines the `varhome` location. For more information about the types of relationships between the Application Server and Message Queue, see The JMS Provider.

When executing Message Queue scripts such as as-install`/imq/bin/imqusermgr`, use the `-varhome` option to point the scripts to the Message Queue data if the relationship type is `LOCAL` or `EMBEDDED`. For example:

    imqusermgr -varhome $AS_INSTALL/domains/domain1/imq add -u testuser

For more information about the Message Queue software, refer to the documentation at `http://docs.sun.com/app/docs/coll/1343.3`.

# Delivering SOAP Messages Using the JMS API

Web service clients use the Simple Object Access Protocol (SOAP) to communicate with web services. SOAP uses a combination of XML-based data structuring and Hyper Text Transfer Protocol (HTTP) to define a standardized way of invoking methods in objects distributed in diverse operating environments across the Internet.

For more information about SOAP, see the Apache SOAP web site at `http://xml.apache.org/soap/index.html`.

You can take advantage of the JMS provider’s reliable messaging when delivering SOAP messages. You can convert a SOAP message into a JMS message, send the JMS message, then convert the JMS message back into a SOAP message. The following sections explain how to do these conversions:

- To send SOAP messages using the JMS API

- To receive SOAP messages using the JMS API

## To send SOAP messages using the JMS API

1. Import the `MessageTransformer` library.

       import com.sun.messaging.xml.MessageTransformer;

   This is the utility whose methods you use to convert SOAP messages to JMS messages and the reverse. You can then send a JMS message containing a SOAP payload as if it were a normal JMS message.

2. Initialize the `TopicConnectionFactory`, `TopicConnection`, `TopicSession`, and publisher.

       tcf = new TopicConnectionFactory();
       tc = tcf.createTopicConnection();
       session = tc.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
       topic = session.createTopic(topicName);
       publisher = session.createPublisher(topic);

3. Construct a SOAP message using the SOAP with Attachments API for Java (SAAJ).

       *construct a default soap MessageFactory */
       MessageFactory mf = MessageFactory.newInstance();
       * Create a SOAP message object.*/
       SOAPMessage soapMessage = mf.createMessage();
       /** Get SOAP part.*/
       SOAPPart soapPart = soapMessage.getSOAPPart();
       /* Get SOAP envelope. */
       SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
       /* Get SOAP body.*/
       SOAPBody soapBody = soapEnvelope.getBody();
       /* Create a name object. with name space */
       /* http://www.sun.com/imq. */
       Name name = soapEnvelope.createName("HelloWorld", "hw",
        "http://www.sun.com/imq");
       * Add child element with the above name. */
       SOAPElement element = soapBody.addChildElement(name)
       /* Add another child element.*/
       element.addTextNode( "Welcome to Sun Java System Web Services." );
       /* Create an atachment with activation API.*/
       URL url = new URL ("http://java.sun.com/webservices/");
       DataHandler dh = new DataHandler (url);
       AttachmentPart ap = soapMessage.createAttachmentPart(dh);
       /*set content type/ID. */
       ap.setContentType("text/html");
       ap.setContentId("cid-001");
       /**  add the attachment to the SOAP message.*/
       soapMessage.addAttachmentPart(ap);
       soapMessage.saveChanges();

4. Convert the SOAP message to a JMS message by calling the `MessageTransformer.SOAPMessageintoJMSMessage()` method.

       Message m = MessageTransformer.SOAPMessageIntoJMSMessage (soapMessage,
       session );

5. Publish the JMS message.

       publisher.publish(m);

6. Close the JMS connection.

       tc.close();

## To receive SOAP messages using the JMS API

1. Import the `MessageTransformer` library.

       import com.sun.messaging.xml.MessageTransformer;

   This is the utility whose methods you use to convert SOAP messages to JMS messages and the reverse. The JMS message containing the SOAP payload is received as if it were a normal JMS message.

2. Initialize the `TopicConnectionFactory`, `TopicConnection`, `TopicSession`, `TopicSubscriber`, and `Topic`.

       messageFactory = MessageFactory.newInstance();
       tcf = new com.sun.messaging.TopicConnectionFactory();
       tc = tcf.createTopicConnection();
       session = tc.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
       topic = session.createTopic(topicName);
       subscriber = session.createSubscriber(topic);
       subscriber.setMessageListener(this);
       tc.start();

3. Use the `OnMessage` method to receive the message. Use the `SOAPMessageFromJMSMessage` method to convert the JMS message to a SOAP message.

       public void onMessage (Message message) {
       SOAPMessage soapMessage =
        MessageTransformer.SOAPMessageFromJMSMessage( message,
        messageFactory ); }

4. Retrieve the content of the SOAP message.

# Chapter 15 Using the JavaMail API

This chapter describes how to use the JavaMailTM API, which provides a set of abstract classes defining objects that comprise a mail system.

This chapter contains the following sections:

- Introducing JavaMail

- Creating a JavaMail Session

- JavaMail Session Properties

- Looking Up a JavaMail Session

- Sending and Reading Messages Using JavaMail

# Introducing JavaMail

The JavaMail API defines classes such as `Message`, `Store`, and `Transport`. The API can be extended and can be subclassed to provide new protocols and to add functionality when necessary. In addition, the API provides concrete subclasses of the abstract classes. These subclasses, including `MimeMessage` and `MimeBodyPart`, implement widely used Internet mail protocols and conform to the RFC822 and RFC2045 specifications. The JavaMail API includes support for the IMAP4, POP3, and SMTP protocols.

The JavaMail architectural components are as follows:

- The abstract layer declares classes, interfaces, and abstract methods intended to support mail handling functions that all mail systems support.

- The internet implementation layer implements part of the abstract layer using the RFC822 and MIME internet standards.

- JavaMail uses the JavaBeans Activation Framework (JAF) to encapsulate message data and to handle commands intended to interact with that data.

For more information, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide and the JavaMail specification at `http://java.sun.com/products/javamail/`.

# Creating a JavaMail Session

You can create a JavaMail session in the following ways:

- In the Administration Console, open the Resources component and select JavaMail Sessions. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Administration Guide.

- Use the `asadmin create-javamail-resource` command. For details, see the Sun Java System Application Server Enterprise Edition 8.1 2005Q2 Reference Manual.

# JavaMail Session Properties

You can set properties for a JavaMail `Session` object. Every property name must start with a `mail-` prefix. The Application Server changes the dash (`-`) character to a period (`.`) in the name of the property and saves the property to the `MailConfiguration` and JavaMail `Session` objects. If the name of the property doesn’t start with `mail-`, the property is ignored.

For example, if you want to define the property `mail.from` in a JavaMail `Session` object, first define the property as follows:

- Name - `mail-from`

- Value - `john.doe@sun.com`

After you get the JavaMail `Session` object, you can get the `mail.from` property to retrieve the value as follows:

    String password = session.getProperty("mail.from");

# Looking Up a JavaMail Session

The standard Java Naming and Directory InterfaceTM (JNDI) subcontext for JavaMail sessions is `java:comp/env/mail`.

Registering JavaMail sessions in the `mail` naming subcontext of a JNDI namespace, or in one of its child subcontexts, is standard. The JNDI namespace is hierarchical, like a file system’s directory structure, so it is easy to find and nest references. A JavaMail session is bound to a logical JNDI name. The name identifies a subcontext, `mail`, of the root context, and a logical name. To change the JavaMail session, you can change its entry in the JNDI namespace without having to modify the application.

The resource lookup in the application code looks like this:

    InitialContext ic = new InitialContext();
    String snName = "java:comp/env/mail/MyMailSession";
    Session session = (Session)ic.lookup(snName);

For more information about the JNDI API, see Chapter 13, Using the Java Naming and Directory Interface.

# Sending and Reading Messages Using JavaMail

## To send a message using JavaMail

1. Import the packages that you need.

       import java.util.*;
       import javax.activation.*;
       import javax.mail.*;
       import javax.mail.internet.*;
       import javax.naming.*;

2. Look up the JavaMail session.

       InitialContext ic = new InitialContext();
       String snName = "java:comp/env/mail/MyMailSession";
       Session session = (Session)ic.lookup(snName);

   For more information, see Looking Up a JavaMail Session.

3. Override the JavaMail session properties if necessary.

   For example:

       Properties props = session.getProperties();
       props.put("mail.from", "user2@mailserver.com");

4. Create a `MimeMessage`.

   The `msgRecipient`, `msgSubject`, and `msgTxt` variables in the following example contain input from the user:

       Message msg = new MimeMessage(session);
       msg.setSubject(msgSubject);
       msg.setSentDate(new Date());
       msg.setFrom();
       msg.setRecipients(Message.RecipientType.TO,
          InternetAddress.parse(msgRecipient, false));
       msg.setText(msgTxt);

5. Send the message.

       Transport.send(msg);

## To read a message using JavaMail

1. Import the packages that you need.

       import java.util.*;
       import javax.activation.*;
       import javax.mail.*;
       import javax.mail.internet.*;
       import javax.naming.*;

2. Look up the JavaMail session.

       InitialContext ic = new InitialContext();
       String snName = "java:comp/env/mail/MyMailSession";
       Session session = (javax.mail.Session)ic.lookup(snName);

   For more information, see Looking Up a JavaMail Session.

3. Override the JavaMail session properties if necessary.

   For example:

       Properties props = session.getProperties();
       props.put("mail.from", "user2@mailserver.com");

4. Get a `Store` object from the `Session`, then connect to the mail server using the Store object’s `connect()` method.

   You must supply a mail server name, a mail user name, and a password.

       Store store = session.getStore();
       store.connect("MailServer", "MailUser", "secret");

5. Get the INBOX folder.

       Folder folder = store.getFolder("INBOX");

6. It is efficient to read the `Message` objects (which represent messages on the server) into an array.

       Message[] messages = folder.getMessages();

# Chapter 16 Using the Java Management Extensions (JMX) API

The Sun JavaTM System Application Server uses Java Management Extensions (JMXTM) technology for monitoring, management and notification purposes. Management and monitoring of the Application Server is performed by the Application Server Management Extensions (AMX), which exposes managed resources for remote management via the JMX Application Programming Interface (API).

The Application Server incorporates the JMX 1.2 Reference Implementation, that was developed by the Java Community Process as Java Specification Request (JSR) 3, and the JMX Remote API 1.0 Reference Implementation (JSR 160).

This chapter assumes some familiarity with the JMX technology, but the AMX interfaces can be used for the most part without understanding JMX.

The JMX specifications and Reference Implementations are available for download at `http://java.sun.com/products/JavaManagement/download.html`.

This chapter contains the following topics:

- About AMX

- AMX MBeans

- Proxies

- Connecting to the Domain Administration Server

- Examining AMX Code Samples

- Running the AMX Samples

# About AMX

This section describes the Application Server Management eXtensions (AMX). AMX is an API that exposes all of the Application Server configuration and monitoring MBeans as easy-to-use client-side dynamic proxies implementing the AMX interfaces.

Full API documentation for the AMX API is provided in the following Application Server package:

    com.sun.appserv.management

The Application Server is based around the concept of administration domains, which consist of one or more managed resources. A managed resource can be an Application Server instance, a cluster of such instances, or a manageable entity within a server instance. A managed resource is of a particular type, and each resource type exposes a set of attributes and administrative operations that change the resource’s state.

Managed resources are exposed as JMX management beans, or MBeans. While the MBeans can be accessed via standard JMX APIs (for example, `MBeanServerConnection`), most users find the use of the AMX client-side dynamic proxies much more convenient.

All the vital components of the Application Server are visible for monitoring and management via AMX. You can use third-party tools to perform all common administrative tasks programmatically, based on the JMX and JMX Remote API standards.

The AMX API consists of a set of proxy interfaces. MBeans are registered in the JMX runtime contained in the Domain Administration Server (DAS). AMX provides routines to obtain proxies for MBeans, starting with a root-level domain MBean.

You can navigate generically through the MBean hierarchy using the `com.sun.appserv.management.base.Container` interface. When using AMX, the interfaces defined are implemented by client-side dynamic proxies, but they also implicitly define the `MBeanInfo` that is made available by the MBean or MBeans corresponding to it. Certain operations defined in the interface might have a different return type or a slightly different name when accessed through the MBean directly. This results from the fact that direct access to JMX requires the use of `ObjectName`, whereas use of the AMX interfaces is via strongly typed proxies implementing the interface(s).

# AMX MBeans

All AMX MBeans are represented as interfaces in a subpackage of `com.sun.appserv.management` and are implemented by dynamic proxies on the client-side. While you can access AMX MBeans directly through standard JMX APIs, most users find the use of AMX interface (proxy) classes to be most convenient.

An AMX MBean belongs to an application server domain. There is exactly one domain per DAS. Thus all MBeans accessible through the DAS belong to a single Application Server administrative domain. All MBeans in an Application Server administrative domain, and hence within the DAS, belong to the JMX domain `amx`. Any MBeans that do not have the JMX domain `amx` are not part of AMX, and are neither documented nor supported for use by clients. All AMX MBeans can be reached navigationally through the `DomainRoot`.

AMX defines different types of MBean, namely, configuration MBeans, monitoring MBeans, utility MBeans and J2EE management (JSR 77) MBeans. These MBeans are logically related in the following ways:

- They all implement the `com.sun.appserv.management.base.AMX` interface.

- They all have a `j2eeType` and `name` property within their `ObjectName` (see `com.sun.appserv.management.base.XTypes` and `com.sun.appserv.management.j2ee.J2EETypes` for the available values of the `j2eeType` property).

- All MBeans that logically contain other MBeans implement the `com.sun.appserv.management.base.Container` interface.

- JSR 77 MBeans that have a corresponding configuration or monitoring peer expose it via `getConfigPeer()` or `getMonitoringPeer()`. However, there are many configuration and monitoring MBeans that do not correspond to JSR 77 MBeans.

## Configuration MBeans

Configuration information for a given Application Server domain is stored in a central repository that is shared by all instances in that domain. The central repository can only be written to by the DAS. However, configuration information in the central repository is made available to administration clients via AMX MBeans.

The configuration MBeans are those that modify the underlying `domain.xml` or related files. Collectively, they form a model representing the configuration and deployment repository and the operations that can be performed on them.

The `Group` Attribute of configuration MBeans, obtained from `getGroup()`, has a value of `com.sun.appserv.management.base.AMX.GROUP_CONFIGURATION`.

## Monitoring MBeans

Monitoring MBeans provide transient monitoring information about all the vital components of the Application Server.

The `Group` Attribute of monitoring MBeans, obtained from `getGroup()`, has a value of `com.sun.appserv.management.base.AMX.GROUP_MONITORING`.

## Utility MBeans

Utility MBeans provide commonly used services to the Application Server.

The `Group` Attribute of utility MBeans, obtained from `getGroup()`, has a value of `com.sun.appserv.management.base.AMX.GROUP_UTILITY`.

## J2EE Management MBeans

The J2EE management MBeans implement, and in some cases extend, the management hierarchy as defined by JSR 77, which specifies the management model for the whole J2EE platform. One of the management APIs implemented in JSR 77 is the JMX API.

The implementation of JSR 77 in AMX offers access to and monitoring of MBeans via J2EE management MBeans, by using the `getMonitoringPeer()` and `getConfigPeer()` methods.

The J2EE management MBeans can be thought of as the central hub from which other MBeans are obtained.

The `Group` Attribute of J2EE management MBeans, obtained from `getGroup()`, has a value of `com.sun.appserv.management.base.AMX.GROUP_JSR77`.

## Other MBeans

MBeans that do not fit into one of the above four categories have the value `com.sun.appserv.management.base.AMX.GROUP_OTHER`. One such example is `com.sun.appserv.management.deploy.DeploymentMgr`.

## MBean Notifications

All AMX MBeans that emit Notifications place a `java.util.Map` within the `userData` field of a standard Notification, which can be obtained via `Notification.getUserData()`. Within the map are zero or more items, which vary according to the Notification type. Each Notification type, and the data available within the Notification, is defined in its respective MBean or in an appropriate place.

Note that certain standard Notifications, such as `javax.management.AttributeChangeNotification` do not and cannot follow this behavior.

## Access to MBean Attributes

An AMX MBean `Attribute` is accessible in three ways:

- Dotted names via `MonitoringDottedNames` and `ConfigDottedNames`

- Attributes on MBeans via `getAttribute(s)` and `setAttributes(s)` (from the standard JMX API)

- Getters/setters within the MBean’s interface class, for example, `getPort()`, `setPort()`, and so on.

All dotted names that are accessible via the command line interface are available as Attributes within a single MBean. This includes properties, which are Attributes beginning with the prefix `property.`, for example, `server.property.myproperty`.

Note –

Certain attributes that may be of a specific type, such as `int`, are declared as `java.lang.String`. This is because the value of the attribute may be a template of a form such as `${HTTP_LISTENER_PORT}`.

Note –

An application or module MBean has two `enabled` attributes. Which `enabled` attribute to look up for the state of the application or module depends on the target. If the target is `domain`, look up the attribute under application or module itself. If the target is not domain, look up the attribute under the `application-ref`.

To look up an application in JConsole, select the following:

`com.sun.appserv` -> `j2ee-application` -> app-name -> `server` -> `config`

To look up a module in JConsole, select the following:

`com.sun.appserv` -> module-type -> module-name -> `server` -> `config`

To look up an `application-ref` in JConsole, select the following:

`com.sun.appserv` -> `application-ref` -> app-or-module-name -> `server` -> `config`

The attributes, including `enabled`, are listed under `config`.

# Proxies

Proxies are an important part of the AMX API, and enhance ease-of-use for the programmer.

While JMX MBeans can be used directly, client-side proxies are offered to facilitate navigation through the MBean hierarchy. In some cases, proxies also function as support or helper objects to simplify the use of the MBeans.

See the API documentation for the `com.sun.appserv.management` package and its sub-packages for more information about using proxies. The API documentation explains the use of AMX with proxies. If you are using JMX directly (for example, via `MBeanServerConnection`), the return type, argument types and method names might vary as needed for the difference between a strongly-typed proxy interface and generic `MBeanServerConnection/ObjectName` interface.

# Connecting to the Domain Administration Server

As stated in Configuration MBeans, the AMX API allows client applications to connect to Application Server instances via the DAS. All AMX connections are established to the DAS only: AMX does not support direct connections to individual server instances. This makes it simple to interact with all servers, clusters, and so on, with a single connection.

Sample code for connecting to the DAS is shown in Connecting to the DAS.

# Examining AMX Code Samples

The following example uses of AMX are discussed in this document:

- Starting an Application Server

- Deploying an Archive

- Displaying the AMX MBean Hierarchy

- Setting Monitoring States

- Accessing AMX MBeans

- Accessing and Displaying the Attributes of an AMX MBean

- Listing AMX MBean Properties

- Querying

- Monitoring Attribute Changes

- Undeploying Modules

- Stopping an Application Server

## Connecting to the DAS

The connection to the DAS is shown in the following code.

##### Example 16–1 Connecting to the DAS

    [...]
    public static AppserverConnectionSource
        connect(
            final String host,
            final int port,
            final String user,
            final String password,
            final TLSParams tlsParams )
            throws IOException
            {
                final String info = "host=" + host + ", port=" + port +
                    ", user=" + user + ", password=" + password +
                    ", tls=" + (tlsParams != null);

                SampleUtil.println( "Connecting...:" + info );

                final AppserverConnectionSource conn    =
                    new AppserverConnectionSource(
                        AppserverConnectionSource.PROTOCOL_RMI,
                        host, port, user, password, tlsParams, null);

                conn.getJMXConnector( false );

                SampleUtil.println( "Connected: " + info );

                return( conn );
            }
    [...]

A connection to the DAS is obtained via an instance of the `com.sun.appserv.management.client.AppserverConnectionSource` class. For the connection to be established, you must know the name of the host and port number on which the DAS is running, and have the correct user name, password and TLS parameters.

Once the connection to the DAS is established, `DomainRoot` is obtained as follows:

    DomainRoot domainRoot = appserverConnectionSource.getDomainRoot();

This `DomainRoot` instance is a client-side dynamic proxy to the MBean `amx:j2eeType=X-DomainRoot,name=amx`.

See the API documentation for `com.sun.appserv.management.client.AppserverConnectionSource` for further details about connecting to the DAS using the `AppserverConnectionSource` class`.`

However, if you prefer to work with standard JMX, instead of getting `DomainRoot`, you can get the `MBeanServerConnection` or `JMXConnector`, as shown:

    MBeanServerConnection conn =
    appserverConnectionSource.getMBeanServerConnection( false );
    JMXConnector jmxConn =
    appserverConnectionSource.getJMXConnector( false );

## Starting an Application Server

The `startServer()` method demonstrates how to start an Application Server.

##### Example 16–2 Starting an Application Server

    [...]
    startServer( final String serverName )
    {
        final J2EEServer server    = getJ2EEServer( serverName );

        server.start();
    }
    [...]

This method retrieves and starts an application server instance named `server`. The `server` is an instance of the `com.sun.appserv.management.j2see.J2EEServer` interface, and is obtained by calling another method, `getJ2EEServer()`, shown in the following code.

##### Example 16–3 Obtaining a Named J2EE server instance

    [...]
    getJ2EEServer( final String serverName )
    {
        final J2EEDomain j2eeDomain = getDomainRoot().getJ2EEDomain();
        final Map servers = j2eeDomain.getServerMap();
        final J2EEServer server = (J2EEServer)servers.get( serverName );
            if ( server == null )
            {
                throw new IllegalArgumentException( serverName );
            }
        return( server );
    }
    [...]

To obtain a J2EE server instance, the `getJ2EEServer()` method first of all obtains an instance of the `J2EEDomain` interface by calling the `com.sun.appserv.management.base.AMX.getDomainRoot()` and `com.sun.appserv.management.DomainRoot.getJ2EEDomain()` methods. The two methods called establish the following:

- `AMX.getDomainRoot()` obtains the Application Server domain to which `j2eeDomain` belongs.

- `DomainRoot.getJ2EEDomain()` obtains the J2EE domain for `j2eeDomain`.

The `J2EEServer` instance is then started by a call to the `start()` method. The `com.sun.appserv.management.j2ee.StateManageable.start()` method can be used to start any state manageable object.

## Deploying an Archive

The `uploadArchive()` and `deploy()` methods demonstrate how to upload and deploy a J2EE archive file.

##### Example 16–4 Uploading an archive

    [...]
    uploadArchive ( final File archive  ) throws IOException
    {
        final FileInputStream input = new FileInputStream( archive );
        final long length = input.available();
        final DeploymentMgr mgr = getDomainRoot().getDeploymentMgr();
        final Object uploadID = mgr.initiateFileUpload( length );
        try
        {
            [...]
        }
        finally
        {
            input.close();
        }
        return( uploadID );
    }
    [...]

The `uploadArchive()` method creates a standard Java `FileInputStream` instance called `input`, to upload the archive `archive`. It then obtains the AMX deployment manager running in the application server domain, by calling the `DomainRoot.getDeploymentMgr()` method.

A call to `com.sun.appserv.management.deploy.initiateFileUpload` starts the upload of `archive`. The `initiateFileUpload()` method automatically issues an upload ID, that `uploadArchive()` returns when it is called by `deploy()`.

##### Example 16–5 Deploying an archive

    [...]
    deploy ( final File archive ) throws IOException
    {
        final Object uploadID = uploadArchive(archive);
        final DeploymentMgr mgr    = getDomainRoot().getDeploymentMgr();
        final Object deployID = mgr.initDeploy( );
        final DeployNotificationListener myListener =
            new DeployNotificationListener( deployID);
        mgr.addNotificationListener( myListener, null, null);
        try
        {
            final Map    options  = new HashMap();
            options.put( DeploymentMgr.DEPLOY_OPTION_VERIFY_KEY,
                Boolean.TRUE.toString() );
            options.put( DeploymentMgr.DEPLOY_OPTION_DESCRIPTION_KEY,
                "description" );
            mgr.startDeploy( deployID, uploadID, null, null);
            while ( ! myListener.isCompleted() )
            {
                try
                {
                    println( "deploy: waiting for deploy of " + archive);
                    Thread.sleep( 1000 );
                }
                catch( InterruptedException e )
                {
                }
            }
            final DeploymentStatus status = myListener.getDeploymentStatus();
            println( "Deployment result: " + getStageStatusString(
                status.getStageStatus() ) );
            if ( status.getStageThrowable() != null )
            {
                status.getStageThrowable().printStackTrace();
            }
        }
        finally
        {
            try
            {
                mgr.removeNotificationListener( myListener );
            }
            catch( Exception e )
            {
            }
        }
    }
    [...]

The `deploy()` method calls `uploadArchive` to get the upload ID for `archive`. It then identifies the deployment manager by calling `DomainRoot.getDeploymentMgr()`. A call to `DeploymentMgr.initDeploy()` initializes the deployment and obtains a deployment ID, which is used to track the progress of the deployment.

A JMX notification listener, `myListener`, is created and activated to listen for notifications regarding the deployment of `deployID`.

Deployment is started by calling the `DeploymentMgr.startDeploy()` method and providing it with the `deployID` and `uploadID`.

While the deployment is continuing, `myListener` listens for the completion notification and `DeploymentStatus` keeps you informed of the status of the deployment by regularly calling its `getStageStatus()` method. Once the deployment is complete, the listener is closed down.

Caution –

Some of the behavior of the `com.sun.appserv.management.deploy` API is unpredictable, and it should be used with caution.

## Displaying the AMX MBean Hierarchy

The `displayAMX()` method demonstrates how to display the AMX MBean hierarchy.

##### Example 16–6 Displaying the AMX MBean Hierarchy

    [...]
    displayAMX(
        final AMX amx,
        final int indentCount )
    {
        final String indent = getIndent( indentCount );
        final String j2eeType = amx.getJ2EEType();
        final String name = amx.getName();
        if ( name.equals( AMX.NO_NAME ) )
        {
            println( indent + j2eeType );
        }
        else
        {
            println( indent + j2eeType + "=" + name );
        }
    }
    private void
    displayHierarchy(
        final Collection amxSet,
        final int indentCount )
    {
        final Iterator    iter    = amxSet.iterator();
        while ( iter.hasNext() )
        {
            final AMX amx = (AMX)iter.next();
            displayHierarchy( amx, indentCount );
        }
    }
    public void
    displayHierarchy(
        final AMX amx,
        final int    indentCount )
    {
        displayAMX( amx, indentCount );
        if ( amx instanceof Container )
        {
            final Map m = ((Container)amx).getMultiContaineeMap( null );
            final Set deferred = new HashSet();
            final Iterator mapsIter = m.values().iterator();
            while ( mapsIter.hasNext() )
            {
                final Map instancesMap = (Map)mapsIter.next();
                final AMX first = (AMX)instancesMap.values().iterator().next();
                if ( first instanceof Container )
                {
                    deferred.add( instancesMap );
                }
                else
                {
                    displayHierarchy( instancesMap.values(), indentCount + 2);
                }
            }
            // display deferred items
            final Iterator iter = deferred.iterator();
            while ( iter.hasNext() )
            {
                final Map instancesMap = (Map)iter.next();
                displayHierarchy( instancesMap.values(), indentCount + 2);
            }
        }
    }
    public void displayHierarchy()
    {
        displayHierarchy( getDomainRoot(), 0);
    }
    public void
    displayHierarchy( final String j2eeType )
    {
        final Set items = getQueryMgr().queryJ2EETypeSet( j2eeType );
        if ( items.size() == 0 )
        {
            println( "No {@link AMX} of j2eeType "
                + SampleUtil.quote( j2eeType ) + " found" );
        }
        else
        {
            displayHierarchy( items, 0);
        }
    }
    [...]

The `displayAMX()` method obtains the J2EE type and the name of an AMX MBean by calling `AMX.getJ2EEType` and `AMX.getName` respectively.

The `displayHierarchy()` method defines a standard Java `Collection` instance, `amxSet`, which collects instances of AMX MBeans.

To display the hierarchy of MBeans within a particular MBean in the collection, `displayHierarchy()` checks whether the MBean is an instance of `Container`. If so, it creates a set of the MBeans it contains by calling the `com.sun.appserv.management.base.Container.getMultiContaineeMap()` method.

The MBean hierarchy for a particular J2EE type is displayed by calling the `com.sun.appserv.management.base.QueryMgr.queryJ2EETypeSet()`, and passing the result to `displayHierarchy()`.

To display the entire AMX MBean hierarchy in a domain, `displayHierarchy()` calls `getDomainRoot()` to obtain the root AMX MBean in the domain.

## Setting Monitoring States

The `setMonitoring()` method demonstrates how to set monitoring states.

##### Example 16–7 Setting Monitoring States

    [...]
    private static final Set LEGAL_MON =
        Collections.unmodifiableSet( SampleUtil.newSet( new String[]
    {
        ModuleMonitoringLevelValues.HIGH,
        ModuleMonitoringLevelValues.LOW,
        ModuleMonitoringLevelValues.OFF,
    } ));
    public void setMonitoring(
        final String configName,
        final String state )
    {
        if ( ! LEGAL_MON.contains( state ) )
        {
            throw new IllegalArgumentException( state );
        }
        final ConfigConfig config =
            (ConfigConfig)getDomainConfig().
            getConfigConfigMap().get( configName );
        final ModuleMonitoringLevelsConfig mon =
            config.getMonitoringServiceConfig().
            getModuleMonitoringLevelsConfig();
        mon.setConnectorConnectionPool( state );
        mon.setThreadPool( state );
        mon.setHTTPService( state );
        mon.setJDBCConnectionPool( state );
        mon.setORB( state );
        mon.setTransactionService( state );
        mon.setWebContainer( state );
        mon.setEJBContainer( state );
    }
    [...]

The AMX API defines three levels of monitoring in `com.sun.appserv.management.config.ModuleMonitoringLevelValues`, namely, `HIGH`, `LOW`, and `OFF`.

In this example, the configuration element being monitored is named `configName`. The `com.sun.appserv.management.config.ConfigConfig` interface is used to configure the `config` element for `configName` in the `domain.xml` file.

An instance of `com.sun.appserv.management.config.ModuleMonitoringLevelsConfig` is created to configure the `module-monitoring-levels` element for `configName` in the `domain.xml` file.

The `ModuleMonitoringLevelsConfig` instance created then calls each of its set methods to change their states to `state`.

The above is performed by running the `set-monitoring` command when you run `SimpleMain`, stating the name of the configuration element to be monitored and the monitoring `state` to one of `HIGH`, `LOW` or `OFF`.

## Accessing AMX MBeans

The `handleList()` method demonstrates how to access many (but not all) configuration elements.

##### Example 16–8 Accessing AMX MBeans

    [...]
    handleList()
    {
        final DomainConfig dcp = getDomainConfig();
        println( "\n--- Top-level --- \n" );
        displayMap( "ConfigConfig", dcp.getConfigConfigMap() );
        displayMap( "ServerConfig", dcp.getServerConfigMap() );
        displayMap( "StandaloneServerConfig",
            dcp.getStandaloneServerConfigMap() );
        displayMap( "ClusteredServerConfig",
            dcp.getClusteredServerConfigMap() );
        displayMap( "ClusterConfig", dcp.getClusterConfigMap() );
        println( "\n--- DeployedItems --- \n" );
        displayMap( "J2EEApplicationConfig",
            dcp.getJ2EEApplicationConfigMap() );
        displayMap( "EJBModuleConfig",
            dcp.getEJBModuleConfigMap() );
        displayMap( "WebModuleConfig",
            dcp.getWebModuleConfigMap() );
        displayMap( "RARModuleConfig",
            dcp.getRARModuleConfigMap() );
        displayMap( "AppClientModuleConfig",
            dcp.getAppClientModuleConfigMap() );
        displayMap( "LifecycleModuleConfig",
            dcp.getLifecycleModuleConfigMap() );
        println( "\n--- Resources --- \n" );
        displayMap( "CustomResourceConfig",
            dcp.getCustomResourceConfigMap() );
        displayMap( "PersistenceManagerFactoryResourceConfig",
            dcp.getPersistenceManagerFactoryResourceConfigMap() );
        displayMap( "JNDIResourceConfig",
            dcp.getJNDIResourceConfigMap() );
        displayMap( "JMSResourceConfig",
            dcp.getJMSResourceConfigMap() );
        displayMap( "JDBCResourceConfig",
            dcp.getJDBCResourceConfigMap() );
        displayMap( "ConnectorResourceConfig",
            dcp.getConnectorResourceConfigMap() );
        displayMap( "JDBCConnectionPoolConfig",
            dcp.getJDBCConnectionPoolConfigMap() );
        displayMap( "PersistenceManagerFactoryResourceConfig",
            dcp.getPersistenceManagerFactoryResourceConfigMap() );
        displayMap( "ConnectorConnectionPoolConfig",
            dcp.getConnectorConnectionPoolConfigMap() );
        displayMap( "AdminObjectResourceConfig",
            dcp.getAdminObjectResourceConfigMap() );
        displayMap( "ResourceAdapterConfig",
            dcp.getResourceAdapterConfigMap() );
        displayMap( "MailResourceConfig",
            dcp.getMailResourceConfigMap() );
        final ConfigConfig config =
            (ConfigConfig)dcp.getConfigConfigMap().get( "server-config" );
        println( "\n--- HTTPService --- \n" );
        final HTTPServiceConfig httpService = config.getHTTPServiceConfig();
        displayMap( "HTTPListeners",
            httpService.getHTTPListenerConfigMap() );
        displayMap( "VirtualServers",
            httpService.getVirtualServerConfigMap() );
    }
    [...]

The `handleList()` method makes use of the `displayMap()` method, which simply prints out the key value pairs.

The `handleList()` method identifies the configuration for a domain by calling the `DomainRoot.getDomainConfig()` method. This `DomainConfig` instance then calls each of its `getXXXMap()` methods in turn, to obtain a `Map` for each type of AMX MBean. The `Map` returned by each getter is displayed by `displayMap()`.

Similarly, the AMX MBeans representing the `http-service` element are displayed as `Maps` by calling the `getXXXMap()` methods of the `com.sun.appserv.management.config.HTTPServiceConfig` interface, and passing them to `displayMap()`.

## Accessing and Displaying the Attributes of an AMX MBean

The `displayAllAttributes()` method demonstrates how to access and display the attributes of an AMX MBean.

##### Example 16–9 Accessing and Displaying the Attributes of an AMX MBean

    [...]
    displayAllAttributes( final AMX item )
    {
        println( "\n--- Attributes for " + item.getJ2EEType() +
            "=" + item.getName() + " ---" );
        final Extra extra = Util.getExtra( item );
        final Map attrs    = extra.getAllAttributes();
        final Iterator iter = attrs.keySet().iterator();
        while ( iter.hasNext() )
        {
            final String name = (String)iter.next();
            final Object value = attrs.get( name );
            println( name + "=" + toString( value ) );
        }
    }
    public void
    displayAllAttributes( final String j2eeType )
    {
        final Set items = queryForJ2EEType( j2eeType );
        if ( items.size() == 0 )
        {
            println( "No {@link AMX} of j2eeType "
                + SampleUtil.quote( j2eeType ) + " found" );
        }
        else
        {
            final Iterator iter= items.iterator();
            while ( iter.hasNext() )
            {
                final AMX amx = (AMX)iter.next();
                displayAllAttributes( amx );
                println( "" );
            }
        }
    }
    [...]

The `displayAllAttributes()` method calls the `AMX.getName()` and `AMX.getJ2EEType()` methods for an AMX MBean and prints the results onscreen. It then gets all the attributes for that MBean by calling `com.sun.appserv.management.base.Extra.getAllAttributes()` on the `Extra` instance returned by `com.sun.appserv.management.base.Util.getExtra()`. This is repeated for every MBean.

The attributes of AMX MBeans of a certain J2EE type can be displayed by specifying the J2EE type when the command is run. In this case, `displayAllAttributes()` calls `queryForJ2EEType()`. The `queryForJ2EEType()` method calls the `com.sun.appserv.management.base.QueryManager.queryPropSet()` method on the specified J2EE type to identify all elements of that type in the domain.

## Listing AMX MBean Properties

The `displayAllProperties()` demonstrates how to list AMX MBean properties.

##### Example 16–10 Listing AMX MBean Properties

    [...]
    getProperties( final PropertiesAccess pa )
    {
        final HashMap m = new HashMap();
        final String[] names = pa.getPropertyNames();
        for( int i = 0; i < names.length; ++i )
        {
            m.put( names[ i ], pa.getPropertyValue( names[ i ] ) );
        }
        return( m );
    }
    public void
    displayAllProperties( )
    {
        final Iterator iter    = getQueryMgr().queryAllSet().iterator();
        while ( iter.hasNext() )
        {
            final AMX amx = (AMX)iter.next();
            if ( amx instanceof PropertiesAccess )
            {
                final PropertiesAccess pa = (PropertiesAccess)amx;
                final Map    props    = getProperties( pa );
                if ( props.keySet().size() != 0 )
                {
                    println( "\nProperties for:
                        " + Util.getObjectName( AMX)pa ) );
                    println( SampleUtil.mapToString(getProperties(pa), "\n") );
                }
            }
        }
    }
    [...]

The `displayAllProperties()` method uses another `Samples` method, `getProperties()`. This method creates an instance of the `com.sun.appserv.management.config.PropertiesAccess` interface, and calls its `getPropertyNames()` method to obtain the names of all the properties for a given AMX MBean. For each property name obtained, its corresponding value is obtained by calling `PropertiesAccess.getPropertyValue()`.

The `displayAllProperties()` method calls the `com.sun.appserv.management.base.QueryMgr.queryAllSet()` method to obtain a set of all the AMX MBeans present in the domain. All AMX MBeans that have properties obligatorily extend the `PropertiesAccess` interface. Any MBean found to extend `PropertiesAccess` is passed to the `getProperties()` method, and the list of property values returned is printed onscreen.

## Querying

The ```demoQuery()` method demonstrates how to issue queries.

The `demoQuery()` method uses other methods that are defined by `Samples`, namely `displayWild()`, and `displayJ2EEType()`. The `displayWild()` method is shown in the following code.

##### Example 16–11 Querying and displaying wild cards

    [...]
    queryWild(
        final String propertyName,
        final String propertyValue)
    {
        final String[] propNames = new String[] { propertyName };
        final String[] propValues = new String[]{ propertyValue };
        final Set amxs = getQueryMgr().queryWildSet( propNames, propValues );
        return( amxs );
    }
    public Set
    displayWild(
        final String propertyName,
        final String propertyValue)
    {
        final Set items = queryWild( propertyName, propertyValue );
        println( "\n--- Queried for " + propertyName + "="
            + propertyValue + " ---" );
        final Iterator    iter    = items.iterator();
        while ( iter.hasNext() )
        {
            final AMX    item    = (AMX)iter.next();
            println( "j2eeType=" + item.getJ2EEType() + ",
                " + "name=" + item.getName() );
        }
    }
    [...]

The `displayWild()` method calls `queryWild()`, to obtain all the AMX MBeans that have object names matching `propertyName` and `propertyValue`. To do so, `queryWild()` calls the `com.sun.appserv.management.base.QueryMgr.queryWildSet()` method. The `queryWildSet()` method returns the list of AMX MBeans with object names matching the wild card strings.

For each MBean returned, the `displayWild()` calls `AMX.getJ2EEType()` to identify its J2EE type, and prints the result onscreen.

In code that is not shown here, the `displayJ2EEType()` method calls the `queryForJ2EEType()` method, which was seen in Accessing and Displaying the Attributes of an AMX MBean, to identify MBeans of a certain J2EE type and print their object names onscreen.

##### Example 16–12 Querying

    [...]
    demoQuery()
    {
        displayWild( AMX.J2EE_TYPE_KEY, "X-*ResourceConfig" );
        displayWild( AMX.J2EE_TYPE_KEY, "X-*ServerConfig" );
        displayJ2EEType( XTypes.SSL_CONFIG );
        displayJ2EEType( XTypes.CLUSTER_CONFIG );
    }
    [...]

In the `demoQuery()` method, the `displayWild()` and `displayJ2EEType()` methods are called to find the following MBeans:

- `J2EE_TYPE_KEY` MBeans called `ResourceConfig`

- `J2EE_TYPE_KEY` MBeans called `ServerConfig`

- All `SSL_CONFIG` MBeans

- All `CLUSTER_CONFIG` MBeans

## Monitoring Attribute Changes

The `demoJMXMonitor()` demonstrates how to monitor attribute changes.

##### Example 16–13 Monitoring Attribute Changes

    [...]
    demoJMXMonitor() throws InstanceNotFoundException, IOException
    {
        final JMXMonitorMgr mgr = getDomainRoot().getJMXMonitorMgr();
        final String attrName = "SampleString";
        final String attrValue = "hello";
        final SampleListener sampleListener = new SampleListener();
        final MBeanServerConnection conn =
            Util.getExtra( mgr ).getConnectionSource()
            .getExistingMBeanServerConnection();
        conn.addNotificationListener(
            getMBeanServerDelegateObjectName(),
            sampleListener, null, null );
        final Sample sample = (Sample)getDomainRoot()
            .getContainee( XTypes.SAMPLE );
        final String monitorName = "SampleStringMonitor";
        AMXStringMonitor mon = null;
        try
        {
            try { mgr.remove( monitorName ); }
            catch( Exception e ) {}
            mon = mgr.createStringMonitor( monitorName );
            waitMBeanServerNotification( sampleListener,
                MBeanServerNotification.REGISTRATION_NOTIFICATION,
                Util.getObjectName( mon ) );
            sample.addAttribute( attrName, attrValue );
            mon.addNotificationListener( sampleListener, null, null);
            mon.setObservedAttribute( attrName );
            mon.setStringToCompare( attrValue );
            mon.setNotifyDiffer( true );
            mon.setNotifyMatch( true );
            mon.addObservedObject( Util.getObjectName( sample ) );
            final StdAttributesAccess attrs = Util.getExtra( sample);
            attrs.setAttribute( new Attribute(attrName, "goodbye") );
            attrs.setAttribute( new Attribute(attrName, attrValue) );
            sample.removeAttribute( attrName );
            final Map notifs = sampleListener.getNotifsReceived();
            waitNumNotifs( notifs,
                AttributeChangeNotification.ATTRIBUTE_CHANGE, 4 );
        }
        catch( Throwable t )
        {
            t.printStackTrace();
        }
        finally
        {
            try
            {
                mon.removeNotificationListener( sampleListener );
                if ( mon != null )
                {
                    mgr.remove( mon.getName() );
                    waitMBeanServerNotification( sampleListener,
                        MBeanServerNotification
                        .UNREGISTRATION_NOTIFICATION,
                        Util.getObjectName( mon ) );
                }
                conn.removeNotificationListener(
                getMBeanServerDelegateObjectName(),
                sampleListener );
            }
            catch( ListenerNotFoundException e )
            {
            }
        }
    }
    [...]

The `demoJmx()` method demonstrates the implementation of a JMX monitor MBean, that listens for changes in a certain attribute. This is achieved in the following stages:

1. A `com.sun.appserv.management.monitor.JMXMonitorMgr` instance is obtained using the `DomainRoot.getJMXMonitorMgr()` method.

2. A `SampleListener` JMX notification listener that is provided in the sample package is instantiated.

3. A connection to the domain’s MBean server is obtained by calling `com.sun.appserv.management.client.ConnectionSource`. `getExistingMBeanServerConnection()` on the `JMXMonitorMgr` instance’s `Extra` information.

4. The `SampleListener` notification listener is added to the MBean server connection, with an MBean server delegate obtained from `getMBeanServerDelegateObject()`. The notification listener is now in place on the MBean server connection.

5. An AMX MBean, `sample`, of the type `SAMPLE` is obtained by calling the `com.sun.appserv.management.base.Container.getContainee()` method on an instance of the `Sample` interface. The `Sample` interface defines a basic AMX MBean.

6. An `AMXStringMonitor`, an AMX-compatible JMX `StringMonitorMBean`, is instantiated by calling `createStringMonitor` on the `JMXMonitorMgr` instance created above. The `AMXStringMonitor` instance then calls `waitMBeanServerNotification()`. The `waitMBeanServerNotification()` method waits for MBean server notifications of the type `REGISTRATION_NOTIFICATION` from the `SampleListener` instance that is listening on the MBean server connection.

7. An attribute of name `attrName` and value `attrValue` is added to the AMX MBean `sample`.

8. Various methods of the `AMXStringMonitor` instance are called, to add a listener, and to set the value to be observed, the object to be observed, and so on.

9. Access to the `sample` MBean’s attributes is obtained by passing the `sample` MBean’s `Extra` information to an instance of `com.sun.appserv.management.base.StdAttributesAccess`. The `StdAttributesAccess.setAttribute()` method is then called to change the values of these attributes.

10. The `AMXStringMonitor` then calls the sample notification listener’s `getNotifsReceived()` method to retrieve the notifications that resulted from the calls to `setAttribute()` above. The `waitNumNotifs()` method waits until four `ATTRIBUTE_CHANGE` notifications have been received before exiting.

11. The notification listener is then removed and the monitor is closed down.

## Undeploying Modules

The `undeploy()` method demonstrates how to undeploy a module.

##### Example 16–14 Undeploying Modules

    [...]
    undeploy ( final String moduleName ) throws IOException
    {
        final DeploymentMgr mgr = getDomainRoot().getDeploymentMgr();

        final Map statusData = mgr.undeploy( moduleName, null );
        final DeploymentStatus status =
            DeploymentSupport.mapToDeploymentStatus( statusData );
        println( "Undeployment result: "
            + getStageStatusString(status.getStageStatus()));
        if ( status.getStageThrowable() != null )
        {
            status.getStageThrowable().printStackTrace();
        }
    }
    [...]

The `undeploy()` method obtains the `DeploymentMgr` instance for the domain in the same way that `deploy()` does so. It then calls the `DeploymentMgr.undeploy()` method for a named module.

## Stopping an Application Server

The `stopServer()` method demonstrates how to stop an application server. The `stopServer()` method simply calls the `getJ2EEServer()` method on a given server instance, and then calls `J2EEServer.stop()`.

# Running the AMX Samples

To set up your development environment for using AMX, you must ensure that your Java classpath contains the following Java archive (JAR) files:

- `appserv-admin.jar` - The JAR file containing the AMX interfaces needed for your client. This file is found in install-dir`/lib/`. No other classes from this JAR file should be used by your program.

- `jmxri.jar` - The runtime libraries for the JMX Reference Implementation. If you are using JDK 1.5, these are already in the JDK.

- `jmxremote.jar` - The runtime libraries for the JMX Remote API. If you are using JDK 1.5, these are already in the JDK.

- `j2ee.jar` - The runtime libraries for the J2EE Platform. This file is found in install-dir`/lib/`. This JAR file is needed only if you intend to use any of the J2EE Management Statistic classes (`javax.management.j2ee.*`).

Start your Java application in a manner similar to this:

    export JAR_PATH=install-dir/lib/
    export CP="$JAR_PATH/j2ee.jar:$JAR_PATH/appserv-admin.jar"
    java -cp $CP com.mycompany.MyClientMain

- Previous: Part II Developing Applications and Application Components
- Next: Appendix A Deployment Descriptor Files

- © 2010, Oracle Corporation and/or its affiliates