Sun GlassFish Enterprise Server v3 Application Development Guide

Part III Using Services and APIs

Chapter 14 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 GlassFishTM Enterprise Server. This chapter also provides high level JDBC implementation instructions for servlets and EJB components using the Enterprise Server. If the JDK version 1.6 is used, the Enterprise Server supports the JDBC 4.0 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 Enterprise 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 Enterprise Server, perform the following tasks:

For information about how to configure some specific JDBC drivers, see Configuration Specifics for JDBC Drivers in Sun GlassFish Enterprise Server v3 Administration Guide.

Integrating the JDBC Driver

To use JDBC features, you must choose a JDBC driver to work with the Enterprise 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 Enterprise Server, see the Sun GlassFish Enterprise Server v3 Release Notes. For configurations of supported and other drivers, see Configuration Specifics for JDBC Drivers in Sun GlassFish Enterprise Server v3 Administration Guide.


Note –

Because the drivers and databases supported by the Enterprise 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 an Enterprise Server domain, copy the JAR files into the domain-dir/lib directory, then restart the server. This makes classes accessible to all applications or modules deployed on servers that share the same configuration. For more information about Enterprise Server class loaders, see Chapter 2, Class Loaders.

If you are using an Oracle database with EclipseLink extensions, copy the JAR files into the domain-dir/lib/ext directory, then restart the server. For details, see Oracle Database Enhancements.

Automatic Detection of Installed Drivers

The Administration Console detects installed JDBC Drivers automatically when you create a JDBC connection pool. To create a JDBC connection pool using the Administration Console, open the Resources component, open the JDBC component, select Connection Pools, and click on the New button. This displays the New JDBC Connection Pool page.

Based on the Resource Type and Database Vendor you select on the New JDBC Connection Pool page, data source or driver implementation class names are listed in the Datasource Classname or Driver Classname field when you click on the Next button. When you choose a specific implementation class name on the next page, additional properties relevant to the installed JDBC driver are displayed in the Additional Properties section.

Creating a JDBC Connection Pool

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

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

For a complete description of JDBC connection pool features, see the Sun GlassFish Enterprise Server v3 Administration Guide.

Modifying a JDBC Connection Pool

In the Administration Console, some JDBC connection pool attributes are advanced, and you cannot set them during JDBC connection pool creation. You can only set them when modifying an existing JDBC connection pool. You can also use the asadmin set command to set or reset a JDBC connection pool's attributes.

You can modify 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:

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

You can also specify that a connection pool is automatically tested when created or reconfigured by setting the Ping attribute to true (the default is false) in one of the following ways:

Flushing a JDBC Connection Pool

Flushing a JDBC connection pool recreates all the connections in the pool and brings the pool to the steady pool size without the need for reconfiguring the pool. Connection pool reconfiguration can result in application redeployment, which is a time-consuming operation. Flushing destroys existing connections, and any existing transactions are lost and must be retired.

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

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:

Statements

The following features pertain to statements:

Using an Initialization Statement

You can specify a statement that executes each time a physical connection to the database is created (not reused) from a JDBC connection pool. This is useful for setting request or session specific properties and is suited for homogeneous requests in a single application. Set the Init SQL attribute of the JDBC connection pool to the SQL string to be executed in one of the following ways:

Setting a Statement Timeout

An abnormally long running JDBC query executed by an application may leave it in a hanging state unless a timeout is explicitly set on the statement. Setting a statement timeout guarantees that all queries automatically time out if not completed within the specified period. When statements are created, the queryTimeout is set according to the statement timeout setting. This works only when the underlying JDBC driver supports queryTimeout for Statement, PreparedStatement, CallableStatement, and ResultSet.

You can specify a statement timeout in the following ways:

Statement Caching

Statement caching stores statements, prepared statements, and callable statements that are executed repeatedly by applications in a cache, thereby improving performance. Instead of the statement being prepared each time, the cache is searched for a match. The overhead of parsing and creating new statements each time is eliminated.

Statement caching is usually a feature of the JDBC driver. The Enterprise Server provides caching for drivers that do not support caching. To enable this feature, set the Statement Cache Size for the JDBC connection pool in one of the following ways:

By default, this attribute is set to zero and the statement caching is turned off. To enable statement caching, you can set any positive nonzero value. The built-in cache eviction strategy is LRU-based (Least Recently Used). When a connection pool is flushed, the connections in the statement cache are recreated.

Statement Tracing

You can trace the SQL statements executed by applications that use a JDBC connection pool. Set the SQL Trace Listeners attribute to a comma-separated list of trace listener implementation classes in one of the following ways:

The Enterprise Server provides a public interface, org.glassfish.api.jdbc.SQLTraceListener, that implements a means of recording SQLTraceRecord objects. To make custom implementations of this interface available to the Enterprise Server, place the implementation classes in as-install/lib.

The Enterprise Server provides an SQL tracing logger to log the SQL operations in the form of SQLTraceRecord objects in the server.log file. The module name under which the SQL operation is logged is javax.enterprise.resource.sqltrace. SQL traces are logged as FINE messages along with the module name to enable easy filtering of the SQL logs. A sample SQL trace record looks like this:


[#|2009-11-27T15:46:52.202+0530|FINE|glassfishv3.0|javax.enterprise.resource.sqltrace.com.sun.gjc.util
|_ThreadID=29;_ThreadName=Thread-1;ClassName=com.sun.gjc.util.SQLTraceLogger;MethodName=sqlTrace;
|ThreadID=77 | ThreadName=p: thread-pool-1; w: 6 | TimeStamp=1259317012202 
| ClassName=com.sun.gjc.spi.jdbc40.PreparedStatementWrapper40 | MethodName=executeUpdate 
| arg[0]=insert into table1(colName) values(100) | arg[1]=columnNames | |#]

This trace shows that an executeUpdate(String sql, String columnNames) operation is being done.

Connections

The following features pertain to connections:

Disabling Pooling

To disable connection pooling, set the Pooling attribute to false. The default is true. You can enable or disable connection pooling in one of the following ways:

The pooling option and the system property com.sun.enterprise.connectors.SwitchoffACCConnectionPooling, which turns off connection pooling in the Application Client Container, do not affect each other.

An exception is thrown if associate-with-thread is set to true and pooling is disabled. An exception is thrown if you attempt to flush a connection pool when pooling is disabled. A warning is logged if the following attributes are used, because they are useful only in a pooled environment:

Associating Connections with Threads

To associate connections with a thread, set the Associate With Thread attribute to true. The default is false. A true setting allows connections to be saved as ThreadLocal in the calling thread. Connections get reclaimed only when the calling thread dies or when the calling thread is not in use and the pool has run out of connections. If the setting is false, the thread must obtain a connection from the pool each time the thread requires a connection.

The Associate With Thread attribute associates connections with a thread such that when the same thread is in need of connections, it can reuse the connections already associated with that thread. In this case, the overhead of getting connections from the pool is avoided. However, when this value is set to true, you should verify that the value of the Max Pool Size attribute is comparable to the Max Thread Pool Size attribute of the thread pool. If the Max Thread Pool Size value is much higher than the Max Pool Size value, a lot of time is spent associating connections with a new thread after dissociating them from an older one. Use this attribute in cases where the thread pool should reuse connections to avoid this overhead.

You can set the Associate With Thread attribute in the following ways:

Custom Connection Validation

You can specify a custom implementation for Connection Validation that is faster or optimized for a specific database. Set the Validation Method attribute to the value custom-validation. (Other validation methods available are table (the default), auto-commit, and meta-data.) The Enterprise Server provides a public interface, org.glassfish.api.jdbc.ConnectionValidation, which you can implement to plug in your implementation. A new attribute, Validation Classname, specifies the fully qualified name of the class that implements the ConnectionValidation interface. The Validation Classname attribute is required if Connection Validation is enabled and Validation Method is set to Custom Validation.

To enable this feature, set Connection Validation, Validation Method, and Validation Classname for the JDBC connection pool in one of the following ways:

By default, optimized validation mechanisms are provided for Java DB, MySQL, Oracle, and PostgreSQL databases. Additionally, for JDBC 4.0 compliant database drivers, a validation mechanism is provided that uses the Connection.isValid(0) implementation.

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 14, Administering Database Connectivity , in Sun GlassFish Enterprise Server v3 Administration Guide.

Marking Bad Connections

The DataSource implementation in the Enterprise Server provides a markConnectionAsBad method. A marked bad connection is removed from its connection pool when it is closed. The method signature is as follows:

public void markConnectionAsBad(java.sql.Connection con)

For example:

com.sun.appserv.jdbc.DataSource ds=
   (com.sun.appserv.jdbc.DataSource)context.lookup("dataSource");
Connection con = ds.getConnection();
Statement stmt = null;
try{
   stmt = con.createStatement();
   stmt.executeUpdate("Update");
}
catch (BadConnectionException e){
   ds.markConnectionAsBad(con) //marking it as bad for removal
}
finally{
   stmt.close();	
   con.close(); //Connection will be destroyed during close.
}

Handling Invalid Connections

If a ConnectionErrorOccured event occurs, the Enterprise Server considers the connection invalid and removes the connection from the connection pool. Typically, a JDBC driver generates a ConnectionErrorOccured event when it finds a ManagedConnection object unusable. Reasons can be database failure, network failure with the database, fatal problems with the connection pool, and so on.

If the fail-all-connections setting in the connection pool configuration is set to true, and a single connection fails, all connections are closed and recreated. If this setting is false, individual connections are recreated only when they are used. The default is false.

The is-connection-validation-required setting specifies whether connections have to be validated before being given to the application. If a resource’s validation fails, it is destroyed, and a new resource is created and returned. The default is false.

The prefer-validate-over-recreate property specifies that validating idle connections is preferable to closing them. This property has no effect on non-idle connections. If set to true, idle connections are validated during pool resizing, and only those found to be invalid are destroyed and recreated. If false, all idle connections are destroyed and recreated during pool resizing. The default is false.

You can set the fail-all-connections, is-connection-validation-required, and prefer-validate-over-recreate configuration settings during creation of a JDBC connection pool. Or, you can use the asadmin set command to dynamically reconfigure a setting. For example:


asadmin set server.resources.jdbc-connection-pool.JCPool1.fail-all-connections="true"
asadmin set server.resources.jdbc-connection-pool.JCPool1.is-connection-validation-required="true"
asadmin set server.resources.jdbc-connection-pool.JCPool1.property.prefer-validate-over-recreate="true"

For details, see the Sun GlassFish Enterprise Server v3 Reference Manual.

The interface ValidatingManagedConnectionFactory exposes the method getInvalidConnections to allow retrieval of the invalid connections. The Enterprise Server checks if the JDBC driver implements this interface, and if it does, invalid connections are removed when the connection pool is resized.

Connection Wrapping

The following features pertain to connection wrapping:

Wrapping Connections

If the Wrap JDBC Objects option is true (the default), wrapped JDBC objects are returned for Statement, PreparedStatement, CallableStatement, ResultSet, and DatabaseMetaData.

This option ensures that Statement.getConnection() is the same as DataSource.getConnection(). Therefore, this option should be true when both Statement.getConnection() and DataSource.getConnection() are done.

You can specify the Wrap JDBC Objects option in the following ways:

Obtaining a Physical Connection From a Wrapped Connection

The DataSource implementation in the Enterprise Server provides a getConnection method that retrieves the JDBC driver’s SQLConnection from the Enterprise 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); //get physical connection from wrapper
// Do db operations.
// Do not close driver connection.
con.close(); // return wrapped connection to pool.

Using the Connection.unwrap() Method

If the JDK version 1.6 is used, the Enterprise Server supports JDBC 4.0 if the JDBC driver is JDBC 4.0 compliant. Using the Connection.unwrap() method on a vendor-provided interface returns an object or a wrapper object implementing the vendor-provided interface, which the application can make use of to do vendor-specific database operations. Use the Connection.isWrapperFor() method on a vendor-provided interface to check whether the connection can provide an implementation of the vendor-provided interface. Check the JDBC driver vendor's documentation for information on these interfaces.

Transactions

The following features pertain to transactions:

Using Non-Transactional Connections

You can specify a non-transactional database connection in any of these ways:

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 15, Using the Transaction Service and Chapter 21, Administering Transactions, in Sun GlassFish Enterprise Server v3 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 Enterprise Server permits specifying any isolation level your database supports. The following table defines transaction isolation levels.

Table 14–1 Transaction Isolation Levels

Transaction Isolation Level 

Description 

read-uncommitted

Dirty reads, non-repeatable reads, and phantom reads can occur. 

read-committed

Dirty reads are prevented; non-repeatable reads and phantom reads can occur. 

repeatable-read

Dirty reads and non-repeatable reads are prevented; phantom reads can occur. 

serializable

Dirty reads, non-repeatable reads and phantom reads are prevented. 

You can specify the transaction isolation level in the following ways:

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 JDBC 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 API specification.


Note –

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


Other Features

The following additional features related to JDBC are provided:

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:

Accessing a DataSource using the Synchronization.beforeCompletion() method requires setting Allow Non Component Callers to true. For more information about the Transaction Synchronization Registry, see The Transaction Manager, the Transaction Synchronization Registry, and UserTransaction.

Restrictions and Optimizations

This section discusses restrictions and performance optimizations that affect using the JDBC API.

Disabling Stored Procedure Creation on Sybase

By default, DataDirect and Sun GlassFish JDBC drivers for Sybase databases create a stored procedure for each parameterized PreparedStatement. On the Enterprise Server, exceptions are thrown when primary key identity generation is attempted. To disable the creation of these stored procedures, set the property PrepareMethod=direct for the JDBC connection pool.

Chapter 15 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 GlassFishTM Enterprise Server.

This chapter contains the following sections:

For more information about the JavaTM Transaction API (JTA) and Java Transaction Service (JTS), see Chapter 21, Administering Transactions, in Sun GlassFish Enterprise Server v3 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 27, Transactions, in The Java EE 6 Tutorial, Volume I.

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 21, Administering Transactions, in Sun GlassFish Enterprise Server v3 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 Enterprise Server, a JDBC resource is non-XA if it meets either of the following criteria:

A transaction remains local if the following conditions remain true:

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 Enterprise Server in the following ways:

Changing keypoint-interval, retry-timeout-in-seconds, or timeout-in-seconds does not require a server restart. Changing other attributes or properties requires a server restart.

The Transaction Manager, the Transaction Synchronization Registry, and UserTransaction

To access a UserTransaction instance, you can either look it up using the java:comp/UserTransaction JNDI name or inject it using the @Resource annotation.

If you need to access the javax.transaction.TransactionManager implementation, you can look up the Enterprise Server implementation of this interface using the JNDI name java:appserver/TransactionManager. If possible, you should use the javax.transaction.TransactionSynchronizationRegistry interface instead, for portability. You can look up the implementation of this interface by using the JNDI name java:comp/TransactionSynchronizationRegistry. For details, see the Javadoc page for Interface TransactionSynchronizationRegistry and Java Specification Request (JSR) 907.

Accessing a DataSource using the Synchronization.beforeCompletion() method requires setting Allow Non Component Callers to true. The default is false. For more information about non-component callers, see Allowing Non-Component Callers.

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:

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:

  1. Create a JDBC connection Pool, and set the non-transactional-connections attribute to true.

  2. Create a JDBC resource that uses the connection pool and note the JNDI name of the JDBC resource.

  3. Create a table named txn_log_table with the schema shown in Table 15–1.

  4. Add the db-logging-resource property to the transaction service. For example:


    asadmin set server-config.transaction-service.property.db-logging-resource="jdbc/TxnDS"

    The property's value should be the JNDI name of the JDBC resource configured previously.

  5. To disable file synchronization, use the following asadmin create-jvm-options command:


    asadmin create-jvm-options -Dcom.sun.appserv.transaction.nofdsync
  6. Restart the server.

For information about JDBC connection pools and resources, see Chapter 14, Using the JDBC API for Database Access. For more information about the asadmin create-jvm-options command, see the Sun GlassFish Enterprise Server v3 Reference Manual.

Table 15–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 Enterprise Server host name plus 10 characters.

The size of the GTRID column should be at least 64 bytes.

To define the SQL used by the transaction manager when it is storing its transaction logs in the database, use the following flags:

-Dcom.sun.jts.dblogging.insertquery=sql statement
-Dcom.sun.jts.dblogging.deletequery=sql statement

The default statements are as follows:

-Dcom.sun.jts.dblogging.insertquery=insert into txn_log_table values ( ?, ? , ? )
-Dcom.sun.jts.dblogging.deletequery=delete from txn_log_table where localtid = ? and servername = ?

To set one of these flags using the asadmin create-jvm-options command, you must quote the statement. For example:

create-jvm-options '-Dcom.sun.jts.dblogging.deletequery=delete from txn_log_table where gtrid = ?'

You can also set JVM options in the Administration Console. Select the Application Server component and the JVM Settings tab. These flags and their statements must also be quoted in the Administration Console. For example:

'-Dcom.sun.jts.dblogging.deletequery=delete from txn_log_table where gtrid = ?'

Recovery Workarounds and Limitations

The Enterprise Server provides workarounds for some known issues with transaction recovery implementations.


Note –

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


Oracle Thin Driver

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 Enterprise 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. This workaround is used unless explicitly disabled.

Manual Transaction Recovery Limitation

Manual transaction recovery cannot recover transactions after a server crash. Manual operations are intended for cases when a resource dies unexpectedly while the server is running. In case of a server crash, only start-up recovery can recover in-doubt transactions.

Chapter 16 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:


Note –

The Web Profile of the Enterprise Server supports the EJB 3.1 Lite specification, which allows enterprise beans within web applications, among other features. The full Enterprise Server supports the entire EJB 3.1 specification. For details, see JSR 318.


Accessing the Naming Context

The Sun GlassFishTM Enterprise 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 the server must have a unique name.


Global JNDI Names

Global JNDI names are assigned according to the following precedence rules:

  1. 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.

  2. 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.

  3. 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.

  4. 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 software 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 Enterprise Server

The recommended approach for looking up an EJB component in a remote Enterprise 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 Enterprise 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 Enterprise 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 Enterprise 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:

Built- in Factories for Custom Resources

The Enterprise Server provides built-in factories for the following types of custom resources:

Template sun-resources.xml files for these built-in factories and a README file are available at as-install/lib/install/templates/resources/custom/. For more information about the sun-resources.xml file, see the Sun GlassFish Enterprise Server v3 Application Deployment Guide.

JavaBeanFactory

To create a custom resource that provides instances of a JavaBean class, follow these steps:

  1. Set the custom resource's factory class to org.glassfish.resources.custom.factory.JavaBeanFactory.

  2. Create a property in the custom resource for each setter method in the JavaBean class.

    For example, if the JavaBean class has a method named setAccount, specify a property named account and give it a value.

  3. Make sure the JavaBean class is accessible to the Enterprise Server.

    For example, you can place the JavaBean class in the as-install/lib directory.

PropertiesFactory

To create a custom resource that provides properties to applications, set the custom resource's factory class to org.glassfish.resources.custom.factory.PropertiesFactory, then specify one or both of the following:

PrimitiviesAndStringFactory

To create a custom resource that provides Java primitives to applications, follow these steps:

  1. Set the custom resource's factory class to org.glassfish.resources.custom.factory.PrimitivesAndStringFactory.

  2. Set the custom resource's resource type to one of the following or its fully qualified wrapper class name equivalent:

    • int

    • integer

    • long

    • double

    • float

    • char

    • character

    • short

    • byte

    • boolean

    • String

  3. Create a property in the custom resource named value and give it the value needed by the application.

    For example, If the application requires a double of value 22.1, create a property with the name value and the value 22.1.

URLFactory

To create a custom resource that provides URL instances to applications, follow these steps:

  1. Set the custom resource's factory class to org.glassfish.resources.custom.factory.URLFactory.

  2. Choose which of the following constructors to use:

    • URL(protocol, host, port, file)

    • URL(protocol, host, file)

    • URL(spec)

  3. Define properties according to the chosen constructor.

    For example, for the first constructor, define properties named protocol, host, port, and file. Example values might be http, localhost, 8085, and index.html, respectively.

    For the third constructor, define a property named spec and assign it the value of the entire URL.

Using a Custom jndi.properties File

To use a custom jndi.properties file, place the file in the domain-dir/lib/classes directory or JAR it and place it in the domain-dir/lib directory. This adds the custom jndi.properties file to the Common 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 Enterprise Server deployment descriptors map resource references in application client, EJB, and web application components to JNDI names configured in the Enterprise Server:

These elements are part of the sun-web.xml, sun-application-client.xml, and sun-ejb-ref.xml deployment descriptor files. For more information about how these elements behave in each of the deployment descriptor files, see Appendix C, Elements of the Enterprise Server Deployment Descriptors, in Sun GlassFish Enterprise Server v3 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 Enterprise Server, the annotation alone is enough to reference the resource.

However, you can use an Enterprise 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 Enterprise Server.

<resource-ref>
   <res-ref-name>jdbc/helloDbDs</res-ref-name>
   <jndi-name>jdbc/helloDbDataSource</jndi-name>
</resource-ref>

Chapter 17 Using the Java Message Service

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


Note –

JMS resources are supported only in the full Enterprise Server, not in the Web Profile.


For detailed information about JMS concepts and JMS support in the Enterprise Server, see Chapter 19, Administering the Java Message Service (JMS) , in Sun GlassFish Enterprise Server v3 Administration Guide.

For more information about Message Queue software, see the Sun GlassFish Message Queue 4.4 Administration Guide.

This chapter contains the following sections:

The JMS Provider

The Enterprise 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 Enterprise Server uses the Sun GlassFish Message Queue software as its native JMS provider. The Message Queue software is tightly integrated into theEnterprise Server, providing transparent JMS messaging support. This support is known within Enterprise Server as the JMS Service. The JMS Service requires only minimal administration.

The relationship of the Message Queue software to the Enterprise 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:

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/coll/1343.9.

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 GlassFish Message Queue software is integrated into the Enterprise 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 Enterprise Server provides a generic resource adapter for JMS, for those who want to use a JMS provider other than Sun GlassFish Message Queue. For details, see http://genericjmsra.dev.java.net/ and Configuring Resource Adapters for JMS in Sun GlassFish Enterprise Server v3 Administration Guide.

Administration of the JMS Service

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

For more information about JMS administration tasks, see Chapter 19, Administering the Java Message Service (JMS) , in Sun GlassFish Enterprise Server v3 Administration Guide and the Sun GlassFish Message Queue 4.4 Administration Guide.

Configuring the JMS Service

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

You can override the JMS Service configuration using JMS connection factory settings. For details, see Chapter 19, Administering the Java Message Service (JMS) , in Sun GlassFish Enterprise Server v3 Administration Guide.


Note –

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


The Default JMS Host

A JMS host refers to a Sun GlassFish Message Queue broker. A default JMS host for the JMS service is provided, named default_JMS_host. This is the JMS host that the Enterprise 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 Enterprise 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 Administration 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 GlassFish Message Queue instance is running. For details, see the Sun GlassFish Enterprise Server v3 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 Queue physical destination it listens to doesn’t exist, the Enterprise Server automatically creates the physical destination. However, it is good practice to create the Queue physical destination beforehand.

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

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 GlassFish Enterprise Server v3 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 Enterprise Server:

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 Enterprise 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 Enterprise Server. Further changes to the configuration are not available to the client JVM until the client is restarted.

JMS Connection Features

The Sun GlassFish 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 Enterprise 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 GlassFish Message Queue software, the AddressList property is called imqAddressList.


Connection Pooling

The Enterprise 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.

To use the command line, use the asadmin create-connector-connection-pool command to manage the pool.

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 addresslist-behavior JMS service attribute can be set to priority. This means that the first broker in the AddressList is selected first.

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 Enterprise Server.

Connection Failover

To specify whether the Enterprise 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 Enterprise 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 19, Administering the Java Message Service (JMS) , in Sun GlassFish Enterprise Server v3 Administration Guide.

The Sun GlassFish 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.

Using the ConfigurableTransactionSupport Interface

The Java EE Connector 1.6 specification allows a resource adapter to use the transaction-support attribute to specify the level of transaction support that the resource adapter handles. However, the resource adapter vendor does not have a mechanism to figure out the current transactional context in which a ManagedConnectionFactory is used.

If a ManagedConnectionFactory implements an optional interface called com.sun.appserv.connectors.spi.ConfigurableTransactionSupport, the Enterprise Server notifies the ManagedConnectionFactory of the transaction-support configured for the connector connection pool when the ManagedConnectionFactory instance is created for the pool. Connections obtained from the pool can then be used with a transaction level at or lower than the configured value. For example, a connection obtained from a pool that is set to XA_TRANSACTION could be used as a LOCAL resource in a last-agent-optimized transaction or in a non-transactional context.

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 Enterprise Server searches the container for authentication information before using the supplied user and password. Version 7 of the Enterprise Server threw an exception in this situation.

Message Queue varhome Directory

The Sun GlassFish Message Queue software uses a default directory for storing data such as persistent messages and its log file. This directory is called varhome. The Enterprise Server uses domain-dir/imq as the varhome directory if the type of relationship between the Enterprise 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 Enterprise Server and Message Queue, see The JMS Provider.

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

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

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

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:

ProcedureTo Send SOAP Messages Using the JMS API

  1. Import the MessageTransformer library.

    import com.sun.messaging.xml.MessageTransformer;

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

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

    tcf = new TopicConnectionFactory();
    tc = tcf.createTopicConnection();
    session = tc.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
    topic = session.createTopic(topicName);
    publisher = session.createPublisher(topic);
  3. Construct a SOAP message using the SOAP with Attachments API for Java (SAAJ).

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

    Message m = MessageTransformer.SOAPMessageIntoJMSMessage (soapMessage, 
    session );
  5. Publish the JMS message.

    publisher.publish(m);
  6. Close the JMS connection.

    tc.close();

ProcedureTo Receive SOAP Messages Using the JMS API

  1. Import the MessageTransformer library.

    import com.sun.messaging.xml.MessageTransformer;

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

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

    messageFactory = MessageFactory.newInstance();
    tcf = new com.sun.messaging.TopicConnectionFactory();
    tc = tcf.createTopicConnection();
    session = tc.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
    topic = session.createTopic(topicName);
    subscriber = session.createSubscriber(topic);
    subscriber.setMessageListener(this);
    tc.start();
  3. Use the OnMessage method to receive the message. Use the SOAPMessageFromJMSMessage method to convert the JMS message to a SOAP message.

    public void onMessage (Message message) {
    SOAPMessage soapMessage =
     MessageTransformer.SOAPMessageFromJMSMessage( message,
     messageFactory ); }
  4. Retrieve the content of the SOAP message.

Chapter 18 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:


Note –

JavaMail resources are supported only in the full Sun GlassFishTMEnterprise Server, not in the Web Profile.


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:

For more information, see Chapter 18, Administering the JavaMail Service, in Sun GlassFish Enterprise Server v3 Administration Guide and the JavaMail specification at http://java.sun.com/products/javamail/. A useful JavaMail tutorial is located at http://java.sun.com/developer/onlineTraining/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 Enterprise 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:

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 16, 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:

ProcedureTo Send a Message Using JavaMail

  1. Import the packages that you need.

    import java.util.*;
    import javax.activation.*;
    import javax.mail.*;
    import javax.mail.internet.*;
    import javax.naming.*;
  2. Look up the JavaMail session.

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

    For more information, see Looking Up a JavaMail Session.

  3. Override the JavaMail session properties if necessary.

    For example:

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

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

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

    Transport.send(msg);

ProcedureTo Read a Message Using JavaMail

  1. Import the packages that you need.

    import java.util.*;
    import javax.activation.*;
    import javax.mail.*;
    import javax.mail.internet.*;
    import javax.naming.*;
  2. Look up the JavaMail session.

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

    For more information, see Looking Up a JavaMail Session.

  3. Override the JavaMail session properties if necessary.

    For example:

    Properties props = session.getProperties();
    props.put("mail.from", "user2@mailserver.com");
  4. Get a Store object from the Session, then connect to the mail server using the Store object’s connect() method.

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

    Store store = session.getStore();
    store.connect("MailServer", "MailUser", "secret");
  5. Get the INBOX folder.

    Folder folder = store.getFolder("INBOX");
  6. It is efficient to read the Message objects (which represent messages on the server) into an array.

    Message[] messages = folder.getMessages();