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 Platform Edition 8.2 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
To prepare a JDBC resource for use in J2EE applications deployed
to the Application Server, perform the following tasks:
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
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 Platform Edition 8.2 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:
Testing a Connection Pool
You can test a JDBC connection pool for usability in one of
these ways:
Both these commands fail and display an error message unless
they successfully connect to the connection pool.
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:
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
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 Platform Edition 8.2 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 Platform Edition 8.2 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.2 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.2 and
are found to be J2EE compatible. They are also supported for CMP.
For an up to date list of currently supported JDBC drivers,
see the Sun Java System Application Server Platform Edition 8.2 Release Notes.
Other JDBC drivers can be used with Application Server 8.2,
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.2.
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 Platform Edition 8.2 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.
Derby Type 4 Driver
The Derby JDBC driver is included with the Application Server by
default, except for the Solaris bundled installation, which does not
include Derby. Therefore, unless you have the Solaris bundled installation,
you do not need to integrate this JDBC driver with the Application Server.
The JAR file for the Derby driver is derbyclient.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: Derby
-
DataSource Classname: Specify
one of the following:
org.apache.derby.jdbc.ClientDataSource
org.apache.derby.jdbc.ClientXADataSource
-
Properties:
-
user - Specify the database
user.
This is only necessary if Derby is configured to
use authentication. Derby does not use authentication
by default. When the user is provided, it is the name of the schema
where the tables reside.
-
password - Specify the database
password.
This is only necessary if Derby is configured
to use authentication.
-
databaseName - Specify the
name of the database.
-
serverName - Specify the host
name or IP address of the database server.
-
portNumber - Specify the port
number of the database server if it is different from the default.
-
URL: jdbc:derby://serverName:portNumber/databaseName;create=true
Include the ;create=true part
only if you want the database to be created if it does not exist.
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 8i,
9i, and 10g 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.
MM MySQL Type 4 Driver (Non-XA)
The JAR file for the MySQL driver is mysql-connector-java-version-bin-g.jar,
for example, mysql-connector-java-3.1.12-bin-g.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: mysql
-
DataSource Classname: Specify
one of the following:
com.mysql.jdbc.jdbc2.optional.MysqlDataSource
-
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"
MM MySQL Type 4 Driver (XA Only)
The JAR file for the MySQL driver is mysql-connector-java-version-bin-g.jar,
for example, mysql-connector-java-3.1.12-bin-g.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: mysql
-
DataSource Classname: Specify
one of the following:
com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
-
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"
Inet Oraxo JDBC Driver for Oracle 8i, 9i,
and 10g 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 8i,
9i, and 10g 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 8i, 9i,
and 10g 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.
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:
For more information about the JavaTM Transaction API (JTA) and Java Transaction Service (JTS),
see the Sun Java System Application Server Platform Edition 8.2 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:
For details about how transaction resource managers, the transaction
service, and applications interact, see the Sun Java System Application Server Platform Edition 8.2 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 Platform Edition 8.2 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 Platform Edition 8.2 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
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:
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
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:
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:
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 Platform Edition 8.2 Administration Guide.
This chapter contains the following sections:
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 are as follows:
-
If the type is LOCAL, the Message Queue
broker starts when the Application Server starts. This is the default.
-
If the type is REMOTE, the Message Queue
broker must be started separately. For information about starting the broker,
see the Sun Java System Message Queue 3.7 UR1 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.2.
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:
You 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:
For more information about JMS administration tasks, see the Sun Java System Application Server Platform Edition 8.2 Administration Guide and
the Sun Java System Message Queue 3.7 UR1 Administration Guide.
Configuring the JMS Service
The JMS Service configuration is available to all inbound and outbound
connections pertaining to the Application Server.
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 Platform Edition 8.2 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 Platform Edition 8.2 Reference Manual.
You can override the JMS Service configuration using JMS connection
factory settings. For details, see the Sun Java System Application Server Platform Edition 8.2 Administration Guide.
Note –
The Application Server 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:
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 Platform Edition 8.2 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.
However, it is good practice to create the physical destination beforehand.
You can create a JMS physical destination in the following ways:
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:
Note –
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:
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 Platform Edition 8.2 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.
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. Thus, for the
default Application Server domain, Message Queue data is stored in the following
location:
install-dir/domains/domain1/imq/var/instances/imqbroker
Version 7 of the Application Server stored this data in the following location:
install-dir/imq/var/instances/domain1_server
When executing Message Queue scripts such as install-dir/imq/bin/imqusermgr, use the -varhome option. For example:
imqusermgr -varhome $AS_INSTALL/domains/domain1/imq add -u testuser
-p testpassword
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
-
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.
-
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);
-
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();
-
Convert the SOAP message to a JMS message by calling the MessageTransformer.SOAPMessageintoJMSMessage() method.
Message m = MessageTransformer.SOAPMessageIntoJMSMessage (soapMessage,
session );
-
Publish the JMS message.
publisher.publish(m);
-
Close the JMS connection.
tc.close();
To receive SOAP messages using the JMS API
-
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.
-
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();
-
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 ); }
-
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
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 Platform Edition 8.2 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:
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
-
Import the packages that you need.
import java.util.*;
import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.naming.*;
-
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.
-
Override the JavaMail session properties if necessary.
For example:
Properties props = session.getProperties();
props.put("mail.from", "user2@mailserver.com");
-
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);
-
Send the message.
Transport.send(msg);
To read a message using JavaMail
-
Import the packages that you need.
import java.util.*;
import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.naming.*;
-
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.
-
Override the JavaMail session properties if necessary.
For example:
Properties props = session.getProperties();
props.put("mail.from", "user2@mailserver.com");
-
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");
-
Get the INBOX folder.
Folder folder = store.getFolder("INBOX");
-
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
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 or a manageable entity within a server.
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}.
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:
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:
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:
-
A com.sun.appserv.management.monitor.JMXMonitorMgr instance is obtained using the DomainRoot.getJMXMonitorMgr() method.
-
A SampleListener JMX notification
listener that is provided in the sample package is instantiated.
-
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.
-
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.
-
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.
-
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.
-
An attribute of name attrName and
value attrValue is added to the AMX MBean sample.
-
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.
-
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.
-
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.
-
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