Part III Using Services and APIs
Chapter 15 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 EJB 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.
Note –
The Application Server does not support connection pooling or transactions
for an application’s database access if it does not use standard Java
EE DataSource objects.
This chapter discusses the following topics:
General Steps for Creating a JDBC Resource
To prepare a JDBC resource for use in Java EE applications deployed
to the Application Server, perform the following tasks:
For information about how to configure some specific JDBC drivers, see Configurations for Specific JDBC Drivers in Sun Java System Application Server Platform Edition 9 Administration Guide.
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 9 Release Notes.
For configurations of supported and other drivers, see Configurations for Specific JDBC Drivers in Sun Java System Application Server Platform Edition 9 Administration Guide.
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 directory, then restart
the server. This makes classes accessible to any application or module across
the domain. For more information about Application Server class loaders, see Chapter 2, Class Loaders.
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 JDBC Connection Pool
You can test a JDBC connection pool for usability in one of these ways:
-
In
the Admin Console, open the Resources component, open the JDBC component,
select Connection Pools, and select the connection pool you want to test.
Then select the Ping button in the top right corner of the page. For details,
click the Help button in the Admin Console.
-
Use the asadmin ping-connection-pool command.
For details, see the Sun Java System Application Server Platform Edition 9 Reference Manual.
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 Java EE 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 Chapter 2, JDBC Resources, in Sun Java System Application Server Platform Edition 9 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.jdbc.DataSource ds = (com.sun.appserv.jdbc.DataSource)
ctx.lookup("jdbc/MyBase");
Connection con = ds.getConnection();
Connection drivercon = ds.getConnection(con);
// Do db operations.
con.close();
Using Non-Transactional Connections
You can specify a non-transactional database connection in any of these
ways:
-
Check the Non-Transactional Connections box on the JDBC Connection
Pools page in the Admin Console. The default is unchecked. For more information,
click the Help button in the Admin Console.
-
Specify
the --nontransactionalconnections option in the asadmin
create-jdbc-connection-pool command. For more information, see the Sun Java System Application Server Platform Edition 9 Reference Manual.
-
Use the DataSource implementation in the Application Server,
which provides a getNonTxConnection method. This method
retrieves a JDBC connection that is not in the scope of any transaction. There
are two variants.
public java.sql.Connection getNonTxConnection() throws java.sql.SQLException
public java.sql.Connection getNonTxConnection(String user, String password) throws java.sql.SQLException
-
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 16, Using the Transaction Service and Chapter 10, Transactions, in Sun Java System Application Server Platform Edition 9 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 15–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:
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource)
ctx.lookup("jdbc/MyBase");
Connection con = ds.getConnection();
DatabaseMetaData dbmd = con.getMetaData();
if (dbmd.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.
Allowing Non-Component Callers
You can allow non-Java-EE components, such as servlet filters, lifecycle
modules, and third party persistence managers, to use this JDBC connection
pool. The returned connection is automatically enlisted with the transaction
context obtained from the transaction manager. Standard Java EE components
can also use such pools. Connections obtained by non-component callers are
not automatically closed at the end of a transaction by the container. They
must be explicitly closed by the caller.
You can enable non-component callers in the following ways:
-
Check the Allow Non Component Callers box on the JDBC Connection
Pools page in the Admin Console. The default is false.
For more information, click the Help button in the Admin Console.
-
Specify the --allownoncomponentcallers option
in the asadmin create-jdbc-connection-pool command. For
more information, see the Sun Java System Application Server Platform Edition 9 Reference Manual.
-
Create a JDBC resource with a __pm suffix.
Chapter 16 Using the Transaction Service
The Java EE platform provides several abstractions that simplify
development of dependable transaction processing for applications.
This chapter discusses Java EE 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 Chapter 10, Transactions, in Sun Java System Application Server Platform Edition 9 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 “Chapter 35: Transactions”
in the Java EE 5 Tutorial.
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 Chapter 10, Transactions, in Sun Java System Application Server Platform Edition 9 Administration Guide.
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 Java EE 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.
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 Admin Console,
open the Transaction Service component under the relevant configuration.
For details, click the Help button in the Admin Console.
-
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
server.transaction-service.property.db-logging-resource = jdbc/TxnDS
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 9 Reference Manual.
The Transaction Manager, the Transaction
Synchronization Registry, and UserTransaction
You can access the Application Server transaction manager, a javax.transaction.TransactionManager implementation, using the JNDI subcontext java:appserver/TransactionManager. You can access the Application Server transaction synchronization
registry, a javax.transaction.TransactionSynchronizationRegistry implementation, using the JNDI subcontext java:appserver/TransactionSynchronizationRegistry. Accessing the transaction synchronization registry is
recommended. For details, see Java
Specification Request (JSR) 907.
You can also access java:comp/UserTransaction.
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 Admin 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 and the automatic-recovery attribute to false. Do this only if
performance is more important than transaction recovery.
Storing Transaction Logs in a Database
For multi-core machines, logging transactions to a database
may be more efficient.
To log transactions to a database, follow these steps:
-
Create a JDBC connection Pool, and set the non-transactional-connections attribute to true.
-
Create a JDBC resource that uses the connection pool
and note the JNDI name of the JDBC resource.
-
Create a table named txn_log_table with
the schema shown in Table 16–1.
-
Add the db-logging-resource property
to the transaction service. For example:
asadmin set --user adminuser server.transaction-service.property.db-logging-resource="jdbc/TxnDS"
|
The property's value should be the JNDI name of the JDBC resource
configured previously.
-
To disable file synchronization, use the following asadmin
create-jvm-options command:
asadmin create-jvm-options --user adminuser -Dcom.sun.appserv.transaction.nofdsync
|
-
Restart the server.
For information about JDBC connection pools and resources, see Chapter 15, Using the JDBC API for Database Access. For more information about the asadmin create-jvm-options command, see the Sun Java System Application Server Platform Edition 9 Reference Manual.
Table 16–1 Schema for
txn_log_table
|
Column Name
|
JDBC Type
|
|
LOCALTID
|
BIGINT
|
|
SERVERNAME
|
VARCHAR(n)
|
|
GTRID
|
VARBINARY
|
The size of the SERVERNAME column should
be at least the length of the Application Server host name plus 10 characters.
The size of the GTRID column should be at
least 64 bytes.
Recovery Workarounds
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.
In the 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.
Chapter 17 Using the Java Naming and Directory Interface
A naming service maintains a set of bindings,
which relate names to objects. The Java EE 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 EJB 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 Java EE 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 Java EE 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.
Global JNDI Names
Global JNDI names are assigned according to the following precedence
rules:
-
A global JNDI name assigned in the sun-ejb-jar.xml, sun-web.xml, or sun-application-client.xml deployment descriptor file has the highest precedence.
See Mapping References.
-
A global JNDI name assigned in a mapped-name element
in the ejb-jar.xml, web.xml,
or application-client.xml deployment descriptor
file has the second highest precedence. The following elements have mapped-name subelements: resource-ref, resource-env-ref, ejb-ref, message-destination, message-destination-ref, session, message-driven, and entity.
-
A global JNDI name assigned in a mappedName attribute
of an annotation has the third highest precedence. The following annotations
have mappedName attributes: @javax.annotation.Resource, @javax.ejb.EJB, @javax.ejb.Stateless, @javax.ejb.Stateful, and @javax.ejb.MessageDriven.
-
A default global JNDI name is assigned in some cases
if no name is assigned in deployment descriptors or annotations.
-
For an EJB 2.x dependency or a session or entity bean
with a remote interface, the default is the fully qualified name of
the home interface.
-
For an EJB 3.0 dependency or a session bean with a
remote interface, the default is the fully qualified name of the
remote business interface.
-
If both EJB 2.x and EJB 3.0 remote interfaces are
specified, or if more than one 3.0 remote interface is specified,
there is no default, and the global JNDI name must be specified.
-
For all other component dependencies that must be
mapped to global JNDI names, the default is the name of the dependency
relative to java:comp/env. For example, in the @Resource(name="jdbc/Foo") DataSource ds; annotation, the
global JNDI name is jdbc/Foo.
Accessing EJB Components Using the CosNaming Naming Context
The preferred way of accessing the naming service, even in code
that runs outside of a Java EE 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 the java.naming.factory.initial property
to com.sun.jndi.cosnaming.CNCtxFactory in the client JVM when accessing EJB components. You can
set this property as a command-line argument, as follows:
-Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory
|
Or you can set this property in the code, as follows:
Properties properties = null;
try {
properties = new Properties();
properties.put("java.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 Java EE 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 to 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 Java EE 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 tasks based on Java technology 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 13, 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:
-
To create an external JNDI resource using the Admin Console,
open the Resources component, open the JNDI component, and select
External Resources. For details, click the Help button in the Admin Console.
-
To create an external JNDI resource, use the asadmin
create-jndi-resource command. For details, see the Sun Java System Application Server Platform Edition 9 Reference Manual.
Custom Resources
A custom resource specifies a custom server-wide resource object
factory that implements the javax.naming.spi.ObjectFactory interface.
There is no specific JNDI parent context for external JNDI resources,
except for the standard java:comp/env/.
Create a custom resource in one of these ways:
-
To create a custom resource using the Admin Console,
open the Resources component, open the JNDI component, and select
Custom Resources. For details, click the Help button in the Admin Console.
-
To create a custom resource, use the asadmin
create-custom-resource command. For details, see the Sun Java System Application Server Platform Edition 9 Reference Manual.
Using a Custom jndi.properties File
To use a custom jndi.properties file, specify
the path to the file in one of the following ways:
-
Use the Admin Console. Select the Application Server component,
select the JVM Settings tab, select the Path Settings tab, and edit
the Classpath Prefix field. For details, click the Help button in
the Admin Console.
-
Edit the classpath-prefix attribute
of the java-config element in the domain.xml file.
For details about domain.xml, see the Sun Java System Application Server Platform Edition 9 Administration Reference.
This adds the jndi.properties file to the
Shared Chain class loader. For more information about class loading,
see Chapter 2, Class Loaders.
For each property found in more than one jndi.properties file,
the Java EE naming service either uses the first value found or concatenates
all of the values, whichever makes sense.
Mapping References
The following XML elements in the Application Server deployment descriptors
map resource references in application client, EJB, and web application
components to JNDI names configured in the Application Server:
-
resource-env-ref - Maps the @Resource or @Resources annotation (or the resource-env-ref element in the corresponding Java EE XML file) to the absolute
JNDI name configured in the Application Server.
-
resource-ref - Maps the @Resource or @Resources annotation (or the resource-ref element in the corresponding Java EE XML file) to the absolute
JNDI name configured in the Application Server.
-
ejb-ref - Maps the @EJB annotation
(or the ejb-ref element in the corresponding Java
EE 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.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, in Sun Java System Application Server Platform Edition 9 Application Deployment Guide.
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 annotation in the application
code looks like this:
@Resource(name="jdbc/helloDbDs") javax.sql.DataSource ds;
This references a resource with the JNDI name of java:comp/env/jdbc/helloDbDs. If this is the JNDI name of the JDBC resource configured
in the Application Server, the annotation alone is enough to reference
the resource.
However, you can use an Application Server specific deployment descriptor
to override the annotation. For example, the resource-ref element
in the sun-web.xml file maps the res-ref-name (the name specified in the annotation) to the JNDI name
of another JDBC resource configured in the Application Server.
<resource-ref>
<res-ref-name>jdbc/helloDbDs</res-ref-name>
<jndi-name>jdbc/helloDbDataSource</jndi-name>
</resource-ref>
Chapter 18 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 “Chapter 33: The
Java Message Service API” in the Java EE 5 Tutorial.
For detailed information about JMS concepts and JMS support in the Application Server,
see Chapter 3, Configuring Java Message Service Resources, in Sun Java System Application Server Platform Edition 9 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: EMBEDDED, LOCAL,
or REMOTE. The effects of these choices on the Message Queue broker
life cycle are as follows:
-
If the type is EMBEDDED, the Application Server and Message Queue software
run in the same JVM. The Message Queue broker is started and stopped automatically
by the Application Server. This is the default.
Lazy initialization
starts the default embedded broker on the first access of JMS services rather
than at Application Server startup.
-
If the type is LOCAL, the Message Queue broker
starts when the Application Server starts.
-
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/1343.3.
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 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 12, Developing Connectors.
Generic Resource Adapter
The Application Server provides a generic resource adapter for JMS. For details,
see http://genericjmsra.dev.java.net/ and Configuring the Generic Resource Adapter for JMS in Sun Java System Application Server Platform Edition 9 Administration Guide.
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 Chapter 3, Configuring Java Message Service Resources, in Sun Java System Application Server Platform Edition 9 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 Admin Console, open the Java Message Service component under the
relevant configuration. For details, click the Help button in the Admin Console.
-
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 = EMBEDDED
server.jms-service.start-args =
server.jms-service.default-jms-host = default_JMS_host
server.jms-service.reconnect-interval-in-seconds = 5
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 9 Reference Manual.
You can override the JMS Service configuration using JMS connection
factory settings. For details, see Chapter 3, Configuring Java Message Service Resources, in Sun Java System Application Server Platform Edition 9 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 uses for performing all Message Queue broker
administrative operations, such as creating and deleting JMS destinations.
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:
For machines having more than one host, use the Host field in the Admin Console or
the -–mqhost option of create-jms-host to
specify the address to which the broker binds.
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 9 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:
-
Use the Admin Console. Open the
Resources component, open the JMS Resources component, then select Physical
Destinations. For details, click the Help button in the Admin Console.
-
Use the asadmin create-jmsdest command. This
command acts on the default JMS host. For details, see the Sun Java System Application Server Platform Edition 9 Reference Manual.
To
purge all messages currently queued at a physical destination, use the asadmin
flush-jmsdest command. This deletes the messages before they reach
any message consumers. For details, see the Sun Java System Application Server Platform Edition 9 Reference Manual.
To create a destination resource, see Creating JMS Resources: Destinations and Connection Factories.
Creating JMS Resources: Destinations and Connection
Factories
You can create two kinds of JMS resources in the Application Server:
-
Connection Factories –
administered objects that implement the ConnectionFactory, QueueConnectionFactory, or TopicConnectionFactory interfaces.
-
Destination Resources – administered objects
that implement the Queue or Topic interfaces.
In either case, the steps for creating a JMS resource are the same.
You can create a JMS resource in the following ways:
-
To create a JMS resource using the Admin Console,
open the Resources component, then open the JMS Resources component. Click
Connection Factories to create a connection factory, or click Destination
Resources to create a queue or topic. For details, click the Help button in
the Admin Console.
-
A JMS resource is a type of connector. To create a JMS resource
using the command line, see Deploying and Configuring a Stand-Alone Connector Module.
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 Admin 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.
The other addresslist-behavior alternative is priority, which specifies that the first broker in the AddressList is
selected first. This first broker is the local colocated Message Queue broker.
If this broker is unavailable, connection attempts are made to brokers in
the order in which they are listed in 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 Chapter 3, Configuring Java Message Service Resources, in Sun Java System Application Server Platform Edition 9 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.
Authentication With ConnectionFactory
If your web, EJB, or client module has res-auth set
to Container, but you use the ConnectionFactory.createConnection("user","password") method to get a connection, the Application Server searches the container
for authentication information before using the supplied user and password.
Version 7 of the Application Server threw an exception in this situation.
Message Queue varhome Directory
The Sun Java System Message Queue software uses a default directory
for storing data such as persistent messages and its log file. This directory
is called varhome. The Application Server uses domain-dir/imq as the varhome directory if the type of
relationship between the Application Server and the Message Queue software is LOCAL or EMBEDDED. If the relationship type is REMOTE, the Message Queue software determines the varhome location.
For more information about the types of relationships between the Application
Server and Message Queue, see The JMS Provider.
When executing Message Queue scripts such as install-dir/imq/bin/imqusermgr, use the -varhome option to point the scripts
to the Message Queue data if the relationship type is LOCAL or EMBEDDED. For example:
imqusermgr -varhome $AS_INSTALL/domains/domain1/imq add -u testuser
For more information about the Message Queue software, refer to the
documentation at http://docs.sun.com/app/docs/coll/1343.3.
Delivering SOAP Messages Using the JMS API
Web service clients use the Simple Object Access Protocol (SOAP) to
communicate with web services. SOAP uses a combination of XML-based data structuring
and Hyper Text Transfer Protocol (HTTP) to define a standardized way of invoking
methods in objects distributed in diverse operating environments across the
Internet.
For more information about SOAP, see the Apache SOAP web site at http://xml.apache.org/soap/index.html.
You can take advantage of the JMS provider’s reliable messaging
when delivering SOAP messages. You can convert a SOAP message into a JMS message,
send the JMS message, then convert the JMS message back into a SOAP message.
The following sections explain how to do these conversions:
To Send SOAP Messages Using the JMS API
-
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 19 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 Chapter 4, Configuring JavaMail Resources, in Sun Java System Application Server Platform Edition 9 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
Looking Up a JavaMail Session
The standard Java Naming and Directory Interface (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 17, Using the Java Naming and Directory Interface.
Sending and Reading Messages Using JavaMail
The following sections describe how to send and read messages
using the JavaMail API:
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 20 Using the Application Server Management
Extensions
Sun Java System Application Server uses Application Server Management
eXtensions (AMX) for management and monitoring purposes. AMX
technology exposes managed resources for remote management as the
Java Management eXtensions (JMXTM)
API.
The Application Server incorporates the JMX 1.2 Reference Implementation, which was
developed by the Java Community Process as Java Specification
Request (JSR) 3, and the JMX Remote API 1.0 Reference Implementation
, which is 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. For more information about JMX, see the JMX specifications and Reference Implementations.
For information about creating custom MBeans, see Chapter 14, Developing Custom MBeans.
This chapter contains the following topics:
About AMX
AMX is an API that exposes all of the Application Server configuration,
monitoring and JSR 77 MBeans as easy-to-use client-side dynamic proxies
implementing the AMX interfaces. To understand the design and implementation
of the AMX API, you can get started with this white
paper.
Complete API documentation for AMX is provided in the Application Server package.
com.sun.appserv.management
The code samples in this section are taken from the package:
com.sun.appserv.management.sample
The Application Server is based around the concept of administration
domains. Each domain consists 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 using
standard JMX APIs (for example, MBeanServerConnection),
most users find the use of the AMX client-side dynamic proxies much
more convenient.
Virtually all components of the Application Server are visible for
monitoring and management through 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 interfaces. The interfaces
are implemented by client-side dynamic proxies, each of which
is associated with a server-side MBean in the Domain Administration
Server (DAS). AMX provides routines to obtain proxies for MBeans,
starting with the DomainRoot interface (see http://glassfish.dev.java.net/nonav/javaee5/amx/javadoc/com/sun/appserv/management/DomainRoot.html).
Note –
The term AMX interface in the context of this document
should be understood as synonymous with a client-side dynamic proxy
implementing that interface.
You can navigate generically through the MBean hierarchy using
the com.sun.appserv.management.base.Container interface
(see http://glassfish.dev.java.net/nonav/javaee5/amx/javadoc/com/sun/appserv/management/base/Container.html). 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
the AMX interfaces use strongly typed proxies implementing the interface(s).
AMX MBeans
All AMX MBeans are represented as interfaces in a subpackage
of com.sun.appserv.management (see http://glassfish.dev.java.net/nonav/javaee5/amx/javadoc/com/sun/appserv/management/package-summary.html) and are implemented by dynamic proxies on the
client-side. Note that client-side means any client, wherever it resides.
AMX may be used within the server itself such as in a custom MBean.
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.
All AMX MBeans can be reached by navigating through the DomainRoot.
Note –
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.
AMX defines different types of MBean, namely, configuration MBeans, monitoring MBeans, utility MBeans and Java EE management JSR 77 MBeans. These MBeans
are logically related in the following ways:
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 through 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.
Java EE Management MBeans
The Java EE management MBeans implement, and in some cases extend,
the management hierarchy as defined by JSR 77,
which specifies the management model for the whole Java EE platform.
The AMX JSR 77 MBeans offer access to configuration and monitoring
MBeans using the getMonitoringPeer() and getConfigPeer() methods.
The Group Attribute of Java EE 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 (see http://glassfish.dev.java.net/nonav/javaee5/amx/javadoc/com/sun/appserv/management/deploy/DeploymentMgr.html).
MBean Notifications
All AMX MBeans that emit Notifications place a java.util.Map within the UserData field of a standard
JMX Notification, which can be obtained using Notification.getUserData(). Within the map are one or more items, which vary according
to the Notification type. Each Notification type, and the data available
within the Notification, is defined in the Javadoc of the MBean (AMX
interface) that emits it.
Note that certain standard Notifications, such as javax.management.AttributeChangeNotification (see http://java.sun.com/j2se/1.5.0/docs/api/javax/management/AttributeChangeNotification.html) do not and cannot follow this behavior.
Access to MBean Attributes
An AMX MBean Attribute is accessible in three
ways:
-
Dotted names using MonitoringDottedNames and ConfigDottedNames
-
Attributes on MBeans using 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 through the command line
interface are available as Attributes within a single MBean. This
includes properties, which are provided as Attributes beginning with
the prefix property., for example, server.property.myproperty.
Note –
Certain attributes that ought to 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}.
Dynamic Client Proxies
Dynamic Client Proxies are an important part of the AMX API,
and enhance ease-of-use for the programmer.
JMX MBeans can be used directly by an MBeanServerConnection (see http://java.sun.com/j2se/1.5.0/docs/api/javax/management/MBeanServerConnection.html) to the server. However, client proxies greatly
simplify access to Attributes and operations on MBeans, offering get/set
methods and type-safe invocation of operations. Compiling against
the AMX interfaces means that compile-time checking is performed,
as opposed to server-side runtime checking, when invoked generically
through MBeanServerConnection.
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, by usingMBeanServerConnection), 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
using 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. The com.sun.appserv.management.helper.Connect class (see http://glassfish.dev.java.net/nonav/javaee5/amx/javadoc/com/sun/appserv/management/helper/Connect.html) is also available.
Examining AMX Code Samples
An overview of the AMX API and code samples that demonstrate
various uses of the AMX API can be found at http://glassfish.dev.java.net/nonav/javaee5/amx/samples/javadoc/index.html and http://glassfish.dev.java.net/nonav/javaee5/amx/samples/javadoc/amxsamples/Samples.html.
The sample implementation is based around the SampleMain class.
The principal uses of AMX demonstrated by SampleMain are
the following:
All of these actions are performed by commands that you give
to SampleMain. Although these commands are executed
by SampleMain, they are defined as methods of the
class Samples, which is also found in the com.sun.appserv.management.sample package.
The SampleMain Class
The SampleMain class creates a connection
to a DAS, and creates an interactive loop in which you can run the
various commands defined in Samples that demonstrate
different uses of AMX.
Connecting to the DAS
The connection to the DAS is shown in the following code.
Example 20–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 using 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.
After 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 Samples.startServer method demonstrates
how to start an Application Server.
In this sample AMX implementation, all the tasks are performed
by the command start-server when you run SampleMain. See the startServer method to see how
this command is implemented. Click the method name to see the source
code.
Deploying an Archive
The Samples.uploadArchive() and deploy methods
demonstrate how to upload and deploy a Java EE archive file.
Displaying the AMX MBean Hierarchy
The Samples.displayHierarchy method
demonstrates how to display the AMX MBean hierarchy.
Setting Monitoring States
The Samples.setMonitoring method demonstrates
how to set monitoring states.
Accessing AMX MBeans
The Samples.handleList method demonstrates
how to access many (but not all) configuration elements.
Accessing and Displaying the Attributes of
an AMX MBean
The Samples.displayAllAttributes method demonstrates
how to access and display the attributes of an AMX MBean.
Listing AMX MBean Properties
The Samples.displayAllProperties method
demonstrates how to list AMX MBean properties.
Performing Queries
The Samples.demoQuery method demonstrates
how to perform queries.
The demoQuery() method uses other methods
that are defined by Samples, namely displayWild(), and displayJ2EEType().
Monitoring Attribute Changes
The Samples.demoJMXMonitor method demonstrates
how to monitor attribute changes.
Undeploying Modules
The Samples.undeploy method demonstrates
how to undeploy a module.
Stopping an Application Server
The Samples.stopServer method demonstrates
how to stop an Application Server. The stopServer method
simply calls the Samples.getJ2EEServer method on
a given server instance, and then calls J2EEServer.stop.
Running the AMX Samples
The following section lists the steps to run the AMX samples.
To Run the AMX Sample
-
Ensure that the JAR file appserv-ext.jar has
been added to your classpath. Some examples also require that j2ee.jar be present.
-
Define a SampleMain.properties file,
which provides the parameters required by AppserverConnectionSource to connect to the DAS.
The file SampleMain.properties file should use the following format:
connect.host=localhost
connect.port=8686
connect.user=admin
connect.password=admin123
connect.truststore=sample-truststore
connect.truststorePassword=changeme
connect.useTLS=true
-
Scripts are provided in the com.sun.appserv.management.sample package to run the AMX samples.
Start SampleMain by running the appropriate script for your platform:
-
After SampleMain is running, you can
interact with it by typing the commands examined above:
-
Enter Command> start-server serverName
-
Enter Command> list-attributes
You see output like this:
--- Attributes for X-DomainRoot=amx ---
AttributeNames=[...]
BulkAccessObjectName=amx:j2eeType=X-BulkAccess,name=na
DomainConfigObjectName=amx:j2eeType=X-DomainConfig,name=na
MBeanInfoIsInvariant=true
J2EEDomainObjectName=amx:j2eeType=J2EEDomain,name=amx
AppserverDomainName=amx
ObjectName=amx:j2eeType=X-DomainRoot,name=amx
[...]
-
Enter Command> show-hierarchy
You see output like this:
X-DomainRoot=amx
X-ConfigDottedNames
X-SystemInfo
X-QueryMgr
X-DeploymentMgr
X-UploadDownloadMgr
X-BulkAccess
X-MonitoringDottedNames
X-JMXMonitorMgr
X-Sample
X-DomainConfig
X-WebModuleConfig=admingui
X-WebModuleConfig=adminapp
X-WebModuleConfig=com_sun_web_ui
X-JDBCResourceConfig=jdbc/PointBase
X-JDBCResourceConfig=jdbc/__TimerPool
X-J2EEApplicationConfig=MEjbApp
[...]
-
Enter Command> list
You see output like this:
--- Top-level ---
ConfigConfig: [server2-config, default-config, server-config,
server3-config]
ServerConfig: [server3, server, server2]
StandaloneServerConfig: [server3, server, server2]
ClusteredServerConfig: []
ClusterConfig: []
[...]
-
Enter Command> list-properties
You see output like this:
Properties for:
amx:j2eeType=X-JDBCConnectionPoolConfig,name=PointBasePool
Password=pbPublic
DatabaseName=jdbc:pointbase:server://localhost:9092/sun-appserv-samples
User=pbPublic
[...]
-
Enter Command> query
You see output like this:
--- Queried for j2eeType=X-*ResourceConfig ---
j2eeType=X-JDBCResourceConfig,name=jdbc/PointBase
j2eeType=X-JDBCResourceConfig,name=jdbc/__TimerPool
[...]
-
And so on for the other commands:
Enter
Command> demo-jmx-monitor
Enter Command> set-monitoring monitoringLevel (one of HIGH, LOW or OFF)
Enter Command> stop-server serverName
Enter Command> quit