PREFACE This courseware is to help the participants to learn the basic principles of writing applications for the subject

. It surveys the different issues and discusses the various techniques for dealing with it. The participants have no doubt seen many books about the subject that are 800 to 1000 pages long. Presumably the participants have noticed by now that this courseware is much smaller but we have tried to make the coverage as vast as possible. It will always be our endeavor to improve the contents and coverage of the material at all times. The R&D team of professionals of TRENDZ has designed the courseware after extensive research, taking into considerations the present market trends and the requirements of the participants, keeping in mind the knowledge and understanding level of the participants the language used in this book is very simple and easy. This the third released version on the subject by the R&D team. This is only an insight into the subject and the participants are advised to refer the more sources to improve their technical knowledge. In daily sessions the technical coordinator will discuss more real time application as covered in the courseware. The team to give the best knowledge through his courseware has put all efforts, if you have any suggestion please advice on the same. We would be appreciating the suggestions for the current courseware, please contact the Technical Manager or mail to Director on ss@trendzit.net No part or wholly of this publication may be reproduced, stored in retrieval system or transmitted in any form, or by any means, electronic, mechanical, recording or otherwise, without the prior written permission of the publisher. This is a product developed by TRENDZ to circulate exclusively to its participants.

All rights are reserved with Trendz

J2EE

INDEX
 Java Database Connectivity (JDBC) o Overview o Type of Drivers o Connection & Statement o Result Set o Transactions Servlets o Overview o Life Cycle o Request & Response o HTTP Servlets o Session Tracking Remote Method Invocation (RMI) o Overview o System Goals o Interfaces & Classes Java Server Pages (JSP) o Overview & Importance o Web Application Development o JSP Directives o JSP Action Tags o JSP Custom Tag Library Java 2 Enterprise Edition (J2EE) o JNDI  Naming & Directory Service  Installing OpenLDAP  Accessing Naming Service  Accessing Directory Service o Java Transaction API  Transaction Service  Bean managed Transaction o Java Mail API  Java Mail & JAF  Sample Application o EJB  Overview  Remote & Home Interfaces  Entity Beans with CMP and BMP  Session Bean as Stateless and Stateful  EJB 2.0 Features  EJB QL  Message-Driven Bean  EJB & WebService o J2EE Design Pattern
Page No. 2 of 220

© Trendz Information Technologies Ltd.

J2EE    Model-view-Controller What is Design Pattern Helpful Hints

Overview Types of Drivers Connection & Statement Result Set Transactions

© Trendz Information Technologies Ltd.

Page No. 3 of 220

J2EE

JDBC OVERVIEW THE JDBC API: The JDBC API provides programmatic access to relational data from the Java programming language. Using the JDBC API, applications written in the Java programming language can execute SQL statements, retrieve results, and propagate changes back to an underlying data source. The JDBC API can also be used to interact with multiple data sources in a distributed, heterogeneous environment. The JDBC API is based on the X/Open SQL CLI, which is also the basis for ODBC. JDBC provides a natural and easy-to-use mapping from the Java programming language to the abstractions and concepts defined in the X/Open CLI and SQL standards. Since its introduction in January 1997, the JDBC API has become widely accepted and implemented. The flexibility of the API allows for a broad range of implementations. PLATFORMS The JDBC API is part of the Java platform, which includes the Java 2 Standard Edition (J2SE) and the Java 2 Enterprise Edition (J2EE). The JDBC 3.0 API is divided into two packages: java.sql and javax.sql. Both packages are included in the J2SE and J2EE platforms. GOALS: The JDBC API is a mature technology, having first been specified in January 1997. In its initial release, the JDBC API focused on providing a basic call-level interface to SQL databases. The JDBC 2.1 specification and the 2.0 Optional Package specifications then broadened the scope of the API to include support for more advanced applications and for the features required by application servers to manage use of the JDBC API on behalf of their applications. The overall goal of the JDBC 3.0 specification is to “round out” the API by filling in smaller areas of missing functionality. The following list outlines the goals and design philosophy for the JDBC API in general and the JDBC 3.0 API in particular:  Fit into the J2EE and J2SE platforms The JDBC API is a constituent technology of the Java platform. The JDBC 3.0 API should be aligned with the overall direction of the Java 2 Enterprise Edition and Java 2 Standard Edition platforms. Be consistent with SQL99 The JDBC API provides programmatic access from applications written in the Java programming language to standard SQL. At the time the JDBC 2.0 API was in development, the SQL99 specification was a moving target. SQL99 is now a published standard and includes features that are widely supported among DBMS vendors as well as features that only a few vendors support. The intent of the JDBC 3.0 API is to provide access to the subset of SQL99 features that are likely to be widely supported within the next five years.
Page No. 4 of 220

© Trendz Information Technologies Ltd.

J2EE

Consolidate predecessor specifications This document incorporates content from three prior JDBC specifications to provide a single standalone specification of the JDBC API. Offer vendor-neutral access to common features The JDBC API strives to provide high-bandwidth access to features commonly supported across different vendor implementations. The goal is to provide a degree of feature access comparable to what can be achieved by native applications. However, the API must be general and flexible enough to allow for a wide range of implementations. Maintain the focus on SQL The focus of the JDBC API has always been on accessing relational data from the Java programming language. This continues to be true with the JDBC 3.0 API. The JDBC 3.0 API does not preclude interacting with other technologies, including XML, CORBA, or non-relational data, but the primary target will still be relational data and SQL. Provide a foundation for tools and higher-level APIs The JDBC API presents a standard API to access a wide range of underlying data sources or legacy systems. Implementation differences are made transparent through JDBC API abstractions, making it a valuable target platform for tools vendors who want to create portable tools and applications. Because it is a “call-level” interface from the Java programming language to SQL, the JDBC API is also suitable as a base layer for higher-level facilities such as Enterprise Java Beans (EJB) 2.0 container-managed persistence and SQL J. Keep it simple The JDBC API is intended to be a simple-to-use, straightforward interface upon which more complex entities can be built. This goal is achieved by defining many compact, single-purpose methods instead of a smaller number of complex, multipurpose ones with control flag parameters. Enhance reliability, availability, and scalability Reliability, availability, and scalability are the themes of the J2EE and J2SE platforms, as well as the direction for future Java platforms. The JDBC 3.0 API stays true to these themes by enhancing support in several areas, including resource management, the reuse of prepared statements across logical connections, and error handling. Maintain backward compatibility with existing applications and drivers Existing JDBC technology-enabled drivers (“JDBC drivers”) and the applications that use them must continue to work in an implementation of the Java Virtual Machine that supports the JDBC 3.0 API. Applications that use only features defined in earlier releases of the JDBC API, excluding those that were deprecated by JDBC 2.0, will not require changes to continue running. It should be straightforward for existing applications to migrate to JDBC 3.0 technology. Allow forward compatibility with Connectors
Page No. 5 of 220

© Trendz Information Technologies Ltd.

J2EE The Connector architecture defines a standard way to package and deploy a resource adapter that allows a J2EE container to integrate its connection, transaction, and security management with those of an external resource. The JDBC 3.0 API provides the migration path for JDBC drivers to the Connector architecture. It should be possible for vendors whose products use JDBC technology to move incrementally towards implementing the Connector API. The expectation is that these implementers will write “resource manager wrappers” around their existing data source implementations so that they can be reused in a Connector framework.  Specify requirements unambiguously The requirements for JDBC compliance need to be unambiguous and easy to identify. The JDBC 3.0 specification and the API documentation (Javadoc documentation) will clarify which features are required and which are optional.

CONNECTIONS: A Connection object represents a connection to a data source via a JDBC technologyenabled driver. The data source can be a DBMS, a legacy file system, or some other source of data with a corresponding JDBC driver. A single application using the JDBC API may maintain multiple connections. These connections may access multiple data sources, or they may all access a single data source. From the JDBC driver perspective, a Connection object represents a client session. It has associated state information such as user ID, a set of SQL statements and result sets being used in that session, and what transaction semantics are in effect. To obtain a connection, the application may interact with either:

 The DriverManager class working with one or more Driver implementations
(OR)

 A DataSource implementation
Using a DataSource object is the preferred method because it enhances application portability, it makes code maintenance easier, and it makes it possible for an application to transparently make use of connection pooling and distributed transactions. All J2EE components that establish a connection to a data source use a DataSource object to get connection. It describes the various types of JDBC drivers and the use of the Driver interface, the DriverManager class, and the basic DataSource interface. DataSource implementations that support connection pooling and distributed transactions. Types of Drivers

There are many possible implementations implementations are categorized as follows:

of

JDBC

drivers.

These

Type 1 — Drivers that implement the JDBC API as a mapping to another data access API, such as ODBC. Drivers of this type are generally dependent on a native library, which limits their portability. The JDBC-ODBC Bridge driver is an example of a Type 1 driver.

© Trendz Information Technologies Ltd.

Page No. 6 of 220

J2EE  Type 2 — Drivers that are written partly in the Java programming language and partly in native code. These drivers use a native client library specific to the data source to which they connect. Again, because of the native code, their portability is limited. Type 3 — Drivers that use a pure Java client and communicate with a middleware server using a database-independent protocol. The middleware server then communicates the client’s requests to the data source. Type 4 — Drivers that are pure Java and implement the network protocol for a specific data source. The client connects directly to the data source.

The Driver Interface JDBC drivers must implement the Driver interface, and the implementation must contain a static initializer that will be called when the driver is loaded. This initializer registers a new instance of itself with the DriverManager, as shown below. public class AcmeJdbcDriver implements java.sql.Driver { static { java.sql.DriverManager.registerDriver(new AcmeJdbcDriver()); } ... } Static initializer for a driver implementing java.sql.Driver Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Loading a driver that implements java.sql.Driver To insure that drivers can be loaded using this mechanism, drivers are required to provide a constructor that takes no arguments. The DriverManager class invokes Driver methods when it wishes to interact with a registered driver. The Driver interface also includes the method accepts URL. The DriverManager can use this method to determine which of its registered drivers it should use for a given Universal Resource Locator (URL). When the DriverManager is trying to establish a connection, it calls that driver’s connect method and passes the driver, the URL. If the Driver implementation understands the URL, it will return a Connection object; otherwise it returns null. URL Syntax The recommended JDBC URL syntax is structured as follows: jdbc:<subprotocol>:<subname>

Where a ‘subprotocol’ names a particular kind of database connectivity mechanism that may be supported by one or more drivers. The contents of the ‘subname’ will depend on the subprotocol. The recommended syntax for a network address specified as part of a subname follows the standard URL naming convention for the subname:
//hostname:port/subsubname
© Trendz Information Technologies Ltd. Page No. 7 of 220

J2EE

The subsubname can have arbitrary internal syntax. Registering Subprotocol names Sun Microsystems, Java Software Division, will act as an informal registry for JDBC subprotocol names. Send mail to jdbc@eng.sun.com to reserve a subprotocol name. DriverManager Class The DriverManager class works with the Driver interface to manage the set of drivers available to a JDBC client. When the client requests a connection and provides a URL, the DriverManager is responsible for finding a driver that recognizes the URL and for using it to connect to the corresponding data source. Key DriverManager methods include:

 registerDriver() — this method adds a driver to the set of available drivers 
and is invoked implicitly when the driver is loaded. The registerDriver() method is typically called by the static initializer provided by each driver. getConnection() — the method the JDBC client invokes to establish a connection. The invocation includes a JDBC URL, which the DriverManager passes to each driver in its list until it finds one whose Driver.connect method recognizes the URL. That driver returns a Connection object to the DriverManager, which in turn passes it to the application.

illustrates how a JDBC client obtains a connection from the DriverManager. // Load the driver. This creates an instance of the driver // and calls the registerDriver method to make acme.db.Driver // available to clients. Class.forName("acme.db.Driver"); // Set up arguments for the call to the getConnection method. // The sub-protocol "odbc" in the driver URL indicates the // use of the JDBC-ODBC bridge. String url = "jdbc:odbc:DSN"; String user = "SomeUser"; String passwd = "SomePwd"; // Get a connection from the first driver in the DriverManager // list that recognizes the URL "jdbc:odbc:DSN". Connection con = DriverManager.getConnection(url, user, passwd); Loading a driver and getting a connection using the DriverManager: The DriverManager class also provides two other getConnection() methods:

 getConnection(String url) for connecting to data sources that do not use a
username and password.

 getConnection(String url, java.util.Properties prop), which allows the client to
connect using a set of properties describing the user name and password along with any addition information that may be required.
© Trendz Information Technologies Ltd. Page No. 8 of 220

J2EE

The DriverPropertyInfo class provides information on the properties that the JDBC driver can understand. SQLPermission Class The SQLPermission class represents a set of permissions that a codebase may be granted. Currently the only permission defined is setLog. The SecurityManager will check for the setLog permission when an Applet calls either the DriverManager method setLogWriter or setLogStream. If the codebase does not have the setLog permission, a java.lang.SecurityException exception will be thrown. STATEMENTS This section describes the Statement interface and its subclasses PreparedStatement and CallableStatement. It also describes related topics, including escape syntax, performance hints, and auto-generated keys.  Statement Interface The Statement interface defines methods for executing SQL statements that do not contain parameter markers. The PreparedStatement interface adds methods for setting input parameters, and the CallableStatement interface adds methods for retrieving output parameter values returned from stored procedures. Creating Statements Statement objects are created by Connection object. Connection conn = dataSource.getConnection(user, passwd); Statement stmt = conn.createStatement() Creating a Statement object Each Connection object can create multiple Statement objects that may be used concurrently by the program. // get a connection from the DataSource object ds Connection conn = ds.getConnection(user, passwd); // create two instances of Statement Statement stmt1 = conn.createStatement(); Statement stmt2 = conn.createStatement(); Creating multiple Statement objects from a single connection  Setting ResultSet Characteristics

Additional constructors may be used to set the type and concurrency or the type, concurrency,and hold ability of any result sets produced by a statement.
It creates a Statement object that returns result sets that are scrollable, that are insensitive to changes made while the ResultSet object is open, that can be updated, and that do not close the ResultSet objects when a commit operation is implicity or explicitly performed.
© Trendz Information Technologies Ltd. Page No. 9 of 220

J2EE

Connection conn = ds.getConnection(user, passwd); Statement stmt = conn.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.HOLD_CURSOR_OVER_COMMIT); Creating a scrollable, insensitive, updatable result set that stays open after the method commit is called ResultSet types.  Executing Statement Objects The method used to execute a Statement object depends on the type of SQL statement being executed. If the Statement object represents an SQL query returning a ResultSet object, the method executeQuery() should be used. If the SQL is known to be a DDL statement or a DML statement returning an update count; the method executeUpdate() should be used. If the type of the SQL statement is not known, the method execute should be used. Returning a ResultSet object shows the execution of an SQL string returning a ResultSet object. Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(“select TITLE, AUTHOR, ISBN " + "from BOOKLIST”); while (rs.next()){ ... } Executing a Statement object that returns a ResultSet object If the SQL string being executed does not return a ResultSet object, the method executeQuery throws an SQLException.  Returning an Update Count The SQL statement being executed returns the number of rows affected by the update. Statement stmt = conn.createStatement(); int rows = stmt.executeUpdate(“update STOCK set ORDER = ‘Y’ " + "where SUPPLY = 0”); if (rows > 0) { ... } Executing a Statement object that returns an update count The method executeUpdate() throws an SQLException if the SQL string being executed does not return an update count.  Using the Method execute The method execute should be used only when the SQL string being executed could return an update count, a ResultSet object, multiple ResultSet objects, or the type of the statement is not known. The execute method returns true if the first result is a ResultSet object and false if it is an update count. Additional methods must be called to retrieve the ResultSet object or update count or to retrieve additional results, if any.

© Trendz Information Technologies Ltd.

Page No. 10 of 220

J2EE String sql; ... Statement stmt = conn.createStatement(); boolean b = stmt.execute(sql); if (b == true) { // b is true if a ResultSet is returned ResultSet rs; rs = stmt.getResultSet(); while (rs.next()) { ... } } else { // b is false if an update count is returned int rows = stmt.getUpdateCount(); if (rows > 0) { ... } } Executing a Statement object that may return an update count or a ResultSet object. When the SQL string being executed returns a ResultSet object, the method getUpdateCount() returns -1. If the SQL string being executed returns an update count, the method getResultSet() returns null.  Closing Statement Objects An application calls the method Statement.close() to indicate that it has finished processing a statement. All Statement objects will be closed when the connection that created them is closed. However, it is good coding practice for applications to close statements as soon as they have finished processing them. This allows any external resources that the statement is using to be released immediately. Closing a Statement object will close and invalidate any instances of ResultSet produced by that Statement object. The resources held by the ResultSet object may not be released until garbage collection runs again, so it is a good practice to explicitly close ResultSet objects when they are no longer needed. These comments about closing Statement objects PreparedStatement and CallableStatement objects as well.  apply to

PreparedStatement Interface The PreparedStatement interface extends Statement, adding the ability to set values for parameter markers contained within the statement. PreparedStatement objects represent SQL statements that can be prepared, or precompiled, for execution once and then executed multiple times. Parameter markers, represented by “?” in the SQL string, are used to specify input values to the statement that may vary at runtime.

Creating a PreparedStatement Object
Page No. 11 of 220

© Trendz Information Technologies Ltd.

J2EE An instance of PreparedStatement is created in the same manner as a Statement object, except that the SQL command is supplied when the statement is created: Connection conn = ds.getConnection(user, passwd); PreparedStatement ps = conn.prepareStatement(“INSERT INTO BOOKLIST" + "(AUTHOR, TITLE, ISBN) VALUES (?, ?, ?)”); Creating a PreparedStatement object with three placeholder Markers.  Setting ResultSet Characteristics As with createStatement(), the method prepareStatement() defines a constructor that can be used to specify the characteristics of result sets produced by that prepared statement. Connection conn = ds.getConnection(user, passwd); PreparedStatement ps = conn.prepareStatement( “SELECT AUTHOR, TITLE FROM BOOKLIST WHERE ISBN = ?”, ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_UPDATABLE); Creating a PreparedStatement object that returns forward only, updatable result sets  Setting Parameters The Prepared Statement interface defines setter methods that are used to substitute values for each of the parameter markers in the precompiled SQL string. The names of the methods follow the pattern "set<Type>". For example, the method setString() is used to specify a value for a parameter marker that expects a string. Each of these setter methods takes at least two parameters. The first is always an int equal to the ordinal position of the parameter to be set, starting at 1. The second and any remaining parameters specify the value to be assigned to the parameter. PreparedStatement ps = conn.prepareStatement(“INSERT INTO BOOKLIST" +"(AUTHOR, TITLE, ISBN) VALUES (?, ?, ?)”); ps.setString(1, “Zamiatin, Evgenii”); ps.setString(2, “We”); ps.setLong(3, 0140185852); Setting parameters in a PreparedStatement object : A value must be provided for each parameter marker in the PreparedStatement object before it can be executed. The methods used to execute a PreparedStatement object (executeQuery, executeUpdate and execute) will throw an SQLException if a value is not supplied for a parameter marker. The values set for the parameter markers of a PreparedStatement object are not reset when it is executed. The method clearParameters() can be called to

© Trendz Information Technologies Ltd.

Page No. 12 of 220

J2EE explicitly clear the values that have been set. Setting a parameter with a different value will replace the previous value with the new one.  Type Conversions The data type specified in a PreparedStatement setter method is a data type in the Java programming language. The JDBC driver is responsible for mapping this to the corresponding JDBC type (one of the SQL types defined in java.sql.Types) so that it is the appropriate type to be sent to the data source. Type Conversions Using the Method setObject The method setObject() can be used to convert an object in the Java programming language to a JDBC type. The conversion is explicit when setObject() is passed a Java Object and a JDBC data type. The driver will attempt to convert the Object to the specified JDBC type before passing it to the data source. If the object cannot be converted to the target type, an SQLException object is thrown. A Java Object of type Integer is being converted to the JDBC type SHORT. Integer value = new Integer(15); ps.setObject(1, value, java.sql.Types.SHORT); Converting an Integer object to an SQL SHORT: If setObject() is called without a type parameter, the Java Object is implicitly mapped using the default mapping for that object type. Integer value = new Integer(15); // value is mapped to java.sql.Types.INTEGER ps.setObject(1, value);  Setting NULL Parameters The method setNull() can be used to set any parameter to JDBC NULL. It takes two parameters, the ordinal position of the parameter marker, and the JDBC type of the parameter. ps.setNull(2, java.sql.Types.VARCHAR); Setting a String parameter to JDBC NULL: If a Java null is passed to any of the setter methods that take a Java object, the parameter will be set to JDBC NULL.

 Describing Outputs and Inputs of a PreparedStatement Object The method

PreparedStatement.getMetaData() retrieves a ResultSetMetaData object containing a description of the columns that will be returned by a prepared statement when is it executed. The ResultSetMetaData object contains a record for each column being returned. Methods in the ResultSetMetaData interface provide information about the number of columns being returned and the characteristics of each column. PreparedStatement pstmt = conn.prepareStatement( "SELECT * FROM CATALOG"); ResultSetMetaData rsmd = pstmt.getMetaData(); int colCount = rsmd.getColumnCount();

© Trendz Information Technologies Ltd.

Page No. 13 of 220

J2EE int colType; String colLabel; for (int i = 1; i <= colCount; i++) { colType = rsmd.getColumnType(i); colLabel = rsmd.getColumnLabel(i); ... } Creating a ResultSetMetaData object, retrieving column information: The method PreparedStatement.getParameterMetaData() returns a ParameterMetaData object describing the parameter markers that appear in the PreparedStatement object. Methods in the ParameterMetaData interface provide information about the number of parameters and their characteristics. PreparedStatement pstmt = conn.prepareStatement( "SELECT * FROM BOOKLIST WHERE ISBN = ?"); ... ParameterMetaData pmd = pstmt.getParameterMetaData(); int colType = pmd.getParameterType(1); ...

 Executing a PreparedStatement Object
As with Statement objects, the method used to execute a PreparedStatement object depends on the type of SQL statement being executed. If the PreparedStatement object is a query returning a ResultSet object, it should be executed with the method executeQuery(). If it is a DML statement returning a row count, it should be executed with the method executeUpdate(). The method execute should be used only if the return type of the statement is unknown. If any of the PreparedStatement execute methods is called with an SQL string as a parameter, an SQLException is thrown.

 Returning a ResultSet Object Shows a query being prepared and then
executed multiple times. PreparedStatement pstmt = conn.prepareStatement(“SELECT AUTHOR, " + "TITLE FROM BOOKLIST WHERE SECTION = ?”); for (int i = 1; i <= maxSectionNumber; i++) { pstmt.setInt(1, i); ResultSet rs = pstmt.executeQuery(); while (rs.next()) { // process the record } rs.close(); } pstmt.close(); If the statement being executed does not return a ResultSet object, the method executeQuery() throws an SQLException.  Returning a Row Count

© Trendz Information Technologies Ltd.

Page No. 14 of 220

J2EE If the statement being prepared and executed is a DML or DDL operation, it should be executed using the method executeUpdate(). This method returns the number of rows that the statement affected. PreparedStatement pstmt = conn.prepare( “update stock set reorder = ’Y’ where stock < ?”); pstmt.setInt(1, 5); int num = pstmt.executeUpdate(); If the statement being executed returns a ResultSet object, an SQLException is thrown.  Using the Method execute If the return type of a PreparedStatement object is not known or may return multiple ResultSet objects, it should be executed with the execute method. As is true with Statement objects, the methods getResultSet() and getUpdateCount() can be used to retrieve a result. PreparedStatement pstmt = conn.prepareStatement(sqlStatement); // set any parameters the user passes boolean b = pstmt.execute(); if (b == true) { ResultSet rs = pstmt.getResultSet(); // process a ResultSet ... } } else { int rowCount = pstmt.getUpdateCount(); // process row count ... } } CallableStatement Interface The CallableStatement interface extends PreparedStatement with methods for executing and retrieving results from stored procedures.  Creating a CallableStatement Object As with Statement and PreparedStatement objects, CallableStatement objects are created by Connection objects. It shows the creation of a CallableStatement object for calling the stored procedure ‘validate’, which has a return parameter and two other parameters. CallableStatement cstmt = conn.prepareCall(“{? = call validate(?, ?)}”); Creating a CallableStatement object  Setting Parameters Callable Statement objects may take three types of parameters: IN, OUT, and INOUT. The parameter can be specified as either an ordinal parameter or a
Page No. 15 of 220

© Trendz Information Technologies Ltd.

J2EE named parameter. A value must be set for each parameter marker in the statement. The number, type, and attributes of parameters to a stored procedure can be determined using the DatabaseMetaData method getProcedureColumns(). Parameter ordinals, which are integers passed to the appropriate setter method, refer to the parameter markers ("?") in the statement, starting at one. Literal parameter values in the statement do not increment the ordinal value of the parameter markers. the two parameter markers have the ordinal values 1 & 2. CallableStatement cstmt = con.prepareCall( "{CALL PROC(?, "Literal_Value", ?)}"); cstmt.setString(1, "First"); cstmt.setString(2, "Third"); Specifying ordinal parameters Named parameters can also be used to specify specific parameters. This is especially useful when a procedure has many parameters with default values. Named parameters can be used to specify only the values that have no default value. The name of a parameter corresponds to the COLUMN_NAME field returned by DatabaseMetaData.getProcedureColumns(). CallableStatement cstmt = con.prepareCall( "{CALL COMPLEX_PROC(?, ?)}"; cstmt.setString("PARAM_1", "Price"); cstmt.setFloat("PARAM_5", 150.25); The DatabaseMetaData.supportsNamedParameters() method can be called to determine if a JDBC driver and underlying data source support specifying named parameters. It is not possible to combine setting parameters with ordinals and with names in the same statement. If ordinals and names are used for parameters in the same statement, an SQLException is thrown. Note: In some cases it may not be possible to provide only some of the parameters for a procedure. For example, if the procedure name is overloaded, the data source determines which procedure to call based on the number of parameters. Enough parameters must be provided to allow the data source to resolve any ambiguity.  IN Parameters IN parameters are assigned values using the setter methods. cstmt.setString(1, “October”); cstmt.setDate(2, date);  OUT Parameters The method registerOutParameter() must be called to set the type for each OUT parameter before a CallableStatement object is executed. When the

© Trendz Information Technologies Ltd.

Page No. 16 of 220

J2EE stored procedure returns from execution, it will use these types to set the values for any OUT parameters. The values of OUT parameters can be retrieved using the appropriate getter methods defined in the CallableStatement interface. The following lines shows the execution of a stored procedure with two OUT parameters, a string and float, and the retrieval of the OUT parameter values. CallableStatement cstmt = conn.prepareCall( “{CALL GET_NAME_AND_NUMBER(?, ?)}"); cstmt.registerOutParameter(1, java.sql.Types.STRING); cstmt.registerOutParameter(2, java.sql.Types.FLOAT); cstmt.execute(); // Retrieve OUT parameters String name = cstmt.getString(1); float number = cstmt.getFloat(2);  INOUT Parameters Parameters that are both input and output parameters must be both set by using the appropriate setter method and also registered by calling the registerOutParameter() method. The type implied by the setter method and the type supplied to the method registerOutParameter() must be the same. CallableStatement cstmt = conn.prepareCall(“{CALL CALC(?)}”); cstmt.setFloat(1, 1237.98f); ctsmt.registerOutParameter(1, java.sql.Types.FLOAT); cstmt.execute(); float f = cstmt.getFloat(1);  Executing a CallableStatement Object As with Statement and PreparedStatement objects, the method used to execute a CallableStatement object depends on whether it returns a single ResultSet object, an update count, or multiple mixed results.

RESULT SETS The ResultSet interface provides methods for retrieving and manipulating the results of executed queries.  Kinds of ResultSet Objects ResultSet objects can have different functionality and characteristics. These characteristics are result set type, result set concurrency, and cursor holdability. ResultSet Types The type of a ResultSet object determines the level of its functionality in two main areas: (1) the ways in which the cursor can be manipulated, (2) how concurrent changes made to the underlying data source are reflected by the ResultSet object. The latter is called the sensitivity of the ResultSet object. The three different ResultSet types are described below. 1. TYPE_FORWARD_ONLY

© Trendz Information Technologies Ltd.

Page No. 17 of 220

J2EE • • The result set is not scrollable; its cursor moves forward only, from before the first row to after the last row. The rows contained in the result set depend on how the underlying database materializes the results. That is, it contains the rows that satisfy the query at either the time the query is executed or as the rows are retrieved.

2. TYPE_SCROLL_INSENSITIVE • The result set is scrollable; its cursor can move both forward and backward relative to the current position, and it can move to an absolute position. • The result set is insensitive to changes made to the underlying data source while it is open. It contains the rows that satisfy the query at either the time the query is executed or as the rows are retrieved. 3. TYPE_SCROLL_SENSITIVE • The result set is scrollable; its cursor can move both forward and backward relative to the current position, and it can move to an absolute position. • The result set reflects changes made to the underlying data source while the result set remains open. NOTE: The default ResultSet type is TYPE_FORWARD_ONLY. The method DatabaseMetaData.supportsResultSetType() returns true if the specified type is supported by the driver and false otherwise. If the driver does not support the type supplied to the methods createStatement(), prepareStatement(), or prepareCall(), it generates an SQLWarning on the Connection object that is creating the statement. When the statement is executed, the driver returns a ResultSet object of a type that most closely matches the requested type. An application can find out the type of a ResultSet object by calling the method ResultSet.getType().  ResultSet Concurrency The concurrency of a ResultSet object determines what level of update functionality is supported. The two concurrency levels are: • CONCUR_READ_ONLY The ResultSet object cannot be updated using the ResultSet interface. • CONCUR_UPDATABLE The ResultSet object can be updated using the ResultSet interface. NOTE: The default ResultSet concurrency is CONCUR_READ_ONLY. The method DatabaseMetaData.supportsResultSetConcurrency() returns true if the specified concurrency level is supported by the driver and false otherwise. If the driver does not support the concurrency level supplied to the methods createStatement(), prepareStatement(), or prepareCall(), it generates an
© Trendz Information Technologies Ltd. Page No. 18 of 220

J2EE SQLWarning on the Connection object that is creating the statement. An application can find out the concurrency of a ResultSet object by calling the method ResultSet.getConcurrency(). If the driver cannot return a ResultSet object at the requested type and concurrency, it determines the appropriate type before determining the concurrency.

 ResultSet Holdability

Calling the method Connection.commit() can close the ResultSet objects that have been created during the current transaction. In some cases, however, this may not be the desired behaviour. The ResultSet property holdability gives the application control over whether ResultSet objects (cursors) are closed when a commit operation is implicitly or explicitly performed. The following ResultSet constants may be supplied to the Connection methods createStatement(), prepareStatement(), and prepareCall(): 1.HOLD_CURSORS_OVER_COMMIT • ResultSet objects (cursors) are not closed; they are held open when a commit operation is implicity or explicity performed. 2.CLOSE_CURSORS_AT_COMMIT • ResultSet objects (cursors) are closed when a commit operation is implicitly or explicitly performed. Closing cursors at commit can result in better performance for some applications. The default holdability of ResultSet objects is implementation defined. The DatabaseMetaData method getResultSetHoldability() can be called to determine the default holdability of result sets returned by the underlying data source.

 ResultSet Type, Concurrency and Holdability
The parameters supplied to the methods Connection.createStatement(), Connection.prepareStatement(), and Connection.prepareCall() determine the type, concurrency, and holdability of ResultSet objects that the statement produces. The following statements creates a Statement object that will return scrollable, read-only ResultSet objects that are insensitive to updates made to the data source and that will be closed when the transaction in which they were created is committed. Connection conn = ds.getConnection(user, passwd); Statement stmt = conn.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT); Creating a scrollable, insensitive, read-only result set with a cursor that is not holdable. The Statement, PreparedStatement and CallableStatement interfaces also provide setter and getter methods for each of these properties.

© Trendz Information Technologies Ltd.

Page No. 19 of 220

J2EE Creating and Manipulating ResultSet Objects

 Creating ResultSet Objects

A ResultSet object is most often created as the result of executing a Statement object. The Statement methods executeQuery() and getResultSet() both return a ResultSet object, as do various DatabaseMetaData methods. Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(“select author, title, isbn " + "from booklist”); For each book in the table booklist, the ResultSet object will contain a row consisting of three columns, author, title, and isbn. The following sections detail how these rows and columns can be retrieved.

Cursor Movement A ResultSet object maintains a cursor, which points to its current row of data. When a ResultSet object is first created, the cursor is positioned before the first row. The following methods can be used to move the cursor: • next() — moves the cursor forward one row. Returns true if the cursor is now positioned on a row and false if the cursor is positioned after the last row. • previous() — moves the cursor backwards one row. Returns true if the cursor is now positioned on a row and false if the cursor is positioned before the first row. • first() — moves the cursor to the first row in the ResultSet object. Returns true if the cursor is now positioned on the first row and false if the ResultSet object does not contain any rows. • last() — moves the cursor to the last row in the ResultSet object. Returns true if the cursor is now positioned on the last row and false if the ResultSet object does not contain any rows. • beforeFirst() — positions the cursor at the start of the ResultSet object, before the first row. If the ResultSet object does not contain any rows, this method has no effect. • afterLast() — positions the cursor at the end of the ResultSet object, after the last row. If the ResultSet object does not contain any rows, this method has no effect. • relative(int row)— moves the cursor relative to its current position. If row is 0 (zero), the cursor is unchanged. If row is positive, the cursor is moved forward row rows. If the cursor is less than the specified number of rows from the last row, the cursor is positioned after the last row. If row is negative, the cursor is moved backward row rows. If the cursor is less than row rows from the first row, the cursor is positioned before the first row. The method relative returns true if the cursor is positioned on a valid row and false otherwise. If row is 1, relative is identical to the method next. If rows is -1, relative is identical to the method previous.

© Trendz Information Technologies Ltd.

Page No. 20 of 220

J2EE

absolute(int row) — positions the cursor on the row-th row of the ResultSet object. If row is positive, the cursor is moved row rows from the beginning of the ResultSet object. The first row is 1, the second 2, and so on. If row is greater than the number of rows in the ResultSet object, the cursor is positioned after the last row. If row is negative, the cursor is moved row rows from the end of the ResultSet object. The last row is -1, the penultimate -2, and so on. If row is greater than the number of rows in the ResultSet object, the cursor is positioned before the first row. Calling absolute(0) moves the cursor before the first row.

For a ResultSet object that is of type TYPE_FORWARD_ONLY, the only valid cursor movement method is next. All other cursor movement methods throw an SQLException.  Retrieving Values The ResultSet interface provides methods for retrieving the values of columns from the row where the cursor is currently positioned. Two getter methods exist for each JDBC type: one that takes the column index as its first parameter and one that takes the column name or label. The columns are numbered from left to right, as they appear in the select list of the query, starting at 1. Column names supplied to getter methods are case insensitive. If a select list contains the same column more than once, the first instance of the column will be returned. The index of the first instance of a column name can be retrieved using the method findColumn(). If the specified column is not found, the method findColumn() throws an SQLException. ResultSet rs = stmt.executeQuery(sqlstring); int colIdx = rs.findColumn(“ISBN”);  ResultSetMetadata When the ResultSet method getMetaData is called on a ResultSet object, it returns a ResultSetMetaData object describing the columns of that ResultSet object. In cases where the SQL statement being executed is unknown until runtime, the ResultSetMetaData can be used to determine which of the getter methods should be used to retrieve the data. ResultSet rs = stmt.executeQuery(sqlString); ResultSetMetaData rsmd = rs.getMetaData(); int colType [] = new int[rsmd.getColumnCount()]; for (int idx = 0, int col = 1; idx < colType.length; idx++, col++) colType[idx] = rsmd.getColumnType(col);
© Trendz Information Technologies Ltd. Page No. 21 of 220

J2EE

Retrieving NULL values The method wasNull() can be called to determine if the last value retrieved was a JDBC NULL in the database. When the column value in the database is JDBC NULL, it may be returned to the Java application as null, 0, or false, depending on the type of the column value. Column values that map to Java Object types are returned as a Java null; those that map to numeric types are returned as 0; those that map to a Java Boolean are returned as false. Therefore, it may be necessary to call the wasNull() method to determine whether the last value retrieved was a JDBC NULL.

Modifying ResultSet Objects ResultSet objects with concurrency CONCUR_UPDATABLE can be updated using ResultSet methods. Columns can be updated, new rows can be inserted, and rows can be deleted using methods defined in the ResultSet interface. Updating a Row Updating a row in a ResultSet object is a two-phase process. First, the new value for each column being updated is set, and then the change is applied to the row. The row in the underlying data source is not updated until the second phase is completed. The ResultSet interface contains two update methods for each JDBC type, one specifying the column to be updated as an index and one specifying the column name as it appears in the select list. Column names supplied to updater methods are case insensitive. If a select list contains the same column more than once, the first instance of the column will be updated. The method updateRow() is used to apply all column changes to the current row. The changes are not made to the row until updateRow() has been called. The method cancelUpdates() can be used to back out changes made to the row before the method updateRow() is called. The Following code shows the current row being updated to change the value of the column “author” to “Karnitkar, Yaswant”: Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executeQuery(“select author from booklist " + "where isbn = 140185852”); rs.next(); rs.updateString(“author”, “Yaswant, Karnitkar”); rs.updateRow(); The method DatabaseMetaData.ownUpdatesAreVisible(int type) returns true if a ResultSet object of the specified type is able to see its own updates and false otherwise.

© Trendz Information Technologies Ltd.

Page No. 22 of 220

J2EE A ResultSet object may be able to use the method rowUpdated to detect rows that have had the method updateRow called on them. The method DatabaseMetaData.updatesAreDetected(int type) returns true if a ResultSet object of the specified type can determine if a row is updated using the method rowUpdated() and false otherwise.  Deleting a Row A row in a ResultSet object can be deleted using the method deleteRow(). ResultSet rows being deleted. rs.absolute(4); rs.deleteRow();  Inserting a Row New rows may be inserted using the ResultSet interface. New rows are constructed in a special insert row. The steps to insert a new row are: 1. Move the cursor to the insert row 2. Set the values for the columns of the row using the ResultSet interface update methods 3. Insert the new row into the ResultSet object The Following steps necessary to insert a new row into the table booklist. // select all the columns from the table booklist ResultSet rs = stmt.executeQuery(“select author, title, isbn " + "from booklist”); rs.moveToInsertRow(); // set values for each column rs.updateString(1, “Huxley, Aldous”); rs.updateString(2, “Doors of Perception and Heaven and Hell”); rs.updateLong(3, 60900075); // insert the row rs.insertRow(); // move the cursor back to its position in the result set rs.moveToCurrentRow(); Each column in the insert row that does not allow null as a value and does not have a default value must be given a value using the appropriate update method. If this is not the case, the method insertRow() will throw an SQLException.

 Closing a ResultSet Object

A ResultSet object is automatically closed when the Statement object that produced it is closed. The method close can be called explicitly to close a ResultSet object, thereby releasing any external resources and making it immediately available for garbage collection.

TRANSACTIONS

Transactions are used to provide data integrity, correct application semantics, and a consistent view of data during concurrent access. All JDBC compliant
© Trendz Information Technologies Ltd. Page No. 23 of 220

J2EE

drivers are required to provide transaction support. Transaction management in the JDBC API mirrors the SQL99 specification and includes these concepts:
   Auto-commit mode Transaction isolation levels SavePoints

It describes transaction semantics associated with a single Connection object.  Transaction Boundaries and Autocommit When to start a new transaction is a decision made implicitly by either the JDBC driver or the underlying data source. Although some data sources implement an explicit “begin transaction” statement, there is no JDBC API to do so. Typically, a new transaction is started when the current SQL statement requires one and there is no transaction already in place. Whether or not a given SQL statement requires a transaction is also specified by SQL99. The Connection attribute auto-commit specifies when to end transactions. Enabling auto-commit causes the JDBC driver to do a transaction commit after each individual SQL statement as soon as it is complete. The point at which a statement is considered to be “complete” depends on the type of SQL statement as well as what the application does after executing it: • • For Insert, Update, Delete, and DDL statements, the statement is complete as soon as it has finished executing. For Select statements, the statement is complete when the associated result set is closed. The result set is closed as soon as one of the following occurs:  All of the rows have been retrieved  The associated Statement object is re-executed  Another Statement object is executed on the same connection For CallableStatement objects, the statement is complete when all of the associated result sets have been closed.


Disabling Auto-commit Mode // Assume con is a Connection object con.setAutoCommit(false); When auto-commit is disabled, each transaction must be explicitly committed by calling the Connection method commit or else explicitly rolled back by calling the Connection method rollback. This is appropriate for cases where transaction management is being done in a layer above the driver such as: • When the application needs to group multiple SQL statements into a single transaction • When the transaction is being managed by the application server The default is for auto-commit mode to be enabled when the Connection object is created. If the value of auto-commit is changed in the middle of a transaction, the current transaction is committed. It is an error to enable auto-commit for a connection participating in a distributed transaction.

© Trendz Information Technologies Ltd.

Page No. 24 of 220

J2EE

Transaction Isolation Levels Transaction isolation levels specify what data is “visible” to the statements within a transaction. They directly impact the level of concurrent access by defining what interaction, if any, is possible between transactions against the same target data source. Possible interaction between concurrent transactions is categorized as follows:

Dirty reads occur when transactions are allowed to see uncommitted changes to the data. In other words, changes made inside a transaction are visible outside the transaction before they are committed. If the changes are rolled back instead of being committed, it is possible for other transactions to have done work based on incorrect, transient data. Nonrepeatable reads occur when:  Transaction A reads a row.  Transaction B changes the row.  Transaction A reads the same row a second time and gets different results. Phantom reads occur when:


Transaction A reads all rows that satisfy a WHERE condition Transaction B inserts an additional row that satisfies the same condition. Transaction A reevaluates the WHERE condition and picks up the additional “phantom” row.

JDBC augments the four levels of transaction isolation defined by SQL99, by adding TRANSACTION_NONE. From least restrictive to most restrictive, the transaction isolation levels are: 1. TRANSACTION_NONE — indicates that the driver does not support transactions, which means that it is not a JDBC compliant driver. 2. TRANSACTION_READ_UNCOMMITTED — allows transactions to see uncommitted changes to the data. This means that dirty reads, nonrepeatable reads, and phantom reads are possible. 3. TRANSACTION_READ_COMMITTED — means that any changes made inside a transaction are not visible outside the transaction until the transaction is committed. This prevents dirty reads, but non-repeatable reads and phantom reads are still possible. 4. TRANSACTION_REPEATABLE_READ — disallows dirty reads and nonrepeatable reads. Phantom read are still possible. 5. TRANSACTION_SERIALIZABLE — specifies that dirty reads, nonrepeatable reads, and phantom reads are prevented.

 Using the setTransactionIsolation() Method
The default transaction level for a Connection object is determined by the driver supplying the connection. Typically, it is the default transaction level supported by the underlying data source. The Connection method setTransactionIsolation() is provided to allow clients to change the transaction isolation level for a given Connection object. The
© Trendz Information Technologies Ltd. Page No. 25 of 220

J2EE new isolation level remains in effect for the remainder of the session or until the next invocation of the setTransactionIsolation() method. The result of invoking the method setTransactionIsolation() in the middle of a transaction is implementation-defined. The return value of the method getTransactionIsolation() should reflect the change in isolation level when it actually occurs. It is recommended that drivers implement the setTransactionIsolation() method to change the isolation level starting with the next transaction. Committing the current transaction to make the effect immediate is also a valid implementation. It is possible for a given JDBC driver to not support all four-transaction isolation levels (not counting TRANSACTION_NONE). If a driver does not support the isolation level specified in an invocation of setTransactionIsolation(), it is allowed to substitute a higher, more restrictive transaction isolation level. If a driver is unable to substitute a higher transaction level, it throws an SQLException. The DatabaseMetaData method supportsTransactionIsolationLevel() may be used to determine whether or not the driver supports a given level.  Performance Considerations As the transaction isolation level increases, more locking and other DBMS overhead is required to ensure the correct semantics. This in turn lowers the degree of concurrent access that can be supported. As a result, applications may see decreased performance when they use a higher transaction isolation level. For this reason, the transaction manager, whether it is the application itself or part of the application server, should weigh the need for data consistency against the requirements for performance when determining which transaction isolation level is appropriate. Savepoints Savepoints provide finer-grained control of transactions by marking intermediate points within a transaction. Once a savepoint has been set, the transaction can be rolled back to that savepoint without affecting preceding work. The DatabaseMetaData.supportsSavepoints method can be used to determine whether a JDBC API implementation supports savepoints. Setting and Rolling Back to a Savepoint The JDBC 3.0 API adds the method Connection.setSavepoint(), which sets a savepoint within the current transaction. The Connection.rollback() method has been overloaded to take a savepoint argument. The following code inserts a row into a table, sets the savepoint svpt1, and then inserts a second row. When the transaction is later rolled back to svpt1, the second insertion is undone, but the first insertion remains intact. In other words, when the transaction is committed, only the row containing ’FIRST’ will be added to TAB1. Statement stmt = conn.createStatement(); int rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) VALUES " +"(’FIRST’)"); // set savepoint Savepoint svpt1 = conn.setSavepoint("SAVEPOINT_1");
© Trendz Information Technologies Ltd. Page No. 26 of 220

J2EE rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) " + "VALUES (’SECOND’)"); ... conn.rollback(svpt1); ... conn.commit();  Releasing a Savepoint The method Connection.releaseSavepoint takes a Savepoint object as a parameter and removes it from the current transaction. Once a savepoint has been released, attempting to reference it in a rollback operation will cause an SQLException to be thrown. Any savepoints that have been created in a transaction are automatically released and become invalid when the transaction is committed or when the entire transaction is rolled back. Rolling a transaction back to a savepoint automatically releases and makes invalid any other savepoints that were created after the savepoint in question.

© Trendz Information Technologies Ltd.

Page No. 27 of 220

J2EE

Overview Life Cycle Request & Response HTTP Servlets Session Tracking

© Trendz Information Technologies Ltd.

Page No. 28 of 220

J2EE

SERVLETS OVERVIEW What is a Servlet? A Servlet is a Java technology-based Web component, managed by a container that generates dynamic content. Like other Java technology-based components, Servlets are platform-independent Java classes that are compiled to platform-neutral byte code that can be loaded dynamically into and run by a Java technology-enabled Web server. Containers, sometimes called Servlet engines, are Web server extensions that provide Servlet functionality. Servlets interact with Web clients via a request/response paradigm implemented by the Servlet container. What is a Servlet Container? The Servlet container is a part of a Web server or application server that provides the network services over which requests and responses are sent, decodes MIME-based requests, and formats MIME-based responses. A Servlet container also contains and manages Servlets through their lifecycle. A Servlet container can be built into a host Web server, or installed as an add-on component to a Web Server via that server’s native extension API. Servlet containers can also be built into or possibly installed into Web-enabled application servers. All Servlet containers must support HTTP as a protocol for requests and responses, but additional request/response-based protocols such as HTTPS (HTTP over SSL) may be supported. The required versions of the HTTP specification that a container must implement are HTTP/1.0 and HTTP/1.1. Because the container may have a caching mechanism described in RFC2616 (HTTP/1.1), it may modify requests from the clients before delivering them to the Servlet, may modify responses produced by Servlets before sending them to the clients, or may respond to requests without delivering them to the Servlet under the compliance with RFC2616. A Servlet container may place security restrictions on the environment in which a Servlet executes. In a Java 2 Platform, Standard Edition or Java 2 Platform, Enterprise Edition environment, these restrictions should be placed using the permission architecture defined by the Java 2 platform. For example, high-end application servers may limit the creation of a Thread object to insure that other components of the container are not negatively impacted. J2SE is the minimum version of the underlying Java platform with which Servlet containers must be built. An Example The following is a typical sequence of events: 1. A client (e.g., a Web browser) accesses a Web server and makes an HTTP request. 2. The request is received by the Web server and handed off to the Servlet container. The Servlet container can be running in the same process as the host Web server, in a different process on the same host, or on a different host from the Web server for which it processes requests. 3. The Servlet container determines which Servlet to invoke based on the configuration of its Servlets, and calls it with objects representing the request and response.

© Trendz Information Technologies Ltd.

Page No. 29 of 220

J2EE

4. The Servlet uses the request object to find out who the remote user is, what

HTTP POST parameters may have been sent as part of this request, and other relevant data. The Servlet performs whatever logic it was programmed with, and generates data to send back to the client. It sends this data back to the client via the response object. 5. Once the Servlet has finished processing the request, the Servlet container ensures that the response is properly flushed, and returns control back to the host Web server. Comparing Servlets with Other Technologies In functionality, Servlets lie somewhere between Common Gateway Interface (CGI) programs and proprietary server extensions such as the Netscape Server API (NSAPI) or Apache Modules. Servlets have the following advantages over other server extension mechanisms: • • • • They are generally much faster than CGI scripts because a different process model is used. They use a standard API that is supported by many Web servers. They have all the advantages of the Java programming language, including ease of development and platform independence. They can access the large set of APIs available for the Java platform.

Servlet Interface: The Servlet interface is the central abstraction of the Java Servlet API. All Servlets implement this interface either directly, or more commonly, by extending a class that implements the interface. The two classes in the Java Servlet API that implement the Servlet interface are GenericServlet and HttpServlet. For most purposes, Developers will extend HttpServlet to implement their Servlets. Request Handling Methods The basic Servlet interface defines a service method for handling client requests. This method is called for each request that the Servlet container routes to an instance of a Servlet. The handling of concurrent requests to a Web application generally requires that the Web Developer design Servlets that can deal with multiple threads executing within the service method at a particular time. Generally the Web container handles concurrent requests to the same Servlet by concurrent execution of the service method on different threads. HTTP Specific Request Handling Methods The HttpServlet abstract subclass adds additional methods beyond the basic Servlet interface that are automatically called by the service method in the HttpServlet class to aid in processing HTTP-based requests. These methods are:

• •

doGet() for handling HTTP GET requests doPost() for handling HTTP POST requests

Typically when developing HTTP-based Servlets, a Servlet Developer will only concern himself with the doGet() and doPost() methods. The other methods are
© Trendz Information Technologies Ltd. Page No. 30 of 220

J2EE considered to be methods for use by programmers very familiar with HTTP programming. Conditional GET Support The HttpServlet interface defines the getLastModified() method to support conditional GET operations. A conditional GET operation requests a resource be sent only if it has been modified since a specified time. In appropriate situations, implementation of this method may aid efficient utilization of network resources. Number of Instances The Servlet declaration, which is part of the deployment descriptor of the Web application containing the Servlet, “Deployment Descriptor”, controls how the Servlet container provides instances of the Servlet. For a Servlet not hosted in a distributed environment (the default), the Servlet container must use only one instance per Servlet declaration. However, for a Servlet implementing the SingleThreadModel interface, the Servlet container may instantiate multiple instances to handle a heavy request load and serialize requests to a particular instance. In the case where a Servlet was deployed as part of an application marked in the deployment descriptor as distributable, a container may have only one instance per Servlet declaration per Java Virtual Machine (JVM). However, if the Servlet in a distributable application implements the SingleThreadModel interface, the container may instantiate multiple instances of that Servlet in each JVM of the container. Note About The Single Thread Model The use of the SingleThreadModel interface guarantees that only one thread at a time will execute in a given Servlet instance’s service method. It is important to note that this guarantee only applies to each Servlet instance, since the container may choose to pool such objects. Objects that are accessible to more than one Servlet instance at a time, such as instances of HttpSession, may be available at any particular time to multiple Servlets, including those that implement SingleThreadModel. It is recommended that a developer take other means to resolve those issues instead of implementing this interface, such as avoiding the usage of an instance variable or synchronizing the block of the code accessing those resources. The SingleThreadModel Interface is deprecated in this version of the specification. Servlet Life Cycle A Servlet is managed through a well-defined life cycle that defines how it is loaded and instantiated, is initialized, handles requests from clients, and is taken out of service. This life cycle is expressed in the API by the init, service, and destroy methods of the javax.Servlet.Servlet interface that all Servlets must implement directly or indirectly through the GenericServlet or HttpServlet abstract classes. Loading and Instantiation

© Trendz Information Technologies Ltd.

Page No. 31 of 220

J2EE The Servlet container is responsible for loading and instantiating Servlets. The loading and instantiation can occur when the container is started, or delayed until the container determines the Servlet is needed to service a request. When the Servlet engine is started, the Servlet container must locate the Servlet class. The Servlet container loads the Servlet class using normal Java class loading facilities. The loading may be from a local file system, a remote file system, or other network services. After loading the Servlet class, the container instantiates it for use. Initialization After the Servlet object is instantiated, the container must initialize the Servlet before it can handle requests from clients. Initialization is provided so that a Servlet can read persistent configuration data, initialize costly resources (such as JDBC™ API based connections), and perform other one-time activities. The container initializes the Servlet instance by calling the init method of the Servlet interface with a unique (per Servlet declaration) object implementing the ServletConfig interface. This configuration object allows the Servlet to access name-value initialization parameters from the Web application’s configuration information. The configuration object also gives the Servlet access to an object (implementing the ServletContext interface) that describes the Servlet’s runtime environment. See Chapter SRV.3, “Servlet Context” for more information about the ServletContext interface. Request Handling After a Servlet is properly initialized, the Servlet container may use it to handle client requests. Request objects of type ServletRequest represent requests. The Servlet fills out response to requests by calling methods of a provided object of type ServletResponse. These objects are passed as parameters to the service method of the Servlet interface. In the case of an HTTP request, the objects provided by the container are of types HttpServletRequest and HttpServletResponse. Note that a Servlet instance placed into service by a Servlet container may handle no requests during its lifetime. Multithreading Issues A Servlet container may send concurrent requests through the service method of the Servlet. To handle the requests, the Servlet developer must make adequate provisions for concurrent processing with multiple threads in the service method. Although it is not recommended, an alternative for the Developer is to implement the SingleThreadModel interface which requires the container to guarantee that there is only one request thread at a time in the service method. A Servlet container may satisfy this requirement by serializing requests on a Servlet, or by maintaining a pool of Servlet instances. If the Servlet is part of a Web application that has been marked as distributable, the container may maintain a pool of Servlet instances in each JVM that the application is distributed across. For Servlets not implementing the SingleThreadModel interface, if the service method (or methods such as doGet() or doPost() which are dispatched to the service method of the HttpServlet abstract class) has been defined with the synchronized keyword, the Servlet container cannot use the instance pool approach, but must serialize
© Trendz Information Technologies Ltd. Page No. 32 of 220

J2EE requests through it. It is strongly recommended that Developers not synchronize the service method (or methods dispatched to it) in these circumstances because of detrimental effects on performance. Thread Safety Implementations of the request and response objects are not guaranteed to be thread safe. This means that they should only be used within the scope of the request handling thread. References to the request and response objects should not be given to objects executing in other threads as the resulting behavior may be not determine. If the thread created by the application uses the container-managed objects, such as the request or response object, those objects must be accessed only within the Servlet’s service life cycle and such thread itself should have a life cycle within the life cycle of the Servlet’s service method because accessing those objects after the service method ends may cause indeterminist problems. Be aware that the request and response objects are not thread safe. If those objects were accessed in the multiple threads, the access should be synchronized or be done through the wrapper to add the thread safety, for instance, synchronizing the call of the methods to access the request attribute, or using a local output stream for the response object within a thread. End of Service The Servlet container is not required to keep a Servlet loaded for any particular period of time. A Servlet instance may be kept active in a Servlet container for a period of milliseconds, for the lifetime of the Servlet container (which could be a number of days, months, or years), or any amount of time in between. When the Servlet container determines that a Servlet should be removed from service, it calls the destroy method of the Servlet interface to allow the Servlet to release any resources it is using and save any persistent state. For example, the container may do this when it wants to conserve memory resources, or when it is being shut down. Before the Servlet container calls the destroy method, it must allow any threads that are currently running in the service method of the Servlet to complete execution, or exceed a server-defined time limit. Once the destroy method is called on a Servlet instance, the container may not route other requests to that instance of the Servlet. If the container needs to enable the Servlet again, it must do so with a new instance of the Servlet’s class. After the destroy method completes, the Servlet container must release the Servlet instance so that it is eligible for garbage collection. Servlet Context: ServletContext Interface The ServletContext interface defines a Servlet’s view of the Web application within which the Servlet is running. The Container Provider is responsible for providing an implementation of the ServletContext interface in the Servlet container. Using the ServletContext object, a Servlet can log events, obtain URL references to resources, and set and store attributes that other Servlets in the context can access.
© Trendz Information Technologies Ltd. Page No. 33 of 220

J2EE

Scope of a ServletContext Interface There is one instance object of the ServletContext interface associated with each Web application deployed into a container. In cases where the container is distributed over many virtual machines, a Web application will have an instance of the ServletContext for each JVM. Servlets in a container that were not deployed as part of Web application are implicitly part of a “default” Web application and have a default ServletContext. In a distributed container, the default ServletContext is non-distributable and must only exist in one JVM. Initialization Parameters The following methods of the ServletContext interface allow the Servlet access to context initialization parameters associated with a Web application as specified by the Application Developer in the deployment descriptor: • • getInitParameter getInitParameterNames

Initialization parameters are used by an Application Developer to convey setup information. Typical examples are a Webmaster’s e-mail address, or the name of a system that holds critical data. Context Attributes A Servlet can bind an object attribute into the context by name. Any attribute bound into a context is available to any other Servlet that is part of the same Web application. The following methods of ServletContext interface allow access to this functionality:

• • • •

setAttribute() getAttribute() getAttributeNames() removeAttribute()

Context Attributes in a Distributed Container Context attributes are local to the JVM in which they were created. This prevents ServletContext attributes from being a shared memory store in a distributed container. When information needs to be shared between Servlets running in a distributed environment, the information should be placed into a session stored in a database, or set in an Enterprise JavaBeans TM component. Resources The ServletContext interface provides direct access only to the hierarchy of static content documents that are part of the Web application, including HTML, GIF, and JPEG files, via the following methods of the ServletContext interface: • getResource()

getResourceAsStream()

The getResource() and getResourceAsStream() methods take a String with a leading “/” as an argument that gives the path of the resource relative to the root of the
© Trendz Information Technologies Ltd. Page No. 34 of 220

J2EE context. This hierarchy of documents may exist in the server’s file system, in a Web application archive file, on a remote server, or at some other location.

THE REQUEST: The request object encapsulates all information from the client request. In the HTTP protocol, this information is transmitted from the client to the server in the HTTP headers and the message body of the request. HTTP Protocol Parameters Request parameters for the Servlet are the strings sent by the client to a Servlet container as part of its request. When the request is an HttpServletRequest object, and conditions set out in “When Parameters Are Available” on page 36 are met, the container populates the parameters from the URI query string and POST-ed data. The parameters are stored as a set of name-value pairs. Multiple parameter values can exist for any given parameter name. The following methods of the ServletRequest interface are available to access parameters:

• • • •

getParameter() getParameterNames() getParameterValues() getParameterMap()

The getParameterValues() method returns an array of String objects containing all the parameter values associated with a parameter name. The value returned from the getParameter() method must be the first value in the array of String objects returned by getParameterValues(). The getParameterMap() method returns a java.util.Map of the parameter of the request, which contains names as keys and parameter values as map values. Data from the querystring and the post body are aggregated into the request parameter set. Querystring data is presented before post body data. For example, if a request is made with a query string of a=hello and a post body of a=goodbye&a=world, the resulting parameter set would be ordered a=(hello, goodbye, world). Path parameters that are part of a GET request are not exposed. They must be parsed from the String values returned by the getRequestURI() method or the getPathInfo() method. Attributes Attributes are objects associated with a request. Attributes may be set by the container to express information that otherwise could not be expressed via the API, or may be set by a Servlet to communicate information to another Servlet (via the RequestDispatcher). Attributes are accessed with the following methods of the ServletRequest interface:

• •

getAttribute() getAttributeNames()
Page No. 35 of 220

© Trendz Information Technologies Ltd.

J2EE

setAttribute()

Only one attribute value may be associated with an attribute name. Attribute names beginning with the prefixes of “java.” and “javax.” Are reserved for definition by this specification. Similarly, attribute names beginning with the prefixes of “sun.”, and “com.sun.” are reserved for definition by Sun Microsystems. It is suggested that all attributes placed in the attribute set be named in accordance with the reverse domain name convention suggested by the Java Programming Language Specification1 for package naming. Headers A Servlet can access the headers of an HTTP request through the following methods of the HttpServletRequest interface:

• • •

getHeader() getHeaders() getHeaderNames()

The getHeader() method returns a header given the name of the header. There can be multiple headers with the same name, e.g. Cache-Control headers, in an HTTP request. If there are multiple headers with the same name, the getHeader() method returns the first header in the request. The getHeaders() method allows access to all the header values associated with a particular header name, returning an Enumeration of String objects. Headers may contain String representations of int or Date data. The following convenience methods of the HttpServletRequest interface provide access to header data in a one of these formats:

• •

getIntHeader() getDateHeader()

If the getIntHeader() method cannot translate the header value to an int, a NumberFormatException is thrown. If the getDateHeader() method cannot translate the header to a Date object, an IllegalArgumentException is thrown. The following methods exist in the HttpServletRequest interface to access this information:

• • •

getContextPath() getServletPath() getPathInfo()

It is important to note that, except for URL encoding differences between the request URI and the path parts, the following equation is always true: requestURI = contextPath + ServletPath + pathInfo Cookies
© Trendz Information Technologies Ltd. Page No. 36 of 220

J2EE The HttpServletRequest interface provides the getCookies() method to obtain an array of cookies that are present in the request. These cookies are data sent from the client to the server on every request that the client makes. Typically, the only information that the client sends back as part of a cookie is the cookie name and the cookie value. Other cookie attributes that can be set when the cookie is sent to the browser, such as comments, are not typically returned. Lifetime of the Request Object Each request object is valid only within the scope of a Servlet’s service method, or within the scope of a filter’s doFilter() method. Containers commonly recycle request objects in order to avoid the performance overhead of request object creation. The developer must be aware that maintaining references to request objects outside the scope described above is not recommended as it may have indeterminate results. THE RESPONSE: The response object encapsulates all information to be returned from the server to the client. In the HTTP protocol, this information is transmitted from the server to the client either by HTTP headers or the message body of the request. Buffering A Servlet container is allowed, but not required, to buffer output going to the client for efficiency purposes. Typically servers that do buffering make it the default, but allow Servlets to specify buffering parameters. The following methods in the ServletResponse interface allow a Servlet to access and set buffering information:

• • • • • •

getBufferSize() setBufferSize() isCommitted() reset() resetBuffer() flushBuffer()

These methods are provided on the ServletResponse interface to allow buffering operations to be performed whether the Servlet is using a ServletOutputStream or a Writer. The getBufferSize() method returns the size of the underlying buffer being used. If no buffering is being used, this method must return the int value of 0 (zero). The Servlet can request a preferred buffer size by using the setBufferSize() method. The buffer assigned is not required to be the size requested by the Servlet, but must be at least as large as the size requested. This allows the container to reuse a set of fixed size buffers, providing a larger buffer than requested if appropriate. The method must be called before any content is written using a ServletOutputStream or Writer. If any content has been written or the response object has been committed, this method must throw an IllegalStateException.

© Trendz Information Technologies Ltd.

Page No. 37 of 220

J2EE The isCommitted() method returns a boolean value indicating whether any response bytes have been returned to the client. The flushBuffer() method forces content in the buffer to be written to the client. The reset method clears data in the buffer when the response is not committed. Headers and status codes set by the Servlet prior to the reset call must be cleared as well. The resetBuffer() method clears content in the buffer if the response is not committed without clearing the headers and status code. If the response is committed and the reset or resetBuffer() method is called, an IllegalStateException must be thrown. The response and its associated buffer will be unchanged. When using a buffer, the container must immediately flush the contents of a filled buffer to the client. If this is the first data is sent to the client, the response is considered to be committed. Convenience Methods The following convenience methods exist in the HttpServletResponse interface:

• •

sendRedirect() sendError()

The sendRedirect() method will set the appropriate headers and content body to redirect the client to a different URL. It is legal to call this method with a relative URL path, however the underlying container must translate the relative path to a fully qualified URL for transmission back to the client. If a partial URL is given and, for whatever reason, cannot be converted into a valid URL, then this method must throw an IllegalArgumentException. The sendError() method will set the appropriate headers and content body for an error message to return to the client. An optional String argument can be provided to the sendError() method, which can be used in the content body of the error. These methods will have the side effect of committing the response, if it has not already been committed, and terminating it. The Servlet should make no further output to the client after these methods are called. If data is written to the response after these methods are called, the data is ignored. If data has been written to the response buffer, but not returned to the client (i.e. the response is not committed), the data in the response buffer must be cleared and replaced with the data set by these methods. If the response is committed, these methods must throw an IllegalStateException. Closure of Response Object When a response is closed, the container must immediately flush all remaining content in the response buffer to the client. The following events indicate that the Servlet has satisfied the request and that the response object is to be closed:

• •

The termination of the service method of the Servlet. The amount of content specified in the setContentLength() method of the response has been written to the response.
Page No. 38 of 220

© Trendz Information Technologies Ltd.

J2EE

• •

The sendError() method is called. The sendRedirect() method is called.

Lifetime of the Response Object Each response object is valid only within the scope of a Servlet’s service method, or within the scope of a filter’s doFilter() method. Containers commonly recycle response objects in order to avoid the performance overhead of response object creation. The developer must be aware that maintaining references to response objects outside the scope described above may lead to non-deterministic behavior. Filtering Filters are Java components that allow on the fly transformations of payload and header information in both the request into a resource and the response from a resource. This describes the Java Servlet classes and methods that provide a lightweight framework for filtering active and static content. It describes how filters are configured in a Web application, and conventions and semantics for their implementation. What is a filter? A filter is a reusable piece of code that can transform the content of HTTP requests, responses, and header information. Filters do not generally create a response or respond to a request as Servlets do; rather they modify or adapt the requests for a resource, and modify or adapt responses from a resource. Filters can act on dynamic or static content. Dynamic and static content are referred to as Web resources. Among the types of functionality available to the developer needing to use filters are the following: • • • • • • The accessing of a resource before a request to it is invoked. The processing of the request for a resource before it is invoked. The modification of request headers and data by wrapping the request in customized versions of the request object. The modification of response headers and response data by providing customized versions of the response object. The interception of an invocation of a resource after its call. Actions on a Servlet, on groups of Servlets, or static content by zero, one, or more filters in a specifiable order.

Implementation Filtering Components • Authentication filters • Logging and auditing filters • Image conversion filters • Data compression filters • Encryption filters • Tokenizing filters • Filters that trigger resource access events Main Concepts

© Trendz Information Technologies Ltd.

Page No. 39 of 220

J2EE The main concepts of this filtering model are described in this section. The application developer creates a filter by implementing the javax.Servlet.Filter interface and providing a public constructor taking no arguments. The class is packaged in the Web Archive along with the static content and Servlets that make up the Web application. A filter is declared using the <filter> element in the deployment descriptor. A filter or collection of filters can be configured for invocation by defining <filter-mapping> elements in the deployment descriptor. This is done by mapping filters to a particular Servlet by the Servlet’s logical name, or mapping to a group of Servlets and static content resources by mapping a filter to a URL pattern. Filter Lifecycle After deployment of the Web application, and before a request causes the container to access a Web resource, the container must locate the list of filters that must be applied to the Web resource as described below. The container must ensure that it has instantiated a filter of the appropriate class for each filter in the list, and called its init(FilterConfig config) method. The filter may throw an exception to indicate that it cannot function properly. If the exception is of type UnavailableException, the container may examine the isPermanent attribute of the exception and may choose to retry the filter at some later time. When the container receives an incoming request, it takes the first filter instance in the list and calls its doFilter() method, passing in the ServletRequest and ServletResponse, and a reference to the FilterChain object it will use. The doFilter() method of a filter will typically be implemented following this or some subset of the following pattern: Step 1:The method examines the request’s headers. Step 2:The method may wrap the request object with a customized implementation of ServletRequest or HttpServletRequest in order to modify request headers or data. Step 3:The method may wrap the response object passed in to its doFilter method with a customized implementation of ServletResponse or HttpServletResponse to modify response headers or data. Step 4:The filter may invoke the next entity in the filter chain. The next entity may be another filter, or if the filter making the invocation is the last filter configured in the deployment descriptor for this chain, the next entity is the target Web resource. The filter chain’s implementation of the doFilter method, provided by the container, must locate the next entity in the filter chain and invoke its doFilter() method, passing in the appropriate request and response objects. Alternatively, the filter chain can block the request by not making the call to invoke the next entity, leaving the filter responsible for filling out the response object. Step 5:After invocation of the next filter in the chain, the filter may examine response headers. Step 6:Alternatively, the filter may have thrown an exception to indicate an error in processing. If the filter throws an UnavailableException during its doFilter processing, the container must not attempt continued processing down the filter chain. It may choose to retry the whole chain at a later time if the exception is not marked permanent. Step 7:When the last filter in the chain has been invoked, the next entity accessed is the target Servlet or resource at the end of the chain.

© Trendz Information Technologies Ltd.

Page No. 40 of 220

J2EE Step 8: Before a filter instance can be removed from service by the container, the container must first call the destroy method on the filter to enable the filter to release any resources and perform other cleanup operations. Configuration of Filters in a Web Application A filter is defined in the deployment descriptor using the <filter> element. In this element, the programmer declares the following: • • • filter-name: used to map the filter to a Servlet or URL filter-class: used by the container to identify the filter type init-params: initialization parameters for a filter

Optionally, the programmer can specify icons, a textual description, and a display name for tool manipulation. The container must instantiate exactly one instance of the Java class defining the filter per filter declaration in the deployment descriptor. Hence, two instances of the same filter class will be instantiated by the container if the developer makes two filter declarations for the same filter class. Here is an example of a filter declaration: <filter> <filter-name>Image Filter</filter-name> <filter-class>com.acme.ImageServlet</filter-class> </filter> Once a filter has been declared in the deployment descriptor, the assembler uses the <filter-mapping> element to define Servlets and static resources in the Web application to which the filter is to be applied. Filters can be associated with a Servlet using the <Servlet-name> element. For example, the following code example maps the Image Filter filter to the ImageServlet Servlet: <filter-mapping> <filter-name>Image Filter</filter-name> <Servlet-name>ImageServlet</Servlet-name> </filter-mapping> Here the Logging Filter is applied to all the Servlets and static content pages in the Web application, because every request URI matches the ‘/*’ URL pattern. When processing a <filter-mapping> element using the <url-pattern> style, the container must determine whether the <url-pattern> matches the request URI. The order the container uses in building the chain of filters to be applied for a particular request URI is as follows:

1. First, the <url-pattern> matching filter mappings in the same order that 2. Next, the <Servlet-name> matching filter mappings in the same order that
these elements appear in the deployment descriptor. This requirement means that the container, when receiving an incoming request, processes the request as follows: these elements appear in the deployment descriptor.

If there are filters matched by Servlet name and the Web resource has a <Servlet-name>, the container builds the chain of filters matching in the
Page No. 41 of 220

© Trendz Information Technologies Ltd.

J2EE order declared in the deployment descriptor. The last filter in this chain corresponds to the last <Servlet-name> matching filter and is the filter that invokes the target Web resource. If there are filters using <url-pattern> matching and the <url-pattern> matches the request URI. The last filter in this chain is the last <url-pattern> matching filter in the deployment descriptor for this request URI. The last filter in this chain is the filter that invokes the first filter in the <Servletname> matching chain, or invokes the target Web resource if there are none.

It is expected that high performance Web containers will cache filter chains so that they do not need to compute them on a per-request basis. Sessions The Hypertext Transfer Protocol (HTTP) is by design a stateless protocol. To build effective Web applications, it is imperative that requests from a particular client be associated with each other. Many strategies for session tracking have evolved over time, but all are difficult or troublesome for the programmer to use directly. This specification defines a simple HttpSession interface that allows a Servlet container to use any of several approaches to track a user’s session without involving the Application Developer in the nuances of any one approach. Session Tracking Mechanisms The following sections describe approaches to tracking a user’s sessions Cookies Session tracking through HTTP Cookies is the most used session tracking mechanism and is required to be supported by all Servlet containers. The container sends a cookie to the client. The client will then return the cookie on each subsequent request to the server, unambiguously associating the request with a session. The name of the session tracking cookie must be JSESSIONID. URL Rewriting URL Rewriting is the lowest common denominator of session tracking. When a client will not accept a cookie, the server as the basis for session tracking may use URL rewriting. URL rewriting involves adding data, a session ID, to the URL path that is interpreted by the container to associate the request with a session. The session ID must be encoded as a path parameter in the URL string. The name of the parameter must be jsessionid. Here is an example of a URL containing encoded path information: http://www.myserver.com/catalog/index.html;jsessionid=1234 Creating a Session A session is considered “new” when it is only a prospective session and has not been established. Because HTTP is a request-response based protocol, an HTTP session is considered to be new until a client “joins” it. A client joins a session when session tracking information has been returned to the server indicating that a session has been established. Until the client joins a session, it cannot be assumed that the next request from the client will be recognized as part of a session. The session is considered to be “new” if either of the following is true:

© Trendz Information Technologies Ltd.

Page No. 42 of 220

J2EE • • The client does not yet know about the session The client chooses not to join a session.

These conditions define the situation where the Servlet container has no mechanism by which to associate a request with a previous request. A Servlet Developer must design his application to handle a situation where a client has not, cannot, or will not join a session. Session Scope HttpSession objects must be scoped at the application (or Servlet context) level. The underlying mechanism, such as the cookie used to establish the session, can be the same for different contexts, but the object referenced, including the attributes in that object, must never be shared between contexts by the container. Session Timeouts In the HTTP protocol, there is no explicit termination signal when a client is no longer active. This means that the only mechanism that can be used to indicate when a client is no longer active is a timeout period. The default timeout period for sessions is defined by the Servlet container and can be obtained via the getMaxInactiveInterval() method of the HttpSession interface. This timeout can be changed by the Developer using the setMaxInactiveInterval() method of the HttpSession interface. The timeout periods used by these methods are defined in seconds. By definition, if the timeout period for a session is set to -1, the session will never expire. The session invalidation will not take effect until all Servlets using that session have exited the service method. Once the session invalidation is initiated, a new request must not be able to see that session. Dispatching Requests When building a Web application, it is often useful to forward processing of a request to another Servlet, or to include the output of another Servlet in the response. The RequestDispatcher interface provides a mechanism to accomplish this. Obtaining a RequestDispatcher An object implementing the RequestDispatcher interface may be obtained from the ServletContext via the following methods:

• •

getRequestDispatcher() getNamedDispatcher()

The getRequestDispatcher() method takes a String argument describing a path within the scope of the ServletContext. This path must be relative to the root of the ServletContext and begin with a ‘/’. The method uses the path to look up a Servlet, using the Servlet path. If no Servlet can be resolved based on the given path, a RequestDispatcher is provided that returns the content for that path. The behavior of this method is similar to the method of the same name in the ServletContext. The Servlet container uses information in the request object to transform the given relative path against the current Servlet to a complete path.

© Trendz Information Technologies Ltd.

Page No. 43 of 220

J2EE For example, in a context rooted at ’/’ and a request to /garden/tools.html, a request dispatcher obtained via ServletRequest.getRequestDispatcher("header.html") will behave exactly like a call to ServletContext.getRequestDispatcher("/Trendz/ header.html"). Using a Request Dispatcher To use a request dispatcher, a Servlet calls either the include method or forward method of the RequestDispatcher interface. The parameters to these methods can be either the request and response arguments that were passed in via the service method of the javax.Servlet interface, or instances of subclasses of the request and response wrapper classes that were introduced for version 2.3 of the specification. In the latter case, the wrapper instances must wrap the request or response objects that the container passed into the service method. The Container Provider should ensure that the dispatch of the request to a target Servlet occurs in the same thread of the same JVM as the original request. The include() Method The include() method of the RequestDispatcher interface may be called at any time. The target Servlet of the include method has access to all aspects of the request object, but its use of the response object is more limited. It can only write information to the ServletOutputStream or Writer of the response object and commit a response by writing content past the end of the response buffer, or by explicitly calling the flushBuffer() method of the ServletResponse interface. It cannot set headers or call any method that affects the headers of the response. Any attempt to do so must be ignored. Included Request Parameters Except for Servlets obtained by using the getNamedDispatcher() method, a Servlet that has been invoked by another Servlet using the include method of RequestDispatcher has access to the path by which it was invoked. The Forward Method The forward method of the RequestDispatcher interface may be called by the calling Servlet only when no output has been committed to the client. If output data exists in the response buffer that has not been committed, the content must be cleared before the target Servlet’s service method is called. If the response has been committed, an IllegalStateException must be thrown. The path elements of the request object exposed to the target Servlet must reflect the path used to obtain the RequestDispatcher. The only exception to this is if the RequestDispatcher was obtained via the getNamedDispatcher() method. In this case, the path elements of the request object must reflect those of the original request. Before the forward method of the RequestDispatcher interface returns, the response content must be sent and committed, and closed by the Servlet container.

© Trendz Information Technologies Ltd.

Page No. 44 of 220

J2EE

© Trendz Information Technologies Ltd.

Page No. 45 of 220

J2EE JAVA RMI OVERVIEW Distributed systems required that computations running in different address spaces, potentially on different hosts, be able to communicate. For a basic communication mechanism, the Java™ Language supports sockets, which are flexible and sufficient for general communication. However, sockets require the client and decode messages for exchange, and the design of such protocols is cumbersome and can be error-prone. An alternative to sockets is Remote Procedure Call (RPC), which abstracts the communication interface to the level of a procedure call. Instead of working directly with sockets, the programmer has the illusion of calling a local procedure, when in fact the arguments of the call are packaged up and shipped off to the remote target of the call. RPC systems encode arguments and return values using an external data representation, such as XDR. RPC, however, does not translate well into distributed object system, where communication between program-level objects residing in different address spaces is needed. In order to match the semantics of object invocation, distributed object systems require Remote Method Invocation or RMI. In such systems, a local surrogate (stub) object manages the invocation on a remote object. The Java remote method invocation system described in this specification has been specifically designed to operate in the Java environment. The Java language’s RMI system assumes the homogeneous environment of the Java virtual Machine, and the system can therefore take advantage of the Java object model whenever possible. System Goals The goals for supporting distributed objects in the Java language are:         Support seamless remote invocation on objects in different virtual machines. Support callbacks from servers to applets. Integrate the distributed object model into the Java language in a natural way while retaining most of the Java language’s object semantics. Make differences between the distributed object model and local Java object model apparent. Make writing reliable distributed applications as simple as possible. Preserver the type-safety provided by the Java runtime environment. Various reference semantics for remote objects; for example live (NonPersistent) references, persistent references, and lazy activation. The safe Java environment provided by security managers and class loaders.

Underlying all these goals is a general requirement that the RMI model be both simple (easy to use) and natural (fits well in the language). The first two chapters in this specification describe the distributed object model for the Java language and the system overview. The remaining chapters describe the RMI client and server visible APIs which are part of JDK 1.2. Distributed Object Applications RMI applications are often comprised of two separate programs i.e. a server and a client. A typical server application creates a number of remote objects, makes references to those remote objects accessible, and waits for clients to invoke
© Trendz Information Technologies Ltd. Page No. 46 of 220

J2EE methods on those remote objects. A typical client application gets a remote reference to one or more remote objects in the server and then invokes methods on them. RMI provides the mechanism by which the server and the client communicate and pass information back and forth. Such an application is sometimes referred to as a Distributed Object Application. Distributed Object Applications need to:  Locate Remote Objects: Applications can use one of two mechanisms to obtain references to remote objects. An application can register its remote objects with RMI’s simple naming facility, the rmiregistry, or the application can pass and return remote object references as part of its normal operation. Communicate with Remote Objects: Details of communication between remote objects are handled by RMI; to the programmer, remote communication looks like a standard Java Method Invocation. Load class bytecodes for objects that are passed as parameters or return values because RMI allows a caller to pass pure Java objects to remote objects. RMI provides the necessary mechanisms for loading an object’s code as well as transmitting its data.

The illustration below depicts an RMI distributed application that uses the registry to obtain references to a remote object. The server calls the registry to associate a name with a remote object. The client looks up the remote object by its name in the server’s registry and then invokes a method on it. The illustration also shows that the RMI system uses an existing web server to load Java class bytecodes from server to client and from client to server, for objects when needed. RMI can load class bytecodes using any URL protocol (Ex. HTTP, FTP, File etc.) that is supported by the Java System. Definition of Terms In the Java distributed object model, a remote object is one whose methods can be invoked from another Java Virtual Machine, potentially on a different host. An object of this type is described by one or more remote interfaces, which are Java interfaces that declare the methods of the remote objects. Remote Method Invocation (RMI) is the action of invoking a method of a remote interface on a remote object. Most importantly, a method invocation on a remote object has the same syntax as a method invocation on a local object. The Distributed and Non Distributed Models Contrasted The Java distributed object model is similar to the Java object model in the following ways:    A reference to a remote object can be passed as an argument or returned as a result in any method invocation (Local or Remote). A remote object can be cast to any of the set of remote interfaces supported by the implementation using the built in Java syntax for casting. The built in Java instance of operation can be used to test the remote interfaces supported by a remote object.
Page No. 47 of 220

© Trendz Information Technologies Ltd.

J2EE

The Java distributed object model differs from the Java object model in these ways:   Clients of remote objects interact with remote interfaces, never with the implementation classes of those interfaces. Non-Remote arguments to, and results from, a remote method invocation are passed by copy rather than by references to objects are only useful within a single virtual machine. A remote object is passed by references, not by copying the actual remote implementation. The semantics of some of the methods defined by class java.lang.object are specialized for remote objects. Since the failure modes of invoking remote objects are inherently more complicated than the failure modes of invoking local objects, clients must deal with additional exceptions that can occur during a remote method invocation.

  

Overview of RMI Interfaces and Classes The interfaces and classes that are responsible for specifying the remote behavior of the RMI system are defined in the java.rmi package hierarchy. The following figure shows the relationship between several of these interfaces and classes: The java.rmi Remote Interface In RMI, a remote interface is an interface that declares a set of methods that may be invoked from a remote Java Virtual Machine. A remote interface must satisfy the following requirements.    A remote interface must at least extend, either directly or indirectly, the interface java.rmi.remote. Each method declaration in a remote interface must satisfy the requirements of a remote method declaration as follows: A remote method declaration must include the exception java.rmi.RemoteException (or one of its superclasses such as java.io.IOException or java.lang.Exception) in its throws clause. In addition to any application specific exceptions (note that application specific exceptions do not have to extend java.rmi.RemoteException). In a remote method declaration, a remote object declared as a parameter or return value (either declared directly in the parameter list or embedded within a non-remote object in a parameter) must be declared as the remote interface, not the implementation class of that interface.

The interface java.rmi.Remote is a marker interface that defines no methods: public interface remote {} Implementing a Remote Interface The general rules for a class that implements a remote interface are as follows:  That class usually e3xtends java.rmi.server.UnicastRemoteObject, thereby inheriting the remote behavior provided by the classes java.rmi.server.RemoteObject and java.rmi.server.RemoteServer. The class can implement any number of remote interface. The class can extend another remote implementation class.
Page No. 48 of 220

 

© Trendz Information Technologies Ltd.

J2EE  The class can define methods that do not appear in the remote interface, but those methods can only be used locally and are not available remotely.

Parameter Passing in Remote Method Invocation An argument to, or a return value from, a remote object can be any Java object that is serializable. This includes Java primitive types, remote Java objects, and nonremote Java Objects that implement the java.io.Serializable interface. For more details on how to make classes serializable, see the Java “Object Serialization Specification”. Classes, for parameters or return values that are not available locally are downloaded dynamically by the RMI system. Passing Non-Remote Objects A Non-Remote Object, that is passed as a parameter of a remote method invocation or returned as a result of a remote method invocation, is passed by copy; that is, the object is serialized using the Java Object Serialization Mechanism. So, when a Non-Remote Object is passed as an argument or return value in a remote method invocation, the content of the Non-Remote Object is copied before invoking the call on the remote object. When a Non-Remote Object is returned from a remote method invocation, a new object is created in the calling virtual machine. Passing Remote Objects When passing a remote object as a parameter or return value in a remote method call, the stub for the remote object is passed. A remote object passed as a parameter can only implement remote interfaces. Referential Integrity If two references to an object are passed from one VM to another VM in parameters (or in the return value) in a single remote method call and those references refer to the same object in the sending VM, those references will refer to a single copy of the object in the receiving VM. More generally stated: within a single remote method call, the RMI system maintains referential integrity among the objects passed as parameters or as a return value in the call. Class Annotation When an object is sent from one VM to another in a remote method call, the RMI system annotates the class descriptor in the call stream with information (the URL) of the class so that the class can be loaded at the receiver. It is a requirement that classes be downloaded on demand during remote method invocation. Parameter Transmission Parameters in an RMI call are written to a stream that is a subclass of the class java.io.ObjectOutputStream in order to serialize the parameters to the destination of the remote call. The ObjectOutputStream subclass overrides the replace Object method to replace each remote object with its corresponding stub class. Parameters that are objects are written to the stream using the ObjectOutputStream’s writeObject() method.

© Trendz Information Technologies Ltd.

Page No. 49 of 220

J2EE ObjectOutputStream calls the replaceObject() method for each object written to the stream via the writeObject() method (that includes objects referenced by those objects that are written). The replaceObject() method of RMI’s subclass of ObjectOutputStream returns the following.  If the object passed to replaceObject is an instance of java.rmi.Remote, then it returns the stub for the remote object. A stub for a remote object is obtained via a call to the method java.rmi.server.RemoteObject.toStub. If the object passed to replaceObject is not an instance of java.rmi.Remote then the object is simply returned.

RMI’s subclass of ObjectOutputStream also implements the annotateClass method that annotates the call stream with the location of the class so that it can be downloaded at the receiver. Since parameters are written to a single ObjectOutputStream, references that refer to the same object at the caller will refer to the same copy of the object at the receiver. At the receiver, parameters are read by a single ObjectInputStream. Any other default behavior of ObjectOutputStream for writing objects (and similarly ObjectInputStream for reading objects) is maintained in parameter passing. For example, the calling of writeReplace when writing objects and readResolve when reading objects is honored by RMI’s parameter marshal and unmarshal streams. In a similar manner to parameter passing in RMI as described above, a return value (or exception) is written to a subclass of ObjectOutputStream and has the same replacement behavior as parameter transmission. Locating Remote Objects A simple bootstrap name server is provided for storing named references to remote objects. A remote object reference can be stored using the URL-based methods of the class java.rmi.Naming. For a client to invoke a method on a remote object, that client must first obtain a reference to the object. A reference to a remote object is usually obtained as a parameter or return value in a method call. The RMI system provides a simple bootstrap name server from which to obtain remote objects on given hosts. The java.rmi.Naming class provides Uniform Resource Locator (URL) based methods to look up, bind, rebind, unbind, and list the name-object pairings maintained on a particular host and port. Stubs and Skeletons RMI uses a standard mechanism (employed in RPC systems) for communicating with remote objects: Stubs and Skeletons. A stub for a remote object acts as a client’s local representative or proxy for the remote object. The caller invokes a method on the local stub, which is responsible for carrying out the method call on the remote object. In RMI, a stub for remote object implements the same set of remote interfaces that a remote object implements.

© Trendz Information Technologies Ltd.

Page No. 50 of 220

J2EE When a stub’s method is invoked, it does the following:      Initiates a connection with the remote VM containing the remote object. Marshals (writes and transmits) the parameters to the remote VM. Waits for the result of the method invocation. Unmarshals (reads) the return value or exception returned Returns the value to the caller.

The stub hides the serialization of parameters and the network-level communication in order to present a simple invocation mechanism to the caller. In the remote VM, each remote object may have a corresponding skeleton (in JDK 1.2 only environments, skeletons are not required). The skeleton is responsible for dispatching the call to the actual remote object implementation. When a skeleton receives an incoming method invocation it does the following;    Unmarshals (reads) the parameters for the remote method. Invokes the method on the actual remote object implementation. Marshals (writes & transmits) the results (return value or exception) to the caller.

In JDK 1.2 and additional stub protocol was introduced that eliminates the need for skeletons in JDK 1.2 only environments. Instead, generic code is used to carry out the duties performed by skeletons in JDK 1.1. The rmic compiler generates stubs and skeletons. Threads Usage in Remote Method Invocation A method dispatched by the RMI runtime to a remote object implementation may or may not execute in a separate thread. The RMI runtime makes no guarantees with respect to mapping remote object invocations to threads. Since remote method invocation on the same remote object may execute concurrently, a remote object implementation needs to make sure its implementation is thread-safe. Garbage Collection of Remote Objects In a distributed system, just as in the local system, it is desirable to automatically delete those remote objects that are no longer referenced by any client. This fees the programmer from needing to keep track of the remote objects clients so that it can terminate approximately. RMI uses a reference-counting garbage collection algorithm similar to Modula-3’s Network Objects. To accomplish reference-counting garbage collection, the RMI runtime keeps track of all live references within each Java Virtual Machine. When a live reference enters a Java Virtual Machine, its reference count is incremented. The first reference to an object sends a “Referenced” message to the server for the object. As live references are found to be unreferenced in the local virtual machine, the count is decremented. When the last reference has been discarded, an unreferenced message is sent to the server. Many subtleties exist in the protocol; most of these are related to maintaining the ordering of referenced and unreferenced messages in order to ensure that the object is not prematurely collected. When any client does not references a remote object, the RMI runtime refers to it using a weak reference. The weak reference allows the Java Virtual Machine’s garbage collector to discard the object if not other local references to the object
© Trendz Information Technologies Ltd. Page No. 51 of 220

J2EE exist, the distributed garbage collection algorithm interacts with the local Java Virtual Machine’s garbage collector in the usual ways by holding normal or weak references to objects. As long as a local reference to a remote object exists, it cannot be garbage-collected and it can be passed in remote calls or returned to clients. Passing a remote object adds the identifier for the virtual machine to which it was passed to the referenced set. A remote object needing unreferenced notification must implement the java.rmi.server. Unreferenced interface. When those references no longer exist, the unreferenced method will be invoked. Unreferenced is called when the set of references is found to be empty so it might be called more than once. Remote objects are only collected when no more references either local or remote, still exist. Note that if a network partition exists between a client and a remote server object, it is possible that premature collection of the remote object will occur (since the transport might believe that the client crashed). Because of the possibility of premature collection, remote references cannot guarantee referential integrity; in other words, it is always possible that a remote reference may in fact not refer to an existing object. An attempt to use such a reference may in fact not refer to an existing object. An attempt to use such a reference will generate a RemoteException, which must be handled by the application. Understating the first RMI application. The Remote Interface import java.rmi.*; public interface Rmilnter extends Remote { public double getSqrt(doubled) thros RemoteException; } The ServerImplementation Class import java.rmi.*; import java.rmi.server.*; public class ServerImpl extends UnicastRemoteObject implements RmiInter { public ServerImpl() throws RemoteException { System.Out.println(“Object created”) } public double getSqrt(double d) throws RemoteException { return Math.sqrt(d); } public static void main (String args[]) throws Exception { ServerImpl si=new ServerImpl(); Naming.rebind(“server”,si); System.out.println(“Object bounded to remote network”); }
© Trendz Information Technologies Ltd. Page No. 52 of 220

J2EE } Client Application import java.io.*; import java.rmi.*; public class Client { public satic void main(String args[]) throws Exception { RmiInter ri=(RmiInter) Naming.lookup(“rmi://localhost:1099/server”); DataInputStream dis=new DataInputStream(System.in); System.out.println(“Enter a double number to know its sqrt”); String num=dis.readLine(); double d=Double.parseDouble(num); System.out.prinIn(“The Sqr is” +ri.getDouble(d)); } } Executing the application a. b. c. d. e. Compile the 3 applications with “javac”. Generate Stub and Skeleton for the server implementation class. Start the rmiregistry. On prompt c:\> rmiregistry. Take 2nd prompt, start the rmiserver. Take 3rd prompt, start the rmiclient.

Remote Callbacks We have seen earlier how a client can get a reference to a remote object as result of a method invocation. A client also can be a remote object. In some situations, a server may need to make a remote call to a client. Example for Understanding the Remote Callbacks When a Client application is observed, it is first looking the server object and calling the methods using the remote reference. In remote callback server need not to lookup the client object explicitly because when client requests the connection, the server identifies the client, using which it can call a method on the client. For Callback an interface for client is also required CallClientInter.java import java.rmi.*; public interface CallClientInter extends remote { public void msgPopup(String msg) throws RemoteException; } CallServerInter.java import java.rmi.*; public interface CallServerInter extends Remote { public String sayHello(CallClientInter cci) throws RemoteException; }
© Trendz Information Technologies Ltd. Page No. 53 of 220

J2EE

CallClientImpl.java import java.applet.*; import java.awt.*; import java.io.Serializable; import java.rmi.* import java.rmi.server.*; public class CallClientImpl extends Applet implements CallClientInter.Serializable { Strint msg=” “; Frame f=new Frame(); Label l1=new Label(“ Public void init() { f.add(l); try { UnicastRemoteObject.exportObject(this); String host=”rmi://”+getcodeBase().getHost()+”HelloServer”; CallServerInter csi=(CallServerInter) Naming.lookup(host); Msg=csi.getSayHello(CallClientInter) this); } } Public void paint(Graphics g) { g.drawstring(msg,50,50); } public void msgPopup(String s) throws RemoteException { l1.setText(s); f.setSize(100,100); f.setVisible(true); } } CallClientImpl.html <applet code=CallClientImpl width=300 height=300> </applet> CallServerImpl.java import java.util.Date; import java.rmi.*; import java.rmi.server.*; public class CallServerImpl extends UnicastRemoteObject implements CallServerInter { public CallServerImpl() throws RemoteException { System.out.println(“Object created”); }
© Trendz Information Technologies Ltd. Page No. 54 of 220

J2EE public String say Hello(CallClientInter cci) throws Remote Exception { cci.msgPopip(“Hello From Server”); return “Current Date” +new Date(); } public static void main(String args[]) throws Exception { CallServerImpl csi=new CallServerImpl(); Naming.rebind(“HelloServer”,csi); } } Dynamic Class Loading RMI allows parameters; return values and exceptions passed in RMI calls to be any object that is serializable. RMI uses the object serialization mechanism to transmit data from one virtual machine to another and also annotates the call stream with the appropriate location information so that the class definition files can be loaded at the receiver. When parameters and return values for a remote method invocation are unmarshalled to become live objects in the receiving VM, class definitions are required for all of the types of objects in the stream. The unmarshalling process first attempts to resolve classes by name in its local class loading context (the context class loader of the current thread). RMI also provides a facility for dynamically loading the class definitions for the actual types of objects passed as parameters and return values for remote method invocations from network locations specified by the transmitting endpoint. This includes the dynamic downloading of remote stub classes corresponding to particular remote object implementation classes (and used to contain remote references) as well as any other type that is passed by value in RMI calls, such as the subclass of a declared parameter type, that is not already available in the class loading context of the unmarshalling side. To support dynamic class loading, the RMI runtime uses special subclasses of java.io.ObjectOutputStream and java.io.ObjectInputStream for the marshal streams that it uses for marshalling and unmarshalling RMI parameters and return values. These subclasses override the annotateClass method of ObjectOutputStream and the resolveClass method of ObjectInputStream to communicate information about where to locate class files containing the definitions for classes corresponding to the class descriptors in the stream. For every class descriptor written to an RMI marshal stream, the annotateClass method adds to the stream the result of calling java.rmi.server.RMIClassLoader. getClassAnnotation for the class object, which may be null or may be a String object representing the codebase URL path (a space-separated list of URLs) from which the remote endpoint should download the class definition file for the given class. For every class descriptor read from an RMI marshal stream, the resolveClass method reads a single object from the stream. If the object is a String (and the value of the java.rmi.server.useCodebaseOnly, property is not “true”), then resolveClass returns the result of calling RMIClassLoader.loadClass with the annotated String object as the first parameter and the name of the desired class in the class descriptor as the second parameter. Otherwise, resolveClass returns the

© Trendz Information Technologies Ltd.

Page No. 55 of 220

J2EE result of calling RMIClassLoader.loadClass with the name of the desired class as the only parameter. When a client requests a reference to the remote object, the registry returns the stub to the client. The client looks for the class definition of the stub in its local classpath (by default) and if found, the client loads the class or utilizes its codebase property. Based upon the above, five potential configuration can be set up to distribute classes. a. Closed There is no dynamic loading of classes. JVM loads the classes from local classpath only. b. Dynamic Client Side On the client, some classes loaded from the local classpath and some from the codebase specified by the server. c. Dynamic Server Side Similar to dynamic lcient. Some classes loaded from the classpath and some from codebase specified by the client. d. BootStrapped Client On the client, all the classes are loaded from codebase specified by the server. e. BootStrapped Server On the server, all the classes are loaded from codebase specified by the client. Example: BootInter.java import java.rmi.*; public interface BootInter extends Remote { public String sayHello() throws RemoteException; } BootInterImpl.java import java.rmi.*; import java.rmi.server.*; public class bootInterImpl extends UnicastRemoteObject implements BootInter { public BootInterImpl() throws RemoteException { System.out.println(“Remote object created”); } public String sayHello() throws RemoteException { return “Hellow from Server”; }
© Trendz Information Technologies Ltd. Page No. 56 of 220

J2EE } BootServer.java import java.rmi.*; import java.util.*; public class BootServer { public static void main (String args[]) throws Exception { Properties p=System.getProperties(); String s=p.getProperty(“java.rmi.server.codebase”); Class c=RMIClassLoader.loadClass(s,”BootInterImpl”); Naming.rebind(“bootserver”,(Remote) c.newInstance()); System.out.println(“Object Created”); } } Client.java Import java.rmi.*; Public class Client { public Client() { try { BootInter bi=(BootInter) Naming.lookup(“rmi://localhost:1099/bootserver”); System.out.println(bi.sayHello()); }catch(Exception e){} } } BootClient.java import java.rmi.*; import java.rmi.server.*; import java.util.*; public class BootClient { public static void main(String args[]) throws Exception { Properties p=System.getProperties(); String s=p.getProperty(“java.rmi.server.codebase”); Class c=RMIClassLoader.loadClass(S,”Client”); c.newInstance(); } }

Object Activation

© Trendz Information Technologies Ltd.

Page No. 57 of 220

J2EE The remote objects discussed so far are instances of java.rmi.UnicastRemoteObject class, and they are accessible all time, even when there are no clients executing. Consider, when the number remote objects and resources used by them, on a server are high. To overcome this, Object Activation was introduced. Object Activation Allows remote objects to be executed on as needed basis i.e. remote object is accessed (via a method invocation) if that currently executing the system initiates the objects execution JVM. RMI uses lazy activation, this is where the activation of until a client first use, the first method invocation. when an ‘activatable’ remote object is not inside an appropriate an object is deferred

To understand the actual semantics of using activation model, let us understand few terms. Activator It facilitates remote object activation by keeping track of all the information needed to activate an object and is responsible for starting the instances of JVMs on the server. Activation Group Activation Group creates instances of objects in its group, and informs its monitor about the various active and passive states. Activation Monitor Every Activation Group have an Activation Monitor that keeps track of an object’s state in the group and the group’s state as a whole. Activation System The Activation System provides a means for registering groups and activatable objects to be activated within those groups.

© Trendz Information Technologies Ltd.

Page No. 58 of 220

J2EE

Overview & Importance Web Application Development JSP Directives JSP Action Tags JSP Custom Tag Library

© Trendz Information Technologies Ltd.

Page No. 59 of 220

J2EE JAVA SERVER PAGES OVERVIEW The Internet was once full of Web sites hosting static pages or simple forms at best. Now it's an interactive environment for transacting daily business, from shopping to trading stocks to interacting with suppliers, in a personalized and dynamic setting. Today, the tools and products to build dynamic, Web-based applications are still maturing. Traditionally, companies used CGI applications to generate dynamic content for Web pages. But that solution hasn't scaled well to support complex functionality and growing numbers of concurrent users. Java Server Pages technology provides a highly scalable method for creating dynamic content for the Web. As part of the Java family of APIs, JSP technology shares the “Write Once, Run Anywhere” benefits of the Java platform, with easy access to a broad range of Java APIs. JSP technology enables a tiered development methodology that lets organizations leverage internal programming expertise to create applications that are fast to deploy and easy to maintain. Multi-tier Application Architectures The growth and acceptance of the Internet in both businesses and homes is changing the face of many industries - and the information systems that support them. From new .com companies to brick-and-mortar establishments, businesses everywhere are finding new ways to leverage the power of the Internet. Software developers have been quick to realize the possibilities of Web-based clients in application architectures. With a browser on virtually every desktop, companies can deploy a multi-tier architecture in which Web servers act as a middle tier, managing interactions with Web-based clients. The Web-based client architecture may have three or more layers. This multi-tier architecture provides many benefits over a traditional (two-tiered) client/server architecture. Development Tools and Methodologies Are Maturing Companies building and deploying applications on this model are faced with an application environment that is still maturing. A number of different technologies ranging from traditional CGI scripts to JSP technology - are available today to build the interactive, "customer-facing" component of these applications. The challenge is selecting an application architecture and component design that meets the evolving user needs (whether they be customers, partners, or internal staff) as well as the enterprise's own IT requirements. Users Have Heightened Requirements Internet users have heightened expectations for application availability and reliability. They want to be able to access applications at any time of day or night to perform a wide variety of tasks online. They expect up-to-date information and fast response times. To support these requirements, application providers need high-performance, highly reliable applications that can be updated easily. They need applications that can scale to support large numbers of users, and that can interact with vital business systems.

Solutions must meet demanding Enterprise Software Requirements
© Trendz Information Technologies Ltd. Page No. 60 of 220

J2EE The organizations that are building and maintaining these applications also have stringent requirements when selecting the architectures, products, and tools for creating Web-based applications.   The development platform must support fast application deployment and rapid updates. The application must be easy to maintain using minimal developer resources. Many organizations face a shortage of qualified Web developers and need to protect the developers they already have. Finally, the organization needs to retain the ability to adopt new tools or technologies as needed, so the development environment should not close out options. With new tools, systems, and information sources appearing nearly every day, there is a risk to selecting a solution that leaves the organization entirely at the mercy of a single vendor - even if that vendor is the market leader.

JSP Technology: The Next Evolution of Servlets JSP technology is a means for creating dynamic Web-based content using server-side (middle-tier) processing. JSP simplifies the process of creating these dynamic pages by separating the application logic from the page design and encapsulating logic in portable, reusable Java components. JSP technology has evolved from the powerful servlet technology. (Servlets are Java technology-based, server-side applications.) JSP extends the servlet technology in many ways, making it easier and faster to build, deploy, and maintain server-side applications that communicate with Web-based clients. The following sections describe where JSP technology fits in the Java family of products, how JSP can simplify the creation and maintenance of dynamic pages, and how these pages fit into more complex, multi-tier applications. JSP Extends Servlets In a sense, JSP technology does not provide new core technologies - everything that can be done with a JSP page, can also be done by writing a servlet. Servlets have access to the same set of Java APIs as JSP. Pages created with JSP technology are, in fact, compiled into Servlets, so they cannot be capable of anything inherently different. What JSP pages do, however, is enable a different, more efficient development methodology and simplify ongoing maintenance. This is because JSP technology truly separates the page design and static content from the logic used to generate the dynamic content. The Competitive Landscape JSP technology is not the first approach for enabling interactive Web pages -rather it is the next step in the progression of products supporting Web-based clients. Some of the earlier methods include CGI programs, the mod_perl plug-in for the Apache Web Server, and Microsoft Active Server Pages (ASP). The JSP technology surpasses these previous methods in two fundamental areas  Portability - Pages built with JSP technology are portable across platforms and servers, and work with portable, reusable components.  Easier Maintenance and Development - Because the page design is truly separate from the application logic, JSP enables tiered development and
© Trendz Information Technologies Ltd. Page No. 61 of 220

J2EE maintenance tasks, so page authors and developers can focus on specific areas of interest without requiring the others' help. Some of the differences are summarized in the table below. CGI/Perl Web server Mod_Perl ASP JSP

Any Web server, Microsoft IIS Any Web Apache Web including Apache, or Personal server Server Netscape, IIS Web Server today No No Perl No Yes No No VBScript, Jscript No Yes Yes Yes Java Yes Yes

Portable across No platforms/servers Reusable, modular code Scripting language Memory leak protection No C, Perl Yes

Supports concurrent access without separate No processes

The Java Server Pages (JSP) technology provides a simplified, fast way to create web pages that display dynamically generated content. JSP technology was designed to make it easier and faster to build web-based applications that work with a wide variety of web servers, application servers, browsers and development tools. The following lines provides an overview of the JSP technology, describing the background in which it was developed and the overall goals for the technology. It also describes the key components of a Java TM technology-based page, in the context of a simple example. Developing Web-based Applications: A Background. In its short history, the Worldwide Web has evolved from a network of basically static information displays to a mechanism for trading stocks and buying books. There seems to be almost no limit to the possible uses for web-based clients in diverse applications. Applications that can make use of browser-based clients have several advantages over traditional client/server based applications. These include nearly unlimited client access and greatly simplified application deployment and management. (To update an application, a developer only needs to change one server-based program, not thousands of client-installed applications.) As a result, the software industry is moving quickly toward building multi-tiered applications using browser-based clients. These increasingly sophisticated web-based applications require changes in development technology. Static HTML is fine for displaying relatively static content; the challenge has been creating interactive web-based applications, in which the content of the page is based on a user request or system status, not pre-defined text.

© Trendz Information Technologies Ltd.

Page No. 62 of 220

J2EE An early solution to this problem was the CGI-BIN interface; developers wrote individual programs to this interface, and web-based applications called the programs through the web server. This solution has significant scalability problems -each new CGI request launches a new process on the server. If multiple users access the program concurrently, these processes consume all of the web server's available resources and the performance slows to a grind. Individual web server vendors have tried to simplify web application development providing "plug-ins" and APIs for their servers. These solutions are web-server specific, and don't address the problem across multiple vendor solutions. For example, Microsoft's Active Server PagesTM (ASP) technology makes it easier to create dynamic content on a web page, but only works with Microsoft IIS or Personal Web Server. Other solutions exist, but they are not necessarily easy for the average page designer to deploy. Technologies such as Java Servlets, for example, make it easier to write server-based code using the Java programming language for interactive applications. A Java Servlet is a Java technology-based program that runs on the server (as opposed to an applet, which runs on the browser). Developers can write Servlets that take an HTTP request from the web browser, generate the response dynamically (possibly querying databases to fulfill the request) and then send a response containing an HTML or XML document to the browser. Using this approach, the entire page must be composed in the Java Servlet. If a developer or web master wanted to tune the appearance of the page, they would have to edit and recompile the Java Servlet, even if the logic were already working. With this approach, generating pages with dynamic content still requires application development expertise. What is needed, clearly, is an industry-wide solution for creating pages with dynamically generated content. This solution should address the limitations of current alternatives by:    Working on any web or application server Separating the application logic from the appearance of the page Allowing fast development and testing

Simplifying the process of developing interactive web-based applications The Java Server Pages (JSP) technology provides a simplified, fast way to create web pages that display dynamically generated content. JSP technology was designed to make it easier and faster to build web-based applications that work with a wide variety of web servers, application servers, browsers and development tools. The following lines provides an overview of the JSP technology, describing the background in which it was developed and the overall goals for the technology. It also describes the key components of a Java TM technology-based page, in the context of a simple example.

Developing Web-based Applications: A Background In its short history, the Worldwide Web has evolved from a network of basically static information displays to a mechanism for trading stocks and buying books. There
© Trendz Information Technologies Ltd. Page No. 63 of 220

J2EE seems to be almost no limit to the possible uses for web-based clients in diverse applications. Applications that can make use of browser-based clients have several advantages over traditional client/server based applications. These include nearly unlimited client access and greatly simplified application deployment and management. (To update an application, a developer only needs to change one server-based program, not thousands of client-installed applications.) As a result, the software industry is moving quickly toward building multi-tiered applications using browser-based clients. These increasingly sophisticated web-based applications require changes in development technology. Static HTML is fine for displaying relatively static content; the challenge has been creating interactive web-based applications, in which the content of the page is based on a user request or system status, not pre-defined text. An early solution to this problem was the CGI-BIN interface; developers wrote individual programs to this interface, and web-based applications called the programs through the web server. This solution has significant scalability problems -each new CGI request launches a new process on the server. If multiple users access the program concurrently, these processes consume all of the web server's available resources and the performance slows to a grind. Individual web server vendors have tried to simplify web application development providing "plug-ins" and APIs for their servers. These solutions are web-server specific, and don't address the problem across multiple vendor solutions. For example, Microsoft's Active Server PagesTM (ASP) technology makes it easier to create dynamic content on a web page, but only works with Microsoft IIS or Personal Web Server. Other solutions exist, but they are not necessarily easy for the average page designer to deploy. Technologies such as Java Servlets, for example, make it easier to write server-based code using the Java programming language for interactive applications. A Java Servlet is a Java technology-based program that runs on the server (as opposed to an applet, which runs on the browser). Developers can write Servlets that take an HTTP request from the web browser, generate the response dynamically (possibly querying databases to fulfill the request) and then send a response containing an HTML or XML document to the browser. Using this approach, the entire page must be composed in the Java Servlet. If a developer or web master wanted to tune the appearance of the page, they would have to edit and recompile the Java Servlet, even if the logic were already working. With this approach, generating pages with dynamic content still requires application development expertise. What is needed, clearly, is an industry-wide solution for creating pages with dynamically generated content. This solution should address the limitations of current alternatives by: Working on any web or application server Separating the application logic from the appearance of the page Allowing fast development and testing
Page No. 64 of 220

  

© Trendz Information Technologies Ltd.

J2EE  Simplifying the process of developing interactive web-based applications

The Java Server Pages (JSP) technology was designed to fit this need. The JSP specification is the result of extensive industry cooperation between vendors of web servers, application servers, transactional systems, and development tools. Sun Microsystems developed the specification to integrate with and leverage existing expertise and tools support for the Java programming environment, such as Java Servlets and JavaBeans. The result is a new approach to developing web-based applications that extends powerful capabilities to page designers using componentbased application logic. Java Server Pages Technology approach to Web Application Development In developing the JSP specification, Sun Microsystems worked with a number of leading web server, application server and development tool vendors, as well as a diverse and experienced development community. The result is an approach that balances portability with ease-of-use for application and page developers. JSP technology speeds the development of dynamic web pages in a number of ways:  Separating content generation from presentation Using JSP technology, web page developers use HTML or XML tags to design and format the results page. They use JSP tags or scriptlets to generate the dynamic content (the content that changes according to the request, such as requested account information or the price of a specific bottle of wine). The logic that generates the content is encapsulated in tags and JavaBeans components and tied together in scriptlets, all of which are executed on the server side. If the core logic is encapsulated in tags and beans, then other individuals, such as web masters and page designers, can edit the JSP page without affecting the generation of the content. On the server, a JSP engine interprets JSP tags and scriptlets, generates content (for example, by accessing JavaBeans components, accessing a database with JDBCTM technology, or including files), and sends the results back in the form of an HTML (or XML) page to the browser. This helps authors protect proprietary code while ensuring complete portability for any HTMLbased web browser. Emphasizing reusable components Most JSP pages rely on reusable, cross-platform components (JavaBeans or Enterprise JavaBeans components) to perform the more complex processing required of the application. Developers can share and exchange components that perform common operations, or make them available to larger user or customer communities. The component-based approach speeds overall development and lets organizations leverage their existing expertise and development efforts for optimal results. Simplifying page development with tags Web page developers are not always programmers familiar with scripting languages. The JavaServer Pages technology encapsulates much of the functionality required for dynamic content generation in easy-to-use, JSPspecific XML tags. Standard JSP tags can access and instantiate JavaBeans components, set or retrieve bean attributes, download applets, and perform other functions that are otherwise more difficult and time-consuming to code.

© Trendz Information Technologies Ltd.

Page No. 65 of 220

J2EE The JSP technology is extensible through the development of customized tag libraries. Over time, third-party developers and others will create their own tag libraries for common functions. This lets web page developers work with familiar tools and constructs, such as tags, to perform sophisticated functions. The JSP technology integrates easily into a variety of application architectures, leveraging existing tools and skills, and scaling to support enterprise-wide distributed applications. As part of the Java technology-enabled family, and an integral part of the Java 2, Enterprise Edition architecture, the JSP technology can support highly complex web-based applications.  Because the native scripting language for JSP pages is based on the Java programming language, and because all JSP pages are compiled into Java Servlets, JSP pages have all of the benefits of Java technology, including robust memory management and security. As part of the Java platform, JSP shares the Write Once, Run Anywhere TM characteristics of the Java programming language. As more vendors add JSP support to their products, you can use servers and tools of your choice, changing tools or servers without affecting current applications. When integrated with the Java 2 Platform, Enterprise Edition (J2EE) and Enterprise JavaBeans technology, JSP pages will provide enterprise-class scalability and performance necessary for deploying web-based applications across the virtual enterprise.

What Does a JSP Page Look Like? A JSP page looks like a standard HTML or XML page, with additional elements that the JSP engine processes and strips out. Typically, the JSP elements create text that is inserted into the results page. The JSP technology is best described using an example. The following JSP page is very simple; it prints the day of the month and the year, and welcomes you with either "Good Morning" or "Good Afternoon," depending on the time of day. The page combines ordinary HTML with a number of JSP elements:    Calls to a clock JavaBean component An inclusion of an external file (for copyright information) JSP expressions and scriptlets

<HTML> <%@ page language=="java" imports=="com.wombat.JSP.*" %> <H1>Welcome</H1> <P>Today is </P> <jsp:useBean id=="clock" class=="calendar.jspCalendar" /> <UL> <LI>Day: <%==clock.getDayOfMonth() %> <LI>Year: <%==clock.getYear() %> </UL> <% if (Calendar.getInstance().get(Calendar.AM_PM) ==== Calendar.AM) { %> Good Morning
© Trendz Information Technologies Ltd. Page No. 66 of 220

J2EE <% } else { %> Good Afternoon <% } %> <%@ include file=="copyright.html" %> </HTML> The page includes the following components:  A JSP directive passes information to the JSP engine. In this case, the first line indicates the location of some Java programming language extensions to be accessible from this page. Directives are enclosed in <%@ and %> markers. Fixed template data: Any tags that the JSP engine does not recognize it passes on with the results page. Typically, these will be HTML or XML tags. This includes the Unordered List and H1 tags in the example above. JSP actions, or tags: These are typically implemented as standard tags or customized tags, and have an XML tag syntax. In the example, the jsp:useBean tag instantiates the Clock JavaBean on the server. An expression: The JSP engine evaluates anything between <%== and %> markers. In the List Items above, the values of the Day and Year attributes of the Clock bean are returned as a string and inserted as output in the JSP file. In the example above, the first list item will be the day of the year, and the second item the year. A scriptlet is a small script that performs functions not supported by tags or ties everything together. The native scripting language for JSP 1.0 software is based on the Java programming language. The scriptlet in the above sample determines whether it is AM or PM and greets the user accordingly (for daytime users, at any rate).

The example may be trivial, but the technology is not. Businesses can encapsulate critical processing in server-side Beans, and web developers can easily access that information, using familiar syntax and tools. Java-based scriptlets provide a flexible way to perform other functions, without requiring extensive scripting. JSP Directives JSP pages use JSP directives to pass instructions to the JSP engine. These may include the following:   JSP page directives communicate page-specific information, such as buffer and thread information or error handling. The include directive (shown in the example above) can be used to include an external document in the page. A good example is a copyright file or company information, file -- it is easier to maintain this file in one central location and include it in several pages than to update it in each JSP page. However, the included file can also be another JSP file. A taglib directive indicates a library of custom tags that the page can invoke.

Scripting Elements JSP pages can includes include small scripts, called scriptlets, in a page. A scriplet is a code fragment, executed at request time processing. Scriptlets may be combined with static elements on the page (as in the example above) to create a dynamically generated page.

© Trendz Information Technologies Ltd.

Page No. 67 of 220

J2EE Scripts are delineated within <% and %> markers. The scripting language engine, in our example the Java virtual machine on the host, will evaluate anything within those markers. The JSP specification supports all of the usual script elements, including expressions and declarations. Application Models for JSP Pages A JSP page is executed by a JSP engine, which is installed in a web server or a JSPenabled application server. The JSP engine receives requests from a client to a JSP page, and generates responses from the JSP page to the client. JSP pages are typically compiled into Java Servlets. Java Servlets are a standard Java extension. The page developer has access to the complete Java application environment, with all of the scalability and portability of the Java technology-enabled family. When a JSP page is first called, if it does not yet exist, it is compiled into a Java Servlet class and stored in the server memory. This enables very fast responses for subsequent calls to that page. (This avoids the CGI-bin problem of spawning new processes for each HTTP request, or the runtime parsing required by server-side includes.) JSP pages may be included in a number of different application architectures or models. JSP pages may be used in combination with different protocols, components and formats. The following sections describe a few of the possibilities. An Application In a simple implementation, the browser directly invokes a JSP page, which itself generates the requested content (perhaps invoking JDBC to get information directly from a database). The JSP page can call JDBC components to generate results, and creates standard HTML that it sends back to the browser as a result.

This model basically replaces the CGI-BIN concept with a JSP page (compiled as a Java Servlet). This method has the following advantages:   It is simple and fast to program The page author can easily generate dynamic content based on the request and state of the resources.

This architecture works well for many applications, but it does not scale for a large number of simultaneous Web-based clients accessing scarce enterprise resources, since each must establish or share a connection to the content resource in question. For example, if the JSP page accesses a database, it may generate many connections to the database, which can affect the database performance. A flexible application with Java Servlets In another possible configuration, the Web-based client may make a request directly to a Java Servlet, which actually generates the dynamic content, wraps the results
© Trendz Information Technologies Ltd. Page No. 68 of 220

J2EE into a result bean and invokes the JSP page. The JSP page accesses the dynamic content from the bean and sends the results (as HTML) to the browser. This approach creates more reusable components that can be shared between applications, and may be implemented as part of a larger application. It still has scalability issues in terms of handling connections to enterprise resources, such as databases. JSP Tags Most JSP processing will be implemented through JSP-specific XML-based tags. JSP 1.0 includes a number of standard tags, referred to as the core tags. These include: • • • • • jsp:useBean This tag declares the usage of an instance of a JavaBeans component. If the Bean does not already exist, then the JavaBean component instantiates and registers the tag. jsp:setProperty This sets the value of a property in a Bean. jsp:getProperty This tag gets the value of a Bean instance property, converts it to a string, and puts It in the implicit object "out". jsp:include jsp:forward

The advantage of tags is that they are easy to use and share between applications. The real power of a tag-based syntax comes with the development of custom tag libraries, in which tool vendors or others can create and distribute tags for specific purposes. This set of lines describes the standard actions of JavaServer Pages.Standard actions are represented using XML elements with a prefix of jsp (though that prefix can be redefined in the XML syntax). A translation error will result if the JSP prefix is used for an element that is not a standard action. <jsp:useBean> A jsp:useBean action associates an instance of a Java programming language object defined within a given scope and available with a given id with a newly declared scripting variable of the same id.When a <jsp:useBean> action is used in an scriptless page, or in an scriptless context (as in the body of an action so indicated), there are no Java scripting variables created but instead a variable is created. The jsp:useBean action is quite flexible; its exact semantics depends on the attributes given. The basic semantic tries to find an existing object using id and scope. If the object is not found it will attempt to create the object using the other attributes. It is also possible to use this action to give a local name to an object defined elsewhere, as in another JSP page or in a servlet. This can be done by using the type attribute and not providing class or beanName attributes. At least one of type and class must be present, and it is not valid to provide both class and beanName. If type and class are present, class must be assignable to type (in the Java platform sense). For it not to be assignable is a translation time error.

© Trendz Information Technologies Ltd.

Page No. 69 of 220

J2EE The attribute beanName specifies the name of a Bean, as specified in the JavaBeans specification. It is used as an argument to the instantiate method in the java.beans.Beans class. It must be of the form a.b.c, which may be either a class, or the name of a resource of the form a/b/c.ser that will be resolved in the current ClassLoader. If this is not true, a request-time exception, as indicated in the semantics of the instantiate method will be raised. The value of this attribute can be a request-time attribute expression. The id Attribute The id=”name” attribute/value tuple in a jsp:useBean action has special meaning to a JSP container, at page translation time and at client request processing time. In particular:

 The name must be unique within the translation unit, and identifies the
particular element in which it appears to the JSP container and page. Duplicate id’s found in the same translation unit shall result in a fatal translation error. The JSP container will associate an object (a JavaBean component) with the named value and accessed via that name in various contexts through the pagecontext object described later in this specification. The name is also used to expose a variable (name) in the page’s scripting language environment. The scope of the scripting language variable is dependent upon the scoping rules and capabilities of the scripting language used in the page.

Note that this implies the name value syntax must comply with the variable naming syntax rules of the scripting language used in the page. Provides details for the case where the language attribute is java. An example of the scope rules just mentioned is shown next: <jsp:useBean> <% { // introduce a new block %> ... <jsp:useBean id=”customer” class=”mycom.Customer” /> <% /* * the tag above creates or obtains the Customer Bean * reference, associates it with the name “customer” in the * PageContext, and declares a Java programming language * variable of the same name initialized to the object reference * in this block’s scope. */ %> ... <%= customer.getName(); %> ... <% } // close the block %> <% // the variable customer is out of scope now but // the object is still valid (and accessible via pageContext) %> The scope Attribute
© Trendz Information Technologies Ltd. Page No. 70 of 220

J2EE The scope=”page|request|session|application” attribute/value tuple is associated with, and modifies the behavior of the id attribute described above (it has both translation time and client request processing time semantics). In particular it describes the namespace, the implicit lifecycle of the object reference associated with the name, and the APIs used to access this association. For all scopes, it is illegal to change the instance object so associated, such that its new runtime type is a subset of the type(s) of the object previously so associated. The actions performed in a jsp:useBean action are:

 If the object is found, the variable’s value is initialized with a reference to the

  

located object, cast to the specified type. If the cast fails, a java.lang.ClassCastException shall occur. This completes the processing of this jsp:useBean action. If the jsp:useBean action had a non-empty body it is ignored. This completes the processing of this jsp:useBean action. If the object is not found in the specified scope and neither class nor beanName are given, a java.lang.InstantiationException shall occur. This completes the processing of this jsp:useBean action. If the object is not found in the specified scope, and the class specified names a non-abstract class that defines a public no-args constructor, then the class is instantiated. The new object reference is associated with the scripting variable and with the specified name in the specified scope using the appropriate scope dependent association mechanism (sees PageContext). After this, step 8 is performed. If the object is not found, and the class is abstract, an interface, or no public no-args constructor is defined therein, then a java.lang.InstantiationException shall occur. This completes the processing of this jsp:useBean action. If the object is not found in the specified scope; and beanName is given, then the method instantiate of java.beans.Beans will be invoked with the ClassLoader of the servlet object and the beanName as arguments. If the method succeeds, the new object reference is associated the with the scripting variable and with the specified name in the specified scope using the appropriate scope dependent association mechanism (see PageContext). After this, step 8 is performed. If the jsp:useBean action has a non-empty body, the body is processed. The variable is initialized and available within the scope of the body. The text of the body is treated as elsewhere. Any template text will be passed through to the out stream. Scriptlets and action tags will be evaluated. A common use of a non-empty body is to complete initializing the created instance. In that case the body will likely contain jsp:setProperty actions and scriptlets that are evaluated. This completes the processing of this useBean action.

Examples In the following example, a Bean with name connection of type mycom.myapp.Connection is available after actions on this element, either because it was already created and found, or because it is newly created. <jsp:useBean id=”connection” class=”mycom.myapp.Connection” /> In the next example, the timeout property is set to 33 if the Bean was instantiated. <jsp:useBean id=”connection” class=”mycom.myapp.Connection”>
© Trendz Information Technologies Ltd. Page No. 71 of 220

J2EE <jsp:setProperty name=”connection” property=”timeout” value=”33”> </jsp:useBean> In the final example, the object should have been present in the session. If so, it is given the local name wombat with WombatType. A ClassCastException may be raised if the object is of the wrong class, and an InstantiationException may be raised if the object is not defined. <jsp:useBean id=”wombat” type=”my.WombatType” scope=”session”/> Syntax This action may or not have a body. If the action has no body, it is of the form: <jsp:useBean id="name" scope="page|request|session|application" typeSpec /> typeSpec ::= class=”className” | class=”className” type=”typeName” | type=”typeName” class=”className” | beanName=”beanName” type=”typeName” | type=”typeName” beanName=”beanName” | type=”typeName” If the action has a body, it is of the form: <jsp:useBean id="name" scope="page|request|session|application" typeSpec > body </jsp:useBean> In this case, the body will be invoked if the Bean denoted by the action is created. Typically, the body will contain either scriptlets or jsp:setProperty tags that will be used to modify the newly created object, but the contents of the body are not restricted. <jsp:setProperty> The jsp:setProperty action sets the values of properties in a bean. The name attribute that denotes the bean must be defined before this action appears. There are two variants of the jsp:setProperty action. Both variants set the values of one or more properties in the bean based on the type of the properties. The usual bean introspection is done to discover what properties are present, and, for each, its name, whether it is simple or indexed, its type, and the setter and getter methods. Introspection also indicates if a given property type has a PropertyEditor class. Properties in a Bean can be set from one or more parameters in the request object, from a String constant, or from a computed request-time expression. Simple and indexed properties can be set using jsp:setProperty. When assigning values to indexed properties the value must be an array; the rules described in the previous paragraph apply to the actions. A conversion failure leads to an error, whether at translation time or request time. Examples The following two actions set a value from the request parameter values. <jsp:setProperty name=”request” property=”*” /> <jsp:setProperty name=”user” property=”user” param=”username” />

© Trendz Information Technologies Ltd.

Page No. 72 of 220

J2EE The following two element set a property from a value <jsp:setProperty name=”results” property=”col” value=”${i mod 4}”/> <jsp:setProperty name=”results” property=”row” value=”<%= i/4 %>” /> <jsp:getProperty> The <jsp:getProperty> action places the value of a bean instance property, converted to a String, into the implicit out object, from which the value can be displayed as output. The bean instance must be defined as indicated in the name attribute before this point in the page (usually via a jsp:useBean action). The conversion to String is done as in the println methods, i.e. the toString method of the object is used for Object instances, and the primitive types are converted directly. If the object is not found, a request-time exception is raised. jsp:setProperty Attributes Name - The name of a bean instance defined by a <jsp:useBean> action or some other action. The bean instance must contain the property to be set. The defining action must appear before the <jsp:setProperty> action in the same file. Property - The name of the property whose value will be set. If property Name is set to * then the tag will iterate over the current ServletRequest parameters, matching parameter names and value type(s) to property names and setter method type(s), setting each matched property to the value of the matching parameter. If a parameter has a value of "", the corresponding property is not modified. Param - The name of the request parameter whose value is given to a bean property. The name of the request parameter usually comes from a web form. If param is omitted, the request parameter name is assumed to be the same as the bean property name. If the param is not set in the Request object, or if it has the value of ““, the jsp:setProperty action has no effect.. An action may not have both param and value attributes. value The value to assign to the given property. This attribute can accept a request-time attribute expression as a value.An action may not have both param and value attributes. The value of the name attribute in jsp:setProperty and jsp:getProperty will refer to an object that is obtained from the pageContext object through its findAttribute method. The object named by the name must have been “introduced” to the JSP processor using either the jsp:useBean action or a custom action with an associated VariableInfo entry for this name. If the object was not introduced in this manner, the container implementation is recommended (but not required) to raise a translation error. Note – A consequence of the previous paragraph is that objects that are stored in, say, the session by a front component are not automatically visible to jsp:setProperty and jsp:getProperty actions in that page unless a jsp:useBean action, or some other action, makes them visible. If the JSP processor can ascertain that there is an alternate way guaranteed to access the same object, it can use that information. For example it may use a scripting variable, but it must guarantee that no intervening code has invalidated the copy held by the scripting variable. The truth is always the value held by the pageContext object.
© Trendz Information Technologies Ltd. Page No. 73 of 220

J2EE

Examples <jsp:getProperty name=”user” property=”name” /> <jsp:include> A <jsp:include .../> action provides for the inclusion of static and dynamic resources in the same context as the current page. Inclusion is into the current value of out. The resource is specified using a relativeURLspec that is interpreted in the context of the web application (i.e. it is mapped). The page attribute of both the jsp:include and the jsp:forward actions are interpreted relative to the current JSP page, while the file attribute in an include directive is interpreted relative to the current JSP file. See below for some examples of combinations of this. An included page cannot change the response status code or set headers. This precludes invoking methods like setCookie. Attempts to invoke these methods will be ignored. The constraint is equivalent to the one imposed on the include method of the RequestDispatcher class. A jsp:include action may have jsp:param subelements that can provide values for some parameters in the request to be used for the inclusion. Request processing resumes in the calling JSP page, once the inclusion is completed. The flush attribute controls flushing. If true, then, if the page output is buffered and the flush attribute is given a true value, then the buffer is flushed prior to the inclusion, otherwise the buffer is not flushed. The default value for the flush attribute is false. Examples <jsp:include page=”/templates/copyright.html”/> The above example is a simple inclusion of an object. The path is interpreted in the context of the Web Application. It is likely a static object, but it could be mapped into, for instance, a servlet via web.xml. For an example of a more complex set of inclusions, consider the following four situations built using four JSP files: A.jsp, C.jsp, dir/B.jsp and dir/C.jsp:

 A.jsp says <%@ include file=”dir/B.jsp”%> and dir/B.jsp says <%@ include   

file=”C.jsp”%>. In this case the relative specification C.jsp resolves to dir/C.jsp. A.jsp says <jsp:include page=”dir/B.jsp”/> and dir/B.jsp says <jsp:include page=”C.jsp” />. In this case the relative specification C.jsp resolves to dir/ C.jsp. A.jsp says <jsp:include page=”dir/B.jsp”/> and dir/B.jsp says <%@ include file=”C.jsp” %>. In this case the relative specification C.jsp resolves to dir/C.jsp. A.jsp says <%@ include file=”dir/B.jsp”%> and dir/B.jsp says <jsp:include page=”C.jsp”/>. In this case the relative specification C.jsp resolves to C.jsp.

<jsp:forward>
© Trendz Information Technologies Ltd. Page No. 74 of 220

J2EE

A <jsp:forward page=”urlSpec” /> action allows the runtime dispatch of the current request to a static resource, a JSP page or a Java servlet class in the same page The URL is a relative urlSpec as in Section. Relative paths are interpreted relative to the current JSP page. Accepts a requesttime attribute value (which must evaluate to a String that is a relative URL specification). flush Optional boolean attribute. If the value is true, the buffer is flushed now. The default value is false. <jsp:forward> A jsp:forward effectively terminates the execution of the current page. The relative urlSpec. The request object will be adjusted according to the value of the page attribute. A jsp:forward action may have jsp:param subelements that can provide values for some parameters in the request to be used for the forwarding. If the page output is buffered, the buffer is cleared prior to forwarding. If the page output is buffered and the buffer was flushed, an attempt to forward the request will result in an IllegalStateException. If the page output was unbuffered and anything has been written to it, an attempt to forward the request will result in an IllegalStateException. Examples The following action might be used to forward to a static page based on some dynamic condition. <% String whereTo = “/Trendz/”+someValue; %> <jsp:forward page=’<%= whereTo %>’ /> Syntax <jsp:forward page=”relativeURLspec” /> and <jsp:forward page=”urlSpec”> { <jsp:param .... /> }* </jsp:forward> <jsp:param> The jsp:param element is used to provide key/value information. This element is used in the jsp:include, jsp:forward, and jsp:params elements. A translation error shall occur if the element is used elsewhere. When doing jsp:include or jsp:forward, the included page or forwarded page will see the original request object, with the original parameters augmented with the new parameters, with new values taking precedence over existing values when applicable. The scope of the new parameters is the jsp:include or jsp:forward call; i.e. in the case of an jsp:include the new parameters (and values) will not apply after the include. This is the same behavior as in the ServletRequest include and forward methods. Syntax
© Trendz Information Technologies Ltd. Page No. 75 of 220

J2EE <jsp:param name="name" value="value" /> This action has two mandatory attributes: name and value. name indicates the name of the parameter, and value, which may be a request-time expression, indicates its value. <jsp:plugin> The plugin action enables a JSP page author to generate HTML that contains the appropriate client browser dependent constructs (OBJECT or EMBED) that will result in the download of the Java Plugin software (if required) and subsequent execution of the Applet or JavaBeans component specified therein. The <jsp:plugin> tag is replaced by either an <object> or <embed> tag, as appropriate for the requesting user agent, and emitted into the output stream of the <jsp:plugin> response. The attributes of the <jsp:plugin> tag provide configuration data for the presentation of the element, as indicated in the table below. Examples <jsp:plugin type=”applet” code=”MyApplet.class” codebase=”/html” > <jsp:params> <jsp:param name=”Trendz” value=”People Committed to Quality”/> </jsp:params> </jsp:plugin> CUSTOM TAG LIBRARY What is a Tag Library? In JavaServer Pages technology, actions are elements that can create and access programming language objects and affect the output stream. The JSP specification defines 6 standard actions that must be provided by any compliant JSP implementation. In addition to the standard actions, JSP v1.1 technology supports the development of reusable modules called custom actions. A custom action is invoked by using a custom tag in a JSP page. A tag library is a collection of custom tags. Some examples of tasks that can be performed by custom actions include form processing, accessing databases and other enterprise services such as email and directories, and flow control. Before the availability of custom actions, JavaBeans components in conjunction with scriplets were the main mechanism for performing such processing. The disadvantage of using this approach is that it makes JSP pages more complex and difficult to maintain. Custom actions alleviate this problem by bringing the benefits of another level of componentization to JSP pages. Custom actions encapsulate recurring tasks so that they can be reused across more than one application and increase productivity by encouraging division of labor between library developers and library users. JSP tag libraries are created by developers who are proficient at the Java programming language and expert in accessing data and other services. JSP tag libraries are used by Web application designers who can focus on presentation issues rather than being concerned with how to access databases and other enterprise services. Some features of custom tags are:
© Trendz Information Technologies Ltd. Page No. 76 of 220

J2EE

• • • • •

They can be customized via attributes passed from the calling page. They have access to all the objects available to JSP pages. They can modify the response generated by the calling page. They can communicate with each other. You can create and initialize a JavaBeans component, create a variable that refers to that bean in one tag, and then use the bean in another tag. They can be nested within one another, allowing for complex interactions within a JSP page.

Declaring Tag Libraries You declare that a JSP page will use tags defined in a tag library by including a taglib directive in the page before any custom tag is used: <%@ taglib uri="/tlt" prefix="tlt" %> The uri attribute refers to a URI that uniquely identifies the tag library. This URI can be relative or absolute. If it is relative it must be mapped to an absolute location in the taglib element of a Web application deployment descriptor, the configuration file associated with Web applications developed according to the Java Servlet and JavaServer Pages specifications. The prefix attribute defines the prefix that distinguishes tags provided by a given tag library from those provided by other tag libraries. JSP custom actions are expressed using XML syntax. They have a start tag and end tag, and possibly a body: <tlt:tag> body </tlt:tag> A tag with no body can be expressed as follows: <tlt:tag /> Simple Tags The following simple tag invokes an action that creates a greeting: <tlt:greeting /> Tags With Attributes The start tag of a custom action can contain attributes in the form attr="value". Attributes serve to customize the behavior of a tag just as parameters are used to affect the outcome of executing a method on an object. Tag attributes can be set from one or more parameters in the request object or from a String constant. The only types of attributes that can be set from request parameter values and String constants are those listed in Table 1; the conversion applied is that shown in the table. When assigning values to indexed attributes the value must be an array; the rules just described apply to the elements. Table 1 Valid Tag Attribute Assignments Property Type byte or Byte Conversion on String Value As indicated in java.lang.Byte.valueOf(String)
Page No. 77 of 220

boolean or Boolean As indicated in java.lang.Boolean.valueOf(String)

© Trendz Information Technologies Ltd.

J2EE char or Character double or Double int or Integer float or Float long or Long As indicated in java.lang.Character.valueOf(String) As indicated in java.lang.Double.valueOf(String) As indicated in java.lang.Integer.valueOf(String) As indicated in java.lang.Float.valueOf(String) As indicated in java.lang.Long.valueOf(String)

An attribute value of the form <%= scriptlet_expression %> is computed at request time. The value of the expression depends on the type of the attribute's value, which is specified in the object that implements the tag (called a tag handler). Requesttime expressions can be assigned to attributes of any type; no automatic conversions will be performed. The following tag has an attribute named date, which accepts a String value obtained by evaluating the variable today: <tlt:greeting date="<%= today %>" /> The Future for JSP Technology JSP technology is designed to be an open, extensible standard for building dynamic web pages. Developers will use JSP pages to create portable web applications that can run with different web and application servers for different markets, using whatever authoring tools fit their market and their needs. By working with a consortium of industry leaders, Sun has ensured that the JSP specification is open and portable. You should be able to author JSP pages anywhere and deploy them anywhere, using any client and server platforms. Over time, tool vendors and others will extend the functionality of the platform by providing customized tag libraries for specialized functions.

© Trendz Information Technologies Ltd.

Page No. 78 of 220

J2EE

 JNDI • Naming & Directory Service • Installing OpenLDAP • Accessing Naming Service • Accessing Directory Service  Java Transaction API • Transaction Service • Bean managed Transaction  Java Mail API • Java Mail & JAF • Sample Application  EJB • Overview • Remote & Home Interfaces • Entity Beans with CMP and BMP • Session Bean as Stateless and Stateful • EJB 2.0 Features • EJB QL • Message-Driven Bean • EJB & WebService  J2EE Design Pattern • Model-view-Controller • What is Design Pattern • Helpful Hints
Page No. 79 of 220

© Trendz Information Technologies Ltd.

J2EE JAVA 2 EDITIONS Basically Java2 Editions like  J2SE (Java 2 Standard Edition) Java 2 Platform, Standard Edition (J2SE) provides a complete environment for applications development on desktops and servers. It also serves as the foundation for the Java 2 Platform, Enterprise Edition (J2EE) and Java Web Services. J2EE (Java 2 Enterprise Edition) Java 2 Platform, Enterprise Edition (J2EE) defines the standard for developing component-based multi-tier enterprise applications. Features include Web services support and development tools. J2ME (Java 2 Micro Edition) The Micro Edition of the Java 2 Platform provides an application environment that specifically addresses the needs of commodities in the vast and rapidly growing consumer and embedded space, including mobile phones, pagers, personal digital assistants, set-top boxes, and vehicle telematics systems.

J2EE Architecture   The J2EE platform uses a multi-tiered distributed application model for both enterprise applications Application logic is divided into “components” according to function, and the various application components that make up a J2EE application are installed on different machines depending on the tier in the multi-tiered J2EE environment to which the application component belongs J2EE multi-tiered applications are generally considered to be three-tiered applications because they are distributed over three different locations Client machines The J2EE server machine The database or legacy machines at the back end Three-tiered applications that run in this way extend the standard two-tiered client and server model by placing a multithreaded application server between the client application and back-end storage J2EE Containers

    

 The Application Server maintains control and provides services through an


     

interface or framework known as a container There are five defined container types in the J2EE specification Three of these are server-side containers: The server itself, which provides the J2EE runtime environment and the other two containers An EJB container to manage EJB components A Web container to manage Servlets and JSP pages The other two container types are client-side: An application container for Stand-alone GUIs, Console An applet container, meaning a browser, usually with the Java Plug-in

© Trendz Information Technologies Ltd.

Page No. 80 of 220

J2EE

J2EE ARCHITECTURE

JAVA NAMING & DIRECTORY INTERFACE Lightweight Directory Access Protocol (LDAP) is increasingly popular because it simplifies what has been complex, namely, accessing directory services. In this article you will learn what you can do with LDAP and how Java handles LDAP with its Java Naming and Directory Interface (JNDI) API. At the end of the article, you will find a project that provides a white pages service built with LDAP and JNDI. Naming and Directory Services Before you start the project, you should first familiarize yourself the jargon of naming and directory services. The Naming Service A Naming Service lets you find an object in a system based on the name associated with the object. Naming Services are easy to find. Take the file system in your computer, for instance. Every file in a computer has a name; to access a file you must know its name. In file systems, files are objects associated with filenames. Another example is the Internet's DNS, which maps easy-to-remember names (such as onjava.com and jUpload.com) to IP addresses. When you work with Enterprise JavaBeans (EJB), you use a naming service to get a reference to a Bean. In short, a naming service allows you to look up an object by its name.

© Trendz Information Technologies Ltd.

Page No. 81 of 220

J2EE Each naming service has its own rules for making valid names. For example, the rules for valid filenames Linux are different from the rules in Windows. The association of a name with an object is called a binding. In a file system, a filename is bound to a file. In a DNS server, domain names are bound to IP addresses. Objects in some naming services cannot be stored directly inside the naming service. Instead, the name service stores pointers or references to objects. A reference contains an address, that is, specific information on how to access the object itself. A Context In a naming service, obviously you have more than one name-to-object binding. The set of bindings is called a context. There are two types of contexts: root and subcontext. A root context is the base name of an object. In a file system, the root context is the base from which all other directories and files are stored. In the Unix file system, the root context is /. Under Windows it is normally C:\. A subcontext is a name that adds another level to the root context. For example, a directory, such as ‘usr’ under / in a Unix file system, is a subcontext. In the Unix system, this subcontext is called a subdirectory. That is, in a directory, /usr, the directory usr is a subcontext of /. In another example, a DNS domain, like COM or NET, is a context. A DNS domain named relative to another DNS domain is a subcontext. For example, in the DNS domain brainysoftware.com, the DNS domain brainysoftware is a subcontext of COM. The Directory Service A Directory Service is an extension of a Naming Service. In a Directory Service, an object is also associated with a name. However, each object is allowed to have attributes. You can look up an object by its name; but you can also obtain the object's attributes or search for the object based on its attributes. Going back to the Unix file system, it's not just a naming service but also a directory service. Each file can have attributes like owner and date. In real world applications, a directory object in a directory server can be used to represent anything: a printer, a computer, a network, or even a person in an organization. Attributes An attribute of a directory object is a property of the object. For example, a person can have the following attributes: Last name, First name, User name, email address, Telephone number, and so on. A printer can have attributes like Resolution, Color, and Speed. An attribute has an identifier, which is a unique name in that object. Each attribute can have one or more values. For instance, a person object can have an attribute called LastName. The LastName is the identifier of an attribute. An attribute value is the content of the attribute. For example, the LastName attribute can have a value like "Martin". Searches and Search Filters You can look up a directory object by supplying its name to a directory service. Alternatively, many directory services support searches for objects based on properties, not just names. You can supply a query consisting of a logical expression
© Trendz Information Technologies Ltd. Page No. 82 of 220

J2EE in which you specify the attributes that the object or objects must have. The query is called a search filter. This style of searching is sometimes called reverse lookup or content-based searching. The directory service searches for and returns the objects that satisfy the search filter. LDAP Directory services are very common these days. There already exist a plethora of directory service implementations: • • • • Novell Directory Service (NDS) Network Information Services (NIS/NIS+) Windows NT Domain Naming Service (DNS) Active Directory Services (ADS)

Accessing a directory service and manipulating its objects used to be complex and difficult. The traditional protocol is X.500, a set of directory recommendations specified by the International Telecommunication Union. X.500 was enormous and complex. LDAP is a direct descendant of X.500. LDAP was designed at the University of Michigan to simplify access to X.500 directories (hence the "L" for "lightweight" in "LDAP"). LDAP was designed to be powerful enough to solve basic problems in accessing a directory service but simple and light enough so more people can afford to use it. LDAP, currently at version 3, is now a standard for directory information access. Many companies, including Microsoft, IBM, Novell, Computer Associates, and Sun, have agreed to support it. LDAP is now being used as an important part of a variety of services: authentication systems, mail systems, and e-commerce applications. To date more than 60 LDAP server implementations have been released; approximately 90% of which are standalone LDAP directory servers, 10% of which are components of other applications. You probably already have an LDAP-aware client installed on your computer. Many email clients can access an LDAP directory for email addresses, including Outlook, Eudora, Netscape Communicator, QuickMail Pro, and Mulberry. The LDAP naming convention orders components from right to left, delimited by a comma. LDAP arranges all directory objects in a tree, called a Directory Information Tree (DIT). Within the DIT, an organization object, for example, might contain group objects that might in turn contain person objects. When directory objects are arranged in this way, they play the role of naming contexts in addition to being attribute containers. Standard LDAP Operations In addition to client connections and disconnections, an LDAP server must provide the following: • • • The ability to bind to the LDAP server; The ability to add, modify and delete an entry; and The ability to search the server for these entries.

© Trendz Information Technologies Ltd.

Page No. 83 of 220

J2EE Note that the term binding in LDAP is different from its generic directory services meaning. Binding here refers to the authentication that a user is required to perform before accessing an entry in the directory. Public LDAP Servers There are several public LDAP servers you can use over the Internet; the popular of these is probably BigFoot's (ldap://ldap.bigfoot.com); others include ldap://ldap.four11.com and ldap://ldap.InfoSpace.com. A number of universities in the US also provides LDAP service to search for students or staff members. For a list of university public LDAP services, see eMailman's Public LDAP Servers. Choosing an LDAP Server Your organization may already run a directory service, especially if it is very large. If not so, you probably need to do some research before deciding on one. The most popular LDAP server today is iPlanet's Directory Server. Others include Novell's NDS eDirectory, Critical Path's Global Directory Server, Computer Associates' eTrust Directory, Siemens' DirX, and Oracle's Oracle Internet Directory. Deciding the one, which is best for your situation is often tricky. NetworkWorld Fusion published a good article last year, which compares the performance of many LDAP servers. If it's to be believed, iPlanet is the best performer and also the fastest; it concludes that iPlanet's Directory Server is the best choice for commercial use. If you only need an LDAP server for testing, you probably want to use something else. Downloads for the latest version of iPlanet's Directory Server (version 5.0 beta) range from 53 MB to 78 MB, depending on your operating system. For the project in this article, I chose the much slimmer LDAP server from OpenLDAP. Even though not the fastest, their free product is only a 1.52 MB download. OpenLDAP's products are only available for Linux; but once you have seeded it with entries, you can use this article's project code to access any LDAP server on any operating system. Installing OpenLDAP You can download OpenLDAP from the project's site. The LDAP server is called slapd (a stand-alone LDAP server). The latest version of slapd is 2.0.7. Other programs downloadable from the Web site are the replication server, some libraries, and a variety of tools. To install slapd, you first need to download openldap-2_0_7.tgz into the /usr/local/ directory of a Linux system. You can use another directory but you'll need to do some adjustment to the following instructions. Installation takes the following steps: 1. Extract the files -gunzip -c openldap-2_0_7.tgz | tar xvfB -- into a subdirectory, openldap-2.0.7. If you are using a different version, this subdirectory is called openldap-VERSION. 2. Assuming that your current working directory is /usr/local, run cd openldap-2.0.7
© Trendz Information Technologies Ltd. Page No. 84 of 220

J2EE 3. Next, run ./configure 4. Then the following commands: 5. make depend 6. make make test 7. If everything goes smoothly, you are now ready to install, for which you'll need root access. Run su root -c 'make install' Configuring slapd If installation is as expected, you are now ready to configure slapd. The configuration file is called slapd.conf and can be found at the /usr/local/etc/openldap/ directory. Open this file with your favorite text editor. You should see the following lines. database ldbm suffix "dc=<MY-DOMAIN>,dc=<COM>" rootdn "cn=Manager,dc=<MY-DOMAIN>,dc=<COM>" rootpw secret directory /usr/local/var/openldap-ldbm You need to edit the <MY-DOMAIN> and the <COM> parts to reflect your domain name. Using the correct names ensures that your LDAP server can be accessed from the Internet. For example, for the brainysoftware.com domain, the configuration lines will look like database ldbm suffix "dc=brainysoftware,dc=com" rootdn "cn=Manager,dc=brainysoftware,dc=com" rootpw secret directory /usr/local/var/openldap-ldbm If your domain contains additional components -- like sandal.jepit.edu.au -- do something like database ldbm suffix "dc=sandal,dc=jepit,dc=edu,dc=au" rootdn "cn=Manager,dc=sandal,dc=jepit,dc=edu,dc=au" rootpw secret directory /usr/local/var/openldap-ldbm The fourth line (rootpw secret) contains the root password that you need to supply to the server to make changes to the entries and do some other functions. Running slapd Running slapd requires root access, so run su root -c /usr/local/libexec/slapd or /usr/local/libexec/slapd if you're already logged in as root.

© Trendz Information Technologies Ltd.

Page No. 85 of 220

J2EE To check that the server is running and configured correctly, you can search it with ldapsearch. By default, ldapsearch is installed as /usr/local/bin/ldapsearch. Use the following command: ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts The Schema file An important file in an LDAP server is the schema file, which, for slapd, is called core.schema, located at /usr/local/openldap-2.0.7/etc/openldap/schema/. It contains the directory schema of the LDAP server. A directory schema specifies, among other things, the types of objects that a directory may have and the attributes that are mandatory and optional to that object. A directory schema also contains attribute type definitions, object class definitions, and other information, which a server uses to determine how to match a filter or attribute value assertion against the attributes of an entry, and whether to permit add and modify operations. The LDAP v3 schema is based on the X.500 standard for common objects found in a network like countries, localities, organizations, users/persons, groups and devices. The LDAP v3 schema is specified in RFC 2252 and RFC 2256. All LDAP entries in the directory are typed. Each entry belongs to object classes that identify the type of data represented by the entry. The object class specifies the mandatory and optional attributes that can be associated with an entry of that class. The object classes for all objects in the directory form a class hierarchy. The classes top and alias are at the root of the hierarchy. For example, the organizationalPerson object class is a subclass of the Person object class, which in turn is a subclass of top. When creating a new LDAP entry, you must always specify all of the object classes to which the new entry belongs. Because many directories do not support object class subclassing, you also should always include all of the superclasses of the entry. Three types of object classes are possible: • • • Structural. Indicates the attributes that the entry may have and where each entry may occur in the DIT. Auxiliary. Indicates the attributes that the entry may have. Abstract. Indicates a "partial" specification in the object class hierarchy; only structural and auxiliary subclasses may appear as entries in the directory.

For example, for an organizationalPerson object, you should list in its object classes the organizationalPerson, person, and top classes. The organizationalPerson, person, and top objects are listed as the following entries in the core.schema file. objectclass ( 2.5.6.0 NAME 'top' ABSTRACT MUST objectClass ) objectclass ( 2.5.6.6 NAME 'person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) ) objectclass ( 2.5.6.7 NAME 'organizationalPerson' SUP person STRUCTURAL
© Trendz Information Technologies Ltd. Page No. 86 of 220

J2EE MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) ) LDAP v3 specifies that each directory entry may contain an operational attribute that identifies its subschema subentry. A subschema subentry contains the schema definitions for the object classes and attribute type definitions used by entries in a particular part of the directory tree. If a particular entry does not have a subschema subentry, then the subschema subentry of the root DSE, which is named by the empty DN, is used. For more information about the schema, refer to RFCs 2252 and 2256. Adding Entries Adding entries to the server is the first thing you should do. To add entries to slapd, you use ldapadd, which reads the content of an ldif file, checks the validity of its entries, and adds the entries to the server if the entries are correct. To add entries to the LDAP server, you need to pass the domain name and the password for the root user. For example, with the following command you pass the domain name (sendal.jepit.edu.au) and the password (secret) and the example.ldif containing the entries to be added. ldapadd -x -D "cn=Manager ,dc=sendal,dc=jepit,dc=edu,dc=au" -w secret -f example.ldif The argument list of ldapadd can be displayed by typing ldapadd with no arguments. LDAP Data Interchange Format (LDIF) As mentioned above, the LDIF is used to represent LDAP entries in text form. The basic syntax of an LDIF entry is . [<id>] dn: <distinguished name> <attrtype>: <attrvalue> <attrtype>: <attrvalue> ... where <id> is the optional entry ID (a positive decimal number). Normally, you would not supply the <id>, allowing the database creation tools to do that for you. A line may be continued by starting the next line with a single space or tab character, as in dn: cn=Frank Dominic, o=University of Michigan, c=US Multiple attribute values are specified on separate lines. cn: Frank Dominic cn: Frank B Dominic If an <attrvalue> contains a non-printing character, or begins with a space or a colon (:), the <attrtype> is followed by a double colon and the value is encoded in base 64 notation. e.g., the value " begins with a space" would be encoded like this:
© Trendz Information Technologies Ltd. Page No. 87 of 220

J2EE

cn:: IGJlZ2lucyB3aXRoIGEgc3BhY2U= Blank lines separate multiple entries within the same LDIF file. Here is an example of an LDIF file containing three entries. dn: cn=Barbara J Jensen, o=University of Michigan, c=US cn: Barbara J Jensen cn: Babs Jensen objectclass: person sn: Jensen dn: cn=Bjorn J Jensen, o=University of Michigan, c=US cn: Bjorn J Jensen cn: Bjorn Jensen objectclass: person sn: Jensen dn: cn=Jennifer J Jensen, o=University of Michigan, c=US cn: Jennifer J Jensen cn: Jennifer Jensen objectclass: person sn: Jensen jpegPhoto:: /9j/4AAQSkZJRgABAAAAAQABAAD/2wBDABALD A4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQ ERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVG ... Notice that the jpegPhoto in Jennifer Jensen's entry is encoded in base 64. Java Naming and Directory Interface (JNDI) The JNDI is API for writing programs to access naming and directory services. The JNDI is grouped into five packages. • • • • • javax.naming javax.naming.directory javax.naming.event javax.naming.ldap javax.naming.spi you only need the javax.naming and

For the project in this article javax.naming.directory packages.

JNDI is included in version 1.3 of Java 2 SDK. If you are using this version, you are in luck. For users of JDK 1.1 and Java 2 SDK version 1.2, the JNDI can be downloaded and installed separately. In the Java 2 SDK, version 1.3, you can find service providers for the following services: • • • LDAP CORBA Common Object Service (COS) Name Service Java Remote Method Invocation (RMI) Registry.

If you are using an older version of Java, you must first download the JNDI as a Standard Extension on the JDK 1.1 and Java 2 SDK, version 1.2. You must also download one or more service providers. These service providers act like JDBC drivers for database access.

© Trendz Information Technologies Ltd.

Page No. 88 of 220

J2EE

Accessing A Naming Service When accessing a naming service, you first need a service provider. The first thing to do is to get the initial context, which is the starting position into the namespace. You acquire the initial context before you do any other operation. This is because all operations on naming and directory services are performed relative to some context. If you specify that your initial context when accessing a filesystem is the /usr/local directory when you call the list() method, then it's the contents of the /usr/local directory that will be returned. You can think of the initial context as the application default directory. To obtain the initial context, you call the InitialContext() constructor, passing all the necessary environment information in a Hashtable object: Hashtable env = new Hashtable(); Into the Hashtable, you then put the service provider. For example, if you are using the file system service provider from Sun, this is the line of code you need. env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); The file system service provider can be downloaded here. different service provider, replace put()'s second argument. If you are using a

Another important environment property that you need to get the initial context is the PROVIDER_URL. This property is assigned the location of the initial context. This could be a URL on the Internet or it could just be a directory in a file system. For instance, if you decide that your initial context when accessing a Unix file system is the /usr/local directory, then you need the following line of code. env.put(Context.PROVIDER_URL, "file:/usr/local"); Or, on a Windows system, if you want the C:\data directory to be the initial context, your code would look like the following. env.put(Context.PROVIDER_URL, "file:C:\\data"); And, optionally, you can also put the user credentials such as the username and password. env.put(Context.SECURITY_PRINCIPAL, "james"); env.put(Context.SECURITY_CREDENTIALS, "secret"); Having the environment information ready, you can now create the initial context. Context ctx = new InitialContext(env); If the object is created successfully, you can use the resulting Context object to access the naming service. The lookup method of the Context interface can be used to retrieve an object by passing its name. Object obj = ctx.lookup("info.txt");

© Trendz Information Technologies Ltd.

Page No. 89 of 220

J2EE For example, the following code prepares an environment Hashtable object, creates an initial context, and retrieves the info.txt file. import java.util.Hashtable; import javax.naming.*; import java.io.File; public class Naming { public static void main(String[] args) { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); env.put(Context.PROVIDER_URL, "file:C:\\123data\\MyArticles\\WhitePagesWithLDAP"); env.put(Context.SECURITY_PRINCIPAL, "james"); env.put(Context.SECURITY_CREDENTIALS, "secret"); try { Context ctx = new InitialContext(env); File f = (File)ctx.lookup("info.txt"); } catch (NamingException e) { System.out.println(e.toString()); }

} }

The ‘Object’ object from the lookup method is cast to a File object. If the object is a Printer, you can do something similar: Printer printer = (Printer) ctx.lookup("BigMomma"); printer.print(report); Some of the code is in a try-catch wrapper because many methods in the JNDI packages can throw a NamingException. Other useful methods of the Context interface include the following. • • • • bind() -- Binds an object to a name. After the binding, you can retrieve the object by looking up the name. rebind() -- Adds or replaces a binding. If the name is already bound to an object, it will be unbound and bound with the new object specified as the argument of this method. unbind() -- Removes a binding. list() -- Enumerates the names bound in the named context, along with the class names of objects bound to them.

Every naming method in the Context interface has two overloads: one that accepts a Name argument and one that accepts a java.lang.String name. Name is an interface that represents a generic name; an ordered sequence of zero or more components.

© Trendz Information Technologies Ltd.

Page No. 90 of 220

J2EE The overloads that accept Name are useful for applications that need to manipulate names, that is, composing them, comparing components, and so on. A java.lang.String name argument represents a composite name. The overloads that accept java.lang.String names are likely to be more useful for simple applications, such as those that read in a name and look up the corresponding object. Accessing A Directory Service When you access a directory service, there are several initial steps to perform. The first is to prepare an environment Hashtable object to get the initial context. Hashtable env = new Hashtable(); One of the environment properties you need to set is the INITIAL_CONTEXT_FACTORY. For example, if you are accessing an LDAP service, you can use the service provider from Sun. The code would then look like the following. env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); If you are using a service provider from another vendor, just replace the second argument to put(). Next, you supply the location of the service. For example, the following specifies a location of an LDAP server at ldap://sendal.jepit.edu.au:389 (389 is the default port for the LDAP service). env.put(Context.PROVIDER_URL, "ldap://sendal.jepit.usyd.edu.au:389"); You can then acquire an initial context by passing the environment Hashtable. However, unlike accessing a naming system, you use the DirContext interface instead of the Context interface. DirContext ctx = new InitialDirContext(env); Having a DirContext object, you can access the directory service using the methods of the DirContext interface; the important methods of which include getAttributes, getSchema and search. • getAttributes() -- Returns the attributes of an object in the directory. For this method to work, you need to pass the name of the object for which you want the attributes. If you have an object whose name is "cn=boni, ou=person", you can retrieve the object's attributes using the following line of code. Attributes attr = ctx.getAttributes("cn=boni, ou=person"); getSchema() -- Retrieves the schema associated with the named object. search() -- Search for entries in a named context or object. The search must satisfy a given search filter. The syntax of one of the many search methods is as follows. public NamingEnumeration search(String name, String filter, SearchControls cons) throws NamingException The parameters are given below. o name -- The name of the context or object to search. o filter -- The filter expression to use for the search; may not be null o cons -- These control the search. If null, the default search controls are used (equivalent to (new SearchControls())).
Page No. 91 of 220

• • •

© Trendz Information Technologies Ltd.

J2EE You can create a SearchControls object by using the following code. SearchControls constraints = new SearchControls(); constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); Developing a White Pages Service A white pages service for locating a person in an LDAP server. As mentioned previously, I use the LDAP server from OpenLDAP. In order to keep the project simple, I use the person object defined in the core.schema file. For convenience, the person object in the core.schema file is re-presented here. objectclass ( 2.5.6.6 NAME 'person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) ) The person object has two mandatory attributes: sn and cn, and four optional attributes: • • • • userPassword telephoneNumber seeAlso description

Adding Some Entries To test the code in this project, you need to populate the directory: ldapadd -x -D "cn=Manager ,dc=sendal,dc=jepit,dc=edu,dc=au" -w secret -f example.ldif This reads the example.ldif file and insert its content as entries to the server. The example.ldif file contains the following. dn: cn=Bulbul, dc=sedal,dc=usyd,dc=edu,dc=au objectclass: person cn: Bulbul Kurniawan sn: Kurniawan userPassword: secret telephoneNumber: +61 98371313 dn: cn=boni, dc=sedal,dc=usyd,dc=edu,dc=au objectclass: person cn: Boni Milliken sn: Milliken userPassword: dog telephoneNumber: +61 9555 1212 dn: cn=boy, dc=sedal,dc=usyd,dc=edu,dc=au objectclass: person cn: Boy Milliken sn: Milliken userPassword: taboo telephoneNumber: +61 98989898
© Trendz Information Technologies Ltd. Page No. 92 of 220

J2EE

Make sure that you have installed the correct service provider and your CLASSPATH variable contains the path to the JNDI packages. The Code The code for the white pages service is given in Listing 1. The Java code allows you to access the LDAP server and search a person or persons by passing a surname. The code starts by preparing an environment Hashtable object and setting the necessary properties for the environment. Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://sendal.jepit.edu.au:389"); And then, as explained above, you need a DirContext object as the initial context, which is done by calling the InitialDirContext constructor, passing the environment Hashtable. DirContext ctx = new InitialDirContext(env); Once you have a DirContext object, you can use it to access the LDAP service. To start searching, use the search method by passing a SearchControls object. SearchControls constraints = new SearchControls(); constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); NamingEnumeration persons = ctx.search("dc=sendal,dc=jepit,dc=edu,dc=au", "(objectclass=person)", constraints); Then, display the search result, i.e., the attributes of all the person objects that match the search criteria. For each person object found, you use the getAttributes method to retrieve the object's attributes. This method returns the Attributes object. You can then use the get method of the Attributes object to obtain the value of an attribute by passing the attribute name. attributes.get( attributeName ); The part of the code that displays the attribute names of the person objects found is given below. System.out.println("Distinguished Name \t| " + "Common Name \t| Surname \t| Phone"); while (persons != null && persons.hasMore()) { SearchResult sr = (SearchResult) persons.next(); System.out.print( sr.getName() + "\t| "); // distinguised name Attributes attrs = sr.getAttributes(); attrs.put(new BasicAttribute("sn", searchedSurname));
© Trendz Information Technologies Ltd. Page No. 93 of 220

J2EE // attrs.put(new BasicAttribute("cn", "boy")); System.out.print(attrs.get("cn") + "\t| "); // common name System.out.print(attrs.get("sn") + "\t| "); // surname System.out.println(attrs.get("telephoneNumber")); // phone } // end of while If you run the code in Listing 1, you can see the result that looks something like the following. Distinguished Name | Common Name | Surname | Phone cn=Boni Milliken |cn: boy |sn: Milliken | +61 9555 1212 cn=Boy Milliken |cn: boy |sn: Milliken | +61 98989898

© Trendz Information Technologies Ltd.

Page No. 94 of 220

J2EE JAVA TRANSACTION API JTA/XA Transactions A transaction managed and coordinated by the J2EE platform is a JTA or XA transaction. A J2EE product is required to support JTA transactions according to the transaction requirements defined in the J2EE specification. There are two ways to begin a JTA transaction. A component can begin a JTA transaction explicitly using the JTA javax.transaction.UserTransaction interface or it can also be started implicitly or automatically by the EJB container if an EJB bean uses container managed transaction specification. The main benefit of using JTA transactions is the ability to seamlessly combine multiple application components and RDBMS/EIS accesses into one single transaction with a little coding effort. For example, if a component X begins a JTA transaction and invokes a method of component Y, the transaction will be propagated transparently from component X to Y by the platform. Enterprise beans using container-managed transaction demarcation will not need to begin or commit transactions programmatically as the EJB container itself handles the demarcation automatically. It is always recommended to access an RDBMS or EIS within the scope of a JTA transaction. JTA allows applications to access transaction management independent of any specific implementation by specifying standard Java interfaces between a transaction manager, the transactional application, the J2EE server, and the resource managers. OMG Object Transaction Service JTS specifies the implementation of a transaction manager that supports JTA and implements the Java mapping of the OMG Object Transaction Service (OTS) 1.1 specification. JTS propagates transactions using IIOP. A JTS transaction manager provides the services and management functions required to support transaction demarcation, transactional resource management, synchronization, and transaction context propagation. An application component developer uses the JTA UserTransaction interface to demarcate JTA transaction boundaries in components. The JTS TransactionManager and XAResource interfaces are low level APIs between a J2EE server and enterprise information system resource managers and are not intended to use by applications. A J2EE platform might choose to use a JTS implementation to support the transaction semantics defined in J2EE specification. An example is the J2EE SDK. The JTS implementation is transparent to J2EE components. Components should never interact directly with JTS. Instead, they should use the JTA UserTransaction interface for transaction demarcation. Transactions in clients: Case I This is the case where the J2EE configuration is {Stand-alone Client -> EJB Container -> RDBMS/EIS Resources}. Transaction support in applets and application clients is not required by the J2EE platform. However, a J2EE product might choose to implement and provide this capability for added value. So the ability of applets and fat standalone application clients to directly access a UserTransaction object depends entirely on the capabilities provided by the container. To ensure portability, applets and application clients should delegate transactional work to the lower tier of enterprise beans. Transactions in web components: Case II This is the case where the J2EE configuration is {Browser <--> Web Container <--> RDBMS/EIS Resources}. It is possible for a servlet or a JSP page to use JNDI lookup to get hold of a UserTransaction object and use the underlying interface to programmatically specify transactions. In a two-tier application configuration where a
© Trendz Information Technologies Ltd. Page No. 95 of 220

J2EE web component needs to access enterprise information systems under the scope of a JTA transaction, this is quite common. The code snippet below illustrates the use of the JTA interface to specify transactions within a web component: Context myCntxt = new InitialContext(); UserTransaction ut = (UserTransaction) myCntxt.lookup("java:comp/UserTransaction"); ut.begin(); // perform transactional work here ut.commit(); It is important to keep in mind that a web component like a servlet may only start a transaction in its service method. Moreover, a transaction started by a servlet or a JSP page must be completed before the service method returns. Transactions cannot span across web requests. The following guidelines are recommended for handling interactions in web components between JTA transactions, threads, and JDBC connections. • • • • • JTA transactions should start and complete only from the thread in which the service method is called. Additional threads created in the servlet should not attempt to start any JTA transaction. JDBC connections may be acquired and released by a thread other than the service method thread, but should not be shared between threads. JDBC Connection objects should not be stored in static fields. For web components implementing the SingleThreadModel, JDBC Connection objects may be stored in class instance fields. For web components (Servlets) not implementing the SingleThreadModel, JDBC Connection objects should not be stored in class instance fields and should be acquired and released within the same invocation of the service method.

Transactions in application servers: Case III This is the case where the J2EE configuration is {Browser <-> Web Container <-> EJB Container <-> RDBMS/EIS Resources}. The following scenarios are illustrated to motivate discussions on use of transactions in application servers with EJB container and a built in transaction monitor. Scenario A: Messages sent/received over JMS and multiple databases access: It's possible for an application using EJB servers to send messages to or receive messages from one or more JMS destinations or update data in one or more databases in a single transaction. In the following figure, a client invokes a method on the remote interface of enterprise Bean A. which in turn sends a message to a JMS queue and updates data in a database A. After that, enterprise Bean A calls a method of another enterprise Bean B that updates data in database B. The application server with its EJB container and built in transaction manager ensures that the operations on A, B, and C are either all committed or rolled back.

© Trendz Information Technologies Ltd.

Page No. 96 of 220

J2EE

Figure 5. Message sent to JMS queue and updates to multiple databases The application programmer does not have to do anything to ensure transactional semantics. The EJBs A and B perform the sending of the message and database updates using the standard JMS and JDBC APIs. Behind the scenes, the application server enlists the session on the connection to the JMS provider and the database connections as part of the transaction. When the transaction commits, the application server and the messaging and database systems perform a two-phase commit protocol to ensure atomic updates across all the three resources. Scenario B: Multiple database access via multiple Application Servers: The J2EE architecture allows updates of data at multiple sites to be performed in a single transaction. In the following figure, a client invokes a method on enterprise Bean A. which in turn sends a message to a message queue, updates data in database A. After that, EJB A calls a method in another EJB B deployed in another application server which updates data in database B. The EJB architecture makes it possible to perform the updates to databases A and B in a single transaction.

© Trendz Information Technologies Ltd.

Page No. 97 of 220

J2EE

Figure 6. Updates to multiple databases in same transaction When EJB A invokes EJB B, the two application servers cooperate to propagate the transaction context from A to B. This transaction context propagation is transparent to the application. At commit time, the two application servers use distributed two phase commit protocol (if the capability exists) to ensure the atomicity of the database updates and the transaction. The two types of transaction demarcation in enterprise beans, namely, bean managed and container managed, are discussed in detail next. Bean managed transaction As mentioned before, in a bean-managed transaction, an enterprise bean uses the javax.transaction.UserTransaction interface to explicitly specify transaction boundaries in the application code. Only session beans and message driven beans can choose to use bean-managed demarcation. An entity bean must always use container managed transaction demarcation. The following code illustrates the use of JTA interface to specify transactions in an enterprise bean with bean-managed transaction demarcation. UserTransaction ut = ejbContext.getUserTransaction(); ut.begin(); // Transactional work is done here ut.commit(); The following example illustrates a business method of a typical session bean that performs a bean-managed transaction involving both a database connection and a JMS connection. public class MySessionEJB implements SessionBean { EJBContext ejbContext; public void someMethod(...) { javax.transaction.UserTransaction ut;
© Trendz Information Technologies Ltd. Page No. 98 of 220

J2EE javax.sql.DataSource ds; java.sql.Connection dcon; java.sql.Statement stmt; javax.jms.QueueConnectionFactory qcf; javax.jms.QueueConnection qcon; javax.jms.Queue q; javax.jms.QueueSession qsession; javax.jms.QueueSender qsender; javax.jms.Message message; InitialContext initCtx = new InitialContext(); // obtain db conn object and set it up for transactions ds = (javax.sql.DataSource) initCtx.lookup("java:comp/env/jdbc/Database"); dcon = ds.getConnection(); stmt = dcon.createStatement(); // obtain jms conn object and set up session for transactions qcf = (javax.jms.QueueConnectionFactory) initCtx.lookup("java:comp/env/jms/qConnFactory"); qcon = qcf.createQueueConnection(); qsession = qcon.createQueueSession(true,0); q = (javax.jms.Queue) initCtx.lookup("java:comp/env/jms/jmsQueue"); qsender = qsession.createSender(q); message = qsession.createTextMessage(); message.setText("some message"); // // Now do a transaction that involves the two connections. // ut = ejbContext.getUserTransaction(); // start the transaction ut.begin(); // Do database updates and send message. The Container // automatically enlists dcon and qsession with the // transaction. stmt.executeQuery(...); stmt.executeUpdate(...); stmt.executeUpdate(...); qsender.send(message); // commit the transaction ut.commit(); // release connections stmt.close(); qsender.close(); qsession.close(); dcon.close(); qcon.close(); } ... }

© Trendz Information Technologies Ltd.

Page No. 99 of 220

J2EE The following example illustrates a stateful session bean that retains transaction context across three client calls, invoked in the order {method1, method2, and method3}. public class MySessionEJB implements SessionBean { EJBContext ejbContext; javax.sql.DataSource ds1; javax.sql.DataSource ds2; java.sql.Connection con1; java.sql.Connection con2; public void method1(...) { java.sql.Statement stmt; InitialContext initCtx = new InitialContext(); // obtain user transaction interface ut = ejbContext.getUserTransaction(); // start a transaction ut.begin(); // make some updates on con1 ds1 = (javax.sql.DataSource) initCtx.lookup("java:comp/env/jdbc/Database1"); con1 = ds1.getConnection(); stmt = con1.createStatement(); stmt.executeUpdate(...); // // The Container retains the transaction associated with the // instance to the next client call (which is method2(...)). } public void method2(...) { java.sql.Statement stmt; InitialContext initCtx = new InitialContext(); // make some updates on con2 ds2 = (javax.sql.DataSource) initCtx.lookup("java:comp/env/jdbc/Database2"); con2 = ds2.getConnection(); stmt = con2.createStatement(); stmt.executeUpdate(...); // The Container retains the transaction associated with the // instance to the next client call (which is method3(...)). } public void method3(...) { java.sql.Statement stmt; // obtain user transaction interface ut = ejbContext.getUserTransaction(); // make some more updates on con1 and con2 stmt = con1.createStatement(); stmt.executeUpdate(...); stmt = con2.createStatement(); stmt.executeUpdate(...); // commit the transaction ut.commit(); // release connections stmt.close(); con1.close();
© Trendz Information Technologies Ltd. Page No. 100 of 220

J2EE con2.close(); } ... } It is possible for an enterprise bean to open and close a database connection in each business method rather than hold the connection open until the end of transaction. If the client in the following example executes the sequence of methods {method1, method2, method2, method3}, all the database updates done by the multiple invocations of method2 are performed in the scope of the same transaction. This is the transaction started in method1 and committed in method3. public class MySessionEJB implements SessionBean { EJBContext ejbContext; InitialContext initCtx; public void method1(...) { java.sql.Statement stmt; // obtain user transaction interface ut = ejbContext.getUserTransaction(); // start a transaction ut.begin(); } public void method2(...) { javax.sql.DataSource ds; java.sql.Connection con; java.sql.Statement stmt; // open connection ds = (javax.sql.DataSource) initCtx.lookup("java:comp/env/jdbc/Database"); con = ds.getConnection(); // make some updates on con stmt = con.createStatement(); stmt.executeUpdate(...); // close the connection stmt.close(); con.close(); } public void method3(...) { // obtain user transaction interface ut = ejbContext.getUserTransaction(); // commit the transaction ut.commit(); } ... } An enterprise bean with bean-managed transaction specification need not and should not use the getRollbackOnly() and setRollbackOnly()methods of the EJBContext interface since, if necessary, it can obtain the status of a transaction by using the getStatus() method of the javax.transaction.UserTransaction interface. It can also roll back a transaction using the rollback()method of the same interface if required.
© Trendz Information Technologies Ltd. Page No. 101 of 220

J2EE

REMOTE METHOD INVOCATION Java RMI: Serialization Serialization is the process of converting a set of object instances that contain references to each other into a linear stream of bytes, which can then be sent through a socket, stored to a file, or simply manipulated as a stream of data. Serialization is the mechanism used by RMI to pass objects between JVMs, either as arguments in a method invocation from a client to a server or as return values from a method invocation. In the first section of this book, I referred to this process several times but delayed a detailed discussion until now. In this chapter, we drill down on the serialization mechanism; by the end of it, you will understand exactly how serialization works and how to use it efficiently within your applications. The Need for Serialization Envision the banking application while a client is executing a withdrawal. The part of the application we're looking at has the runtime structure shown in Figure 10-1.

Figure 10-1. Runtime structure when making a withdrawal What does it mean for the client to pass an instance of Moneyto the server? At a minimum, it means that the server is able to call public methods on the instance of Money. One way to do this would be to implicitly make Moneyinto a server as well. For example, imagine that the client sends the following two pieces of information whenever it passes an instance as an argument: • • The type of the instance; in this case, Money. A unique identifier for the object (i.e., a logical reference). For example, the address of the instance in memory.

The RMI runtime layer in the server can use this information to construct a stub for the instance of Money, so that whenever the Accountserver calls a method on what it thinks of as the instance of Money, the method call is relayed over the wire, as shown in Figure 10-2.

© Trendz Information Technologies Ltd.

Page No. 102 of 220

J2EE

Figure 10-2. Relaying a Money method call from the

server Attempting to do things this way has three significant drawbacks: • • You can't access fields on the objects that have been passed as arguments. Stubs work by implementing an interface. They implement the methods in the interface by simply relaying the method invocation across the network. That is, the stub methods take all their arguments and simply marshall them for transport across the wire. Accessing a public field is really just dereferencing a pointer--there is no method invocation and hence, there isn't a method call to forward over the wire. It can result in unacceptable performance due to network latency. Even in our simple case, the instance of Accountis going to need to call getCents( )on the instance of Money. This means that a simple call to makeDeposit( )really involves at least two distinct networked method calls: makeDeposit( )from the client and getCents( )from the server. It makes the application much more vulnerable to partial failure. Let's say that the server is busy and doesn't get around to handling the request for 30 seconds. If the client crashes in the interim, or if the network goes down, the server cannot process the request at all. Until all data has been requested and sent, the application is particularly vulnerable to partial failures.

This last point is an interesting one. Any time you have an application that requires a long-lasting and durable connection between client and server, you build in a point of failure. The longer the connection needs to last, or the higher the communication bandwidth the connection requires, the more likely the application is to occasionally break down. TIP: The original design of the Web, with its stateless connections, serves as a good example of a distributed application that can tolerate almost any transient network failure. These three reasons imply that what is really needed is a way to copy objects and send them over the wire. That is, instead of turning arguments into implicit servers, arguments need to be completely copied so that no further network calls are needed to complete the remote method invocation. Put another way, we want the result of makeWithdrawal( )to involve creating a copy of the instance of Moneyon the server side. The runtime structure should resemble Figure 10-3.

© Trendz Information Technologies Ltd.

Page No. 103 of 220

J2EE

Figure 10-3. Making a remote method call can create deep copies of the arguments and return values The desire to avoid unnecessary network dependencies has two significant consequences: • Once an object is duplicated, the two objects are completely independent of each other. Any attempt to keep the copy and the original in sync would involve propagating changes over the network, entirely defeating the reason for making the copy in the first place. The copying mechanism must create deep copies. If the instance of Moneyreferences another instance, then copies must be made of both instances. Otherwise, when a method is called on the second object, the call must be relayed across the wire. Moreover, all the copies must be made immediately--we can't wait until the second object is accessed to make the copy because the original might change in the meantime.

These two consequences have a very important third consequence: • If an object is sent twice, in separate method calls, two copies of the object will be created. In addition to arguments to method calls, this holds for objects that are referenced by the arguments. If you pass object A, which has a reference to object C, and in another call you pass object B, which also has a reference to C, you will end up with two distinct copies of C on the receiving side.

Drilling Down on Object Creation To see why this last point holds, consider a client that executes a withdrawal and then tries to cancel the transaction by making a deposit for the same amount of money. That is, the following lines of code are executed: server.makeWithdrawal(amount); .... server.makeDeposit(amount); The client has no way of knowing whether the server still has a copy of amount. After all, the server may have used it and then thrown the copy away once it was done. This means that the client has to marshall amountand send it over the wire to the server. The RMI runtime can demarshall amount, which is the instance of Money the client sent. However, even if it has the previous object, it has no way (unless equals()has
© Trendz Information Technologies Ltd. Page No. 104 of 220

J2EE been overridden) to tell whether the instance it just demarshalled is equal to the previous object. More generally, if the object being copied isn't immutable, then the server might change it. In this case, even if the two objects are currently equal, the RMI runtime has no way to tell if the two copies will always be equal and can potentially be replaced by a single copy. To see why, consider our Printer example again. At the end of Chapter 3, we considered a list of possible feature requests that could be made. One of them was the following: Managers will want to track resource consumption. This will involve logging print requests and, quite possibly, building a set of queries that can be run against the printer's log. This can be implemented by adding a few more fields to DocumentDescriptionand having the server store an indexed log of all the DocumentDescriptionobjects it has received. For example, we may add the following fields to DocumentDescription: public Time whenPrinted; public Person sender; public boolean printSucceeded; Now consider what happens when the user actually wants to print two copies of the same document. The client application could call: server.printDocument(document); twice with the "same" instance of DocumentDescription. And it would be an error for the RMI runtime to create only one instance of DocumentDescriptionon the server side. Even though the "same" object is passed into the server twice, it is passed as parts of distinct requests and therefore as different objects. TIP: This is true even if the runtime can tell that the two instances of DocumentDescription are equal when it finishes demarshalling. An implementation of a printer may well have a notion of a job queue that holds instances of DocumentDescription. So our client makes the first call, and the copy of document is placed in the queue (say, at number 5), but not edited because the document hasn't been printed yet. Then our client makes the second call. At this point, the two copies of document are equal. However, we don't want to place the same object in the printer queue twice. We want to place distinct copies in the printer queue. Thus, we come to the following conclusion: network latency, and the desire to avoid vulnerability to partial failures, forces us to have a deep copy mechanism for most arguments to a remote method invocation. This copying mechanism has to make deep copies, and it cannot perform any validation to eliminate "extra" copies across methods.

TIP: While this discussion provides examples of implementation decisions that force two copies to occur, it's important to note that,
© Trendz Information Technologies Ltd. Page No. 105 of 220

J2EE even without such examples, clients should be written as if the servers make independent copies. That is, clients are written to use interfaces. They should not, and cannot, make assumptions about server-side implementations of the interfaces. Using Serialization Serialization is a mechanism built into the core Java libraries for writing a graph of objects into a stream of data. This stream of data can then be programmatically manipulated, and reversing the process can make a deep copy of the objects. This reversal is often called deserialization. In particular, there are three main uses of serialization: As a Persistence mechanism If the stream being used is FileOutputStream, then the data will automatically be written to a file. As a Copy mechanism If the stream being used is ByteArrayOutputStream, then the data will be written to a byte array in memory. This byte array can then be used to create duplicates of the original objects. As a Communication mechanism If the stream being used comes from a socket, then the data will automatically be sent over the wire to the receiving socket, at which point another program will decide what to do. The important thing to note is that the use of serialization is independent of the serialization algorithm itself. If we have a serializable class, we can save it to a file or make a copy of it simply by changing the way we use the output of the serialization mechanism. As you might expect, serialization is implemented using a pair of streams. Even though the code that underlies serialization is quite complex, the way you invoke it is designed to make serialization as transparent as possible to Java developers. To serialize an object, create an instance of ObjectOutputStream and call the writeObject()method; to read in a serialized object, create an instance of ObjectInputStreamand call the readObject( )object. ObjectOutputStream ObjectOutputStream, defined in the java.io package, is a stream that implements the "writing-out" part of the serialization algorithm. (RMI actually uses a subclass of ObjectOutputStream to customize its behavior.) The methods implemented by ObjectOutputStream can be grouped into three categories: methods that write information to the stream, methods used to control the stream's behavior, and methods used to customize the serialization algorithm.

The "write()" methods The first, and most intuitive, category consists of the "write" methods:
© Trendz Information Technologies Ltd. Page No. 106 of 220

J2EE

public public public public public public public public public public public public public public public public public

void void void void void void void void void void void void void void void void void

write(byte[] b); write(byte[] b, int off, int len); write(int data); writeBoolean(boolean data); writeByte(int data); writeBytes(String data); writeChar(int data); writeChars(String data); writeDouble(double data); writeFields( ); writeFloat(float data); writeInt(int data); writeLong(long data); writeObject(Object obj); writeShort(int data); writeUTF(String s); defaultWriteObject( );

For the most part, these methods should seem familiar. writeFloat( ), for example, works exactly as you would expect after reading Chapter 1 -- it takes a floating-point number and encodes the number as four bytes. There are, however, two new methods here: writeObject() and defaultWriteObject(). The writeObject()serializes an object. In fact, writeObject() is often the instrument of the serialization mechanism itself. In the simplest and most common case, serializing an object involves doing two things: creating an ObjectOuptutStreamand calling writeObject() with a single "top-level" instance. The following code snippet shows the entire process, storing an object--and all the objects to which it refers--into a file: FileOutputStream underlyingStream = new FileOutputStream("C:\\temp\\test"); ObjectOutputStream serializer = new ObjectOutputStream(underlyingStream); serializer.writeObject(serializableObject); Of course, this works seamlessly with the other methods for writing data. That is, if you wanted to write two floats, a String, and an object to a file, you could do so with the following code snippet: FileOutputStream underlyingStream = new FileOutputStream("C:\\temp\\test"); ObjectOutputStream serializer = new ObjectOutputStream(underlyingStream); serializer.writeFloat(firstFloat); serializer.writeFloat(secongFloat); serializer.writeUTF(aString); serializer.writeObject(serializableObject); TIP: ObjectOutputStream's constructor takes an OutputStream as an argument. This is analogous to many of the streams we looked at in Chapter 1. ObjectOutputStream and ObjectInputStream are simply encoding and transformation layers. This enables RMI to send objects over the wire by opening a socket connection, associating the OutputStream with the socket connection, creating an ObjectOutputStream on top of the socket's OutputStream, and then calling writeObject().
© Trendz Information Technologies Ltd. Page No. 107 of 220

J2EE

The other new "write()" method is defaultWriteObject(). defaultWriteObject( )makes it much easier to customize how instances of a single class are serialized. However, defaultWriteObject() has some strange restrictions placed on when it can be called. Here's what the documentation says about defaultWriteObject( ): Write the nonstatic and nontransient fields of the current class to this stream. This may only be called from the writeObject method of the class being serialized. It will throw the NotActiveException if it is called otherwise. That is, defaultWriteObject() is a method that works only when it is called from another specific method at a particular time. Since defaultWriteObject() is useful only when you are customizing the information stored for a particular class, this turns out to be a reasonable restriction. We'll talk more about defaultWriteObject() later in the chapter, when we discuss how to make a class serializable. The stream manipulation methods ObjectOutputStream also implements four methods that deal with the basic mechanics of manipulating the stream: public public public public void void void void reset( ); close( ); flush( ); useProtocolVersion(int version);

With the exception of useProtocolVersion( ), these methods should be familiar. In fact, reset(), close(), and flush()are standard stream methods. useProtocolVersion(), on the other hand, changes the version of the serialization mechanism that is used. This is necessary because the serialization format and algorithm may need to change in a way that's not backwards compatible. If another application needs to read in your serialized data, and the applications will be versioning independently (or running in different versions of the JVM), you may want to standardize on a protocol version. TIP: There are two versions of the serialization protocol currently defined: PROTOCOL_VERSION_1 and PROTOCOL_VERSION_2. If you send serialized data to a 1.1 (or earlier) JVM, you should probably use PROTOCOL_VERSION_1. The most common case of this involves applets. Most applets run in browsers over which the developer has no control. This means, in particular, that the JVM running the applet could be anything, from Java 1.0.2 through the latest JVM. Most servers, on the other hand, are written using JDK1.2.2 or later. (The main exception is EJB containers that require earlier versions of Java. At this writing, for example, Oracle 8i's EJB container uses JDK 1.1.6.) If you pass serialized objects between an applet and a server, you should specify the serialization protocol.

© Trendz Information Technologies Ltd.

Page No. 108 of 220

J2EE

Methods that customize the Serialization mechanism The last group of methods consists mostly of protected methods that provide hooks that allow the serialization mechanism itself, rather than the data associated to a particular class, to be customized. These methods are: public ObjectOutputStream.PutField putFields( ); protected void annotateClass(Class cl); protected void annotateProxyClass(Class cl); protected boolean enableReplaceObject(boolean enable); protected Object replaceObject(Object obj); protected void drain( ); protected void writeObjectOverride(Object obj); protected void writeClassDescriptor(ObjectStreamClass classdesc); protected void writeStreamHeader( ); These methods are more important to people who tailor the serialization algorithm to a particular use or develop their own implementation of serialization. As such, they require a deeper understanding of the serialization algorithm. We'll discuss these methods in more detail later, after we've gone over the actual algorithm used by the serialization mechanism. ObjectInputStream ObjectInputStream, defined in the java.io package, implements the "reading-in" part of the serialization algorithm. It is the companion to ObjectOutputStream--objects serialized using ObjectOutputStream can be deserialized using ObjectInputStream. Like ObjectOutputStream, the methods implemented by ObjectInputStream can be grouped into three categories: methods that read information from the stream, methods that are used to control the stream's behavior, and methods that are used to customize the serialization algorithm. The "read" methods The first, and most intuitive, category consists of the "read" methods: public int read( ); public int read(byte[] b, int off, int len); public boolean readBoolean( ); public byte readByte( ); public char readChar( ); public double readDouble( ); public float readFloat( ); public intreadInt( ); public long readLong( ); public Object readObject( ); public short readShort( ); public byte readUnsignedByte( ); public short readUnsignedShort( ); public String readUTF( ); void defaultReadObject( );

© Trendz Information Technologies Ltd.

Page No. 109 of 220

J2EE Just as with ObjectOutputStream's write( )methods, these methods should be familiar. readFloat( ), for example, works exactly as you would expect after reading Chapter 1: it reads four bytes from the stream and converts them into a single floating-point number, which is returned by the method call. And, again as with ObjectOutputStream, there are two new methods here: readObject()and defaultReadObject( ). Just as writeObject( ) serializes an object, readObject( ) deserializes it. Deserializing an object involves doing two things: creating an ObjectInputStreamand then calling readObject( ). The following code snippet shows the entire process, creating a copy of an object (and all the objects to which it refers) from a file: FileInputStream underlyingStream = new FileInputStream("C:\\temp\\test"); ObjectInputStream deserializer = new ObjectInputStream(underlyingStream); Object deserializedObject = deserializer.readObject( ); This code is exactly inverse to the code we used for serializing the object in the first place. If we wanted to make a deep copy of a serializable object, we could first serialize the object and then deserialize it, as in the following code example: ByteArrayOutputStream memoryOutputStream = new ByteArrayOutputStream( ); ObjectOutputStream serializer = new ObjectOutputStream(memoryOutputStream); serializer.writeObject(serializableObject); serializer.flush( ); ByteArrayInputStream memoryInputStream = new ByteArrayInputStream(memoryOutputStream. toByteArray( )); ObjectInputStream deserializer = new ObjectInputStream(memoryInputStream); Object deepCopyOfOriginalObject = deserializer.readObject( ); This code simply places an output stream into memory, serializes the object to the memory stream, creates an input stream based on the same piece of memory, and runs the deserializer on the input stream. The end result is a deep copy of the object with which we started. The Stream manipulation methods There are five basic stream manipulation methods defined for ObjectInputStream: public public public public public boolean available( ); void close( ); void readFully(byte[] data); void readFully(byte[] data, int offset, int size); int skipBytes(int len);

Of these, available()and skip()are methods first defined on InputStream. available() returns a boolean flag indicating whether data is immediately available, and close() closes the stream. The three new methods are also straightforward. skipBytes( ) skips the indicated number of bytes in the stream, blocking until all the information has been read. And the two readFully( ) methods perform a batch read into a byte array, also blocking until all the data has been read in.
© Trendz Information Technologies Ltd. Page No. 110 of 220

J2EE

Methods that customize the Serialization mechanism The last group of methods consists mostly of protected methods that provide hooks, which allow the serialization mechanism itself, rather than the data associated to a particular class, to be customized. These methods are: protected boolean enableResolveObject(boolean enable); protected Class resolveClass(ObjectStreamClass v); protected Object resolveObject(Object obj); protected class resolveProxyClass(String[] interfaces); protected ObjectStreamClass readClassDescriptor( ); protected Object readObjectOverride( ); protected void readStreamHeader( ); public void registerValidation(ObjectInputValidation obj, int priority); public GetFields readFields( ); These methods are more important to people who tailor the serialization algorithm to a particular use or develop their own implementation of serialization. Like before, they also require a deeper understanding of the serialization algorithm, so I'll hold off on discussing them right now. How to Make a Class Serializable So far, we've focused on the mechanics of serializing an object. We've assumed we have a serializable object and discussed, from the point of view of client code, how to serialize it. The next step is discussing how to make a class serializable. There are four basic things you must do when you are making a class serializable. They are:

1. Implement the Serializable interface.

2. Make sure that instance-level, locally defined state is serialized properly. 3. Make sure that superclass state is serialized properly. 4. Override equals( ) and hashCode( ). Let's look at each of these steps in more detail. Implement the Serializable Interface This is by far the easiest of the steps. The Serializable interface is an empty interface; it declares no methods at all. So implementing it amounts to adding, "implements Serializable" to your class declaration. Reasonable people may wonder about the utility of an empty interface. Rather than define an empty interface, and require class definitions to implement it, why not just simply make every object serializable? The main reason not to do this is that there are some classes that don't have an obvious serialization. Consider, for example, an instance of File. An instance of File represents a file. Suppose, for example, it was created using the following line of code: File file = new File("c:\\temp\\foo");
© Trendz Information Technologies Ltd. Page No. 111 of 220

J2EE

It's not at all clear what should be written out when this is serialized. The problem is that the file itself has a different lifecycle than the serialized data. The file might be edited, or deleted entirely, while the serialized information remains unchanged. Or the serialized information might be used to restart the application on another machine, where "C:\\temp\\foo" is the name of an entirely different file. Another example is provided by the Thread class. A thread represents a flow of execution within a particular JVM. You would not only have to store the stack, and all the local variables, but also all the related locks and threads, and restart all the threads properly when the instance is deserialized. TIP: Things get worse when you consider platform dependencies. In general, any class that involves native code is not really a good candidate for serialization. Make Sure That Instance-Level, Locally Defined State Is Serialized Properly Class definitions contain variable declarations. The instance-level, locally defined variables (e.g., the nonstatic variables) are the ones that contain the state of a particular instance. For example, in our Money class, we declared one such field: public class Money extends ValueObject { private int _cents; .... } The serialization mechanism has a nice default behavior -- if all the instance-level, locally defined variables have values that are either serializable objects or primitive data types, then the serialization mechanism will work without any further effort on our part. For example, our implementations of Account, such as Account_Impl, would present no problems for the default serialization mechanism: public class Account_Impl extends UnicastRemoteObject implements Account { private Money _balance; ... } While _balance doesn't have a primitive type, it does refer to an instance of Money, which is a serializable class. If, however, some of the fields don't have primitive types, and don't refer to serializable classes, more work may be necessary. Consider, for example, the implementation of ArrayList from the java.util package. An ArrayList really has only two pieces of state: public class ArrayList extends AbstractList implements List, Cloneable, java.io. Serializable { private Object elementData[]; private int size; ... }

© Trendz Information Technologies Ltd.

Page No. 112 of 220

J2EE But hidden in here is a huge problem: ArrayList is a generic container class whose state is stored as an array of objects. While arrays are first-class objects in Java, they aren't serializable objects. This means that ArrayList can't just implement the Serializable interface. It has to provide extra information to help the serialization mechanism handle its nonserializable fields. There are three basic solutions to this problem: • • • Fields can be declared to be transient. The writeObject( )/ readObject( ) methods can be implemented. serialPersistentFields can be declared.

Declaring transient fields The first, and easiest, thing you can do is simply mark some fields using the transientkeyword. In ArrayList, for example, elementData is really declared to be a transient field: public class ArrayList extends AbstractList implements List, Cloneable, java.io. Serializable { private transient Object elementData[]; private int size; ... } This tells the default serialization mechanism to ignore the variable. In other words, the serialization mechanism simply skips over the transient variables. In the case of ArrayList, the default serialization mechanism would attempt to write out size, but ignore elementData entirely. This can be useful in two, usually distinct, situations: The variable isn't serializable If the variable isn't serializable, then the serialization mechanism will throw an exception when it tries to serialize the variable. To avoid this, you can declare the variable to be transient. The variable is redundant Suppose that the instance caches the result of a computation. Locally, we might want to store the result of the computation, in order to save some processor time. But when we send the object over the wire, we might worry more about consuming bandwidth and thus discard the cached computation since we can always regenerate it later on. Implementing writeObject() and readObject( ) Suppose that the first case applies. A field takes values that aren't serializable. If the field is still an important part of the state of our instance, such as elementDatain the case of an ArrayList, simply declaring the variable to be transientisn't good enough. We need to save and restore the state stored in the variable. This is done by implementing a pair of methods with the following signatures: private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
Page No. 113 of 220

© Trendz Information Technologies Ltd.

J2EE When the serialization mechanism starts to write out an object, it will check to see whether the class implements writeObject(). If so, the serialization mechanism will not use the default mechanism and will not write out any of the instance variables. Instead, it will call writeObject() and depend on the method to store out all the important state. Here is ArrayList's implementation of writeObject(): private synchronized void writeObject(java.io.ObjectOutputStream stream) throws java. io.IOException { stream.defaultWriteObject( ); stream.writeInt(elementData.length); for (int i=0; i<size; i++) stream.writeObject(elementData[i]); } The first thing this does is call defaultWriteObject(). defaultWriteObject() invokes the default serialization mechanism, which serializes all the nontransient, nonstatic instance variables. Next, the method writes out elementData.lengthand then calls the stream's writeObject( )for each element of elementData. There's an important point here writeObject( )are a pair of methods any customization of serialization implement the other method. If you that is sometimes missed: readObject( )and that need to be implemented together. If you do inside one of these methods, you need to don't, the serialization algorithm will fail.

Unit Tests and Serialization Unit tests are used to test a specific piece of functionality in a class. They are explicitly not end-to-end or application-level tests. It's often a good idea to adopt a unit-testing harness such as Junit when developing an application. Junit gives you an automated way to run unit tests on individual classes and is available from http://www.junit.org/. If you adopt a unit-testing methodology, then any serializable class should pass the following three tests: • • • If it implements readObject( ), it should implement writeObject( ), and viceversa. It is equal (using the equals( )method) to a serialized copy of itself. It has the same hashcode as a serialized copy of itself.

Similar constraints hold for classes that implement the Externalizable interface. Declaring serialPersistentFields The final option that can be used is to explicitly declare which fields should be stored by the serialization mechanism. This is done using a special static final variable called serialPersistentFields, as shown in the following code snippet: private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("size", Integer.TYPE), .... }; This line of code declares that the field named size, which is of type int, is a serial persistent field and will be written to the output stream by the serialization
© Trendz Information Technologies Ltd. Page No. 114 of 220

J2EE mechanism. Declaring serialPersistentFields is almost the opposite of declaring some fields transient. The meaning of transient is, "This field shouldn't be stored by serialization," and the meaning of serialPersistentFields is, "These fields should be stored by serialization." But there is one important difference between declaring some variables to be transient and others to be serialPersistentFields. In order to declare variables to be transient, they must be locally declared. In other words, you must have access to the code that declares the variable. There is no such requirement for serialPersistentFields. You simply provide the name of the field and the type. TIP: What if you try to do both? That is, suppose you declare some variables to be transient, and then also provide a definition for serialPersistentFields? The answer is that the transient keyword is ignored; the definition of serialPersistentFields is definitive. So far, we've talked only about instance-level state. What about class-level state? Suppose you have important information stored in a static variable? Static variables won't get saved by serialization unless you add special code to do so. In our context, (shipping objects over the wire between clients and servers), static are usually a bad idea anyway. Make sure that Superclass state is handled correctly After you've handled the locally declared state, you may still need to worry about variables declared in a superclass. If the superclass implements the Serializable interface, then you don't need to do anything. The serialization mechanism will handle everything for you, either by using default serialization or by invoking writeObject( )/ readObject( )if they are declared in the superclass. If the superclass doesn't implement Serializable, you will need to store its state. There are two different ways to approach this. You can use serialPersistentFields to tell the serialization mechanism about some of the superclass instance variables, or you can use writeObject( )/ readObject( )to handle the superclass state explicitly. Both of these, unfortunately, require you to know a fair amount about the superclass. If you're getting the .class files from another source, you should be aware that versioning issues can cause some really nasty problems. If you subclass a class, and that class's internal representation of instance-level state changes, you may not be able to load in your serialized data. While you can sometimes work around this by using a sufficiently convoluted readObject( ) method, this may not be a solvable problem. We'll return to this later. However, be aware that the ultimate solution may be to just implement the Externalizable interface instead, which we'll talk about later. Another aspect of handling the state of a nonserializable superclass is that nonserializable superclasses must have a zero-argument constructor. This isn't important for serializing out an object, but it's incredibly important when deserializing an object. Deserialization works by creating an instance of a class and filling out its fields correctly. During this process, the deserialization algorithm doesn't actually call any of the serialized class's constructors, but does call the zeroargument constructor of the first nonserializable superclass. If there isn't a zeroargument constructor, then the deserialization algorithm can't create instances of the class, and the whole process fails.

© Trendz Information Technologies Ltd.

Page No. 115 of 220

J2EE WARNING: If you can't create a zero-argument constructor in the first nonserializable superclass, you'll have to implement the Externalizable interface instead. Simply adding a zero-argument constructor might seem a little problematic. Suppose the object already has several constructors, all of which take arguments. If you simply add a zero-argument constructor, then the serialization mechanism might leave the object in a half-initialized, and therefore unusable, state. However, since serialization will supply the instance variables with correct values from an active instance immediately after instantiating the object, the only way this problem could arise is if the constructors actually do something with their arguments--besides setting variable values. If all the constructors take arguments and actually execute initialization code as part of the constructor, then you may need to refractor a bit. The usual solution is to move the local initialization code into a new method (usually named something like initialize() ), which is then called from the original constructor: public MyObject(arglist) { // set local variables from arglist // perform local initialization } to something that looks like: private MyObject( ) { // zero argument constructor, invoked by serialization // and never by any other // piece of code. // note that it doesn't call initialize( ) } public void MyObject(arglist) { // set local variables from arglist initialize( ); } private void initialize( ) { // perform local initialization } After this is done, writeObject( )/ readObject( ) should be implemented, and readObject( ) should end with a call to initialize( ). Sometimes this will result in code that simply invokes the default serialization mechanism, as in the following snippet: private void writeObject(java.io.ObjectOutputStream stream) throws java.io.IOException { stream.defaultWriteObject( ); } private void readObject(java.io.ObjectInputStream stream) throws java.io.IOException { stream.defaultReadObject( );

© Trendz Information Technologies Ltd.

Page No. 116 of 220

J2EE intialize( ); } TIP: If creating a zero-argument constructor is difficult (for example, you don't have the source code for the superclass), your class will need to implement the Externalizable interface instead of Serializable. Override equals( ) and hashCode( ) if Necessary The default implementations of equals( ) and hashCode( ), which are inherited from java.lang.Object, simply use an instance's location in memory. This can be problematic. Consider our previous deep copy code example: ByteArrayOutputStream memoryOutputStream = new ByteArrayOutputStream( ); ObjectOutputStream serializer = new ObjectOutputStream(memoryOutputStream); serializer.writeObject(serializableObject); serializer.flush( ); ByteArrayInputStream memoryInputStream = new ByteArrayInputStream(memoryOutputStream. toByteArray( )); ObjectInputStream deserializer = new ObjectInputStream(memoryInputStream); Object deepCopyOfOriginalObject = deserializer.readObject( ); The potential problem here involves the following boolean test: serializableObject.equals(deepCopyOfOriginalObject) Sometimes, as in the case of Money and DocumentDescription, the answer should be true. If two instances of Money have the same values for _cents, then they are equal. However, the implementation of equals( )inherited from Object will return false. The same problem occurs with hashCode(). Note that Object implements hashCode() by returning the memory address of the instance. Hence, no two instances ever have the same hashCode( ) using Object's implementation. If two objects are equal, however, then they should have the same hashcode. So if you need to override equals( ), you probably need to override hashCode( ) as well. TIP: With the exception of declaring variables to be transient, all our changes involve adding functionality. Making a class serializable rarely involves significant changes to its functionality and shouldn't result in any changes to method implementations. This means that it's fairly easy to retrofit serialization onto an existing object hierarchy. The hardest part is usually implementing equals( ) and hashCode( ). Making DocumentDescription Serializable To make this more concrete, we now turn to the DocumentDescriptionclass from the RMI version of our printer server, which we implemented in Chapter 4. The code for the first nonserializable version of DocumentDescriptionwas the following: public class DocumentDescription implements PrinterConstants { private InputStream _actualDocument; private int _length; private int _documentType;
© Trendz Information Technologies Ltd. Page No. 117 of 220

J2EE private boolean _printTwoSided; private int _printQuality; public DocumentDescription(InputStream actualDocument) throws IOException { this(actualDocument, DEFAULT_DOCUMENT_TYPE, DEFAULT_PRINT_TWO_SIDED, DEFAULT_PRINT_QUALITY); } public DocumentDescription(InputStream actualDocument, int documentType, boolean printTwoSided, int printQuality) throws IOException { _documentType = documentType; _printTwoSided = printTwoSided; _printQuality = printQuality; BufferedInputStream buffer = new BufferedInputStream(actualDocument); DataInputStream dataInputStream = new DataInputStream(buffer); ByteArrayOutputStream temporaryBuffer = new ByteArrayOutputStream( ); _length = copy(dataInputStream, new DataOutputStream(temporaryBuffer)); _actualDocument = new DataInputStream(new ByteArrayInputStream(temporaryBuffer.toByteArray( ))); } public int getDocumentType( ) { return _documentType; } public boolean isPrintTwoSided( ) { return _printTwoSided; } public int getPrintQuality( ) { return _printQuality; } private int copy(InputStream source, OutputStream destination) throws IOException { int nextByte; int numberOfBytesCopied = 0; while(-1!= (nextByte = source.read( ))) { destination.write(nextByte); numberOfBytesCopied++; } destination.flush( ); return numberOfBytesCopied; } } We will make this into a serializable class by following the steps outlined in the previous section.

© Trendz Information Technologies Ltd.

Page No. 118 of 220

J2EE

Implement the Serializable interface This is easy. All we need to do is change the class declaration: public class DocumentDescription implements Serialiazble, PrinterConstants Make sure that instance-level, locally defined state is serialized properly We have five fields to take care of: private private private private private InputStream _actualDocument; int _length; int _documentType; boolean _printTwoSided; int _printQuality;

Of these, four are primitive types that serialization can handle without any problem. However, _actualDocumentis a problem. InputStream is not a serializable class. And the contents of _actualDocumentare very important; _actualDocumentcontains the document we want to print. There is no point in serializing an instance of DocumentDescription unless we somehow serialize _actualDocument as well. If we have fields that serialization cannot handle, and they must be serialized, then our only option is to implement readObject( ) and writeObject( ). For DocumentDescription, we declare _actualDocument to be transient and then implement readObject( )and writeObject( ) as follows: private transient InputStream _actualDocument; private void writeObject(java.io.ObjectOutputStream out) throws IOException { out.defaultWriteObject( ); copy(_actualDocument, out); } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject( ); ByteArrayOutputStream temporaryBuffer = new ByteArrayOutputStream( ); copy(in, temporaryBuffer, _length); _actualDocument = new DataInputStream(new ByteArrayInputStream(temporaryBuffer.toByteArray( ))); } private void copy(InputStream source, OutputStream destination, int length) throws IOException { int counter; int nextByte; for (counter = 0; counter <length; counter++) { nextByte = source.read( ); destination.write(nextByte); } destination.flush( ); }
© Trendz Information Technologies Ltd. Page No. 119 of 220

J2EE

Note that we declare _actualDocument to be transient and call defaultWriteObject() in the first line of our writeObject() method. Doing these two things allows the standard serialization mechanism to serialize the other four instance variables without any extra effort on our part. We then simply copy _actualDocument to the stream. Our implementation of readObject() simply calls defaultReadObject() and then reads _actualDocument from the stream. In order to read _actualDocument from the stream, we used the length of the document, which had previously been written to the stream. In essence, we needed to encode some metadata into the stream, in order to correctly pull our data out of the stream. This code is a little ugly. We're using serialization, but we're still forced to think about how to encode some of our state when we're sending it out of the stream. In fact, the code for writeObject() and readObject() is remarkably similar to the marshalling code we implemented directly for the socket-based version of the printer server. This is, unfortunately, often the case. Serialization's default implementation handles simple objects very well. But, every now and then, you will want to send a nonserializable object over the wire, or improve the serialization algorithm for efficiency. Doing so amounts to writing the same code you write if you implement all the socket handling yourself, as in our socket-based version of the printer server. TIP: There is also an order dependency here. The first value written must be the first value read. Since we start writing by calling defaultWriteObject( ), we have to start reading by calling defaultReadObject( ). On the bright side, this means we'll have an accurate value for _length before we try to read _actualDocument from the stream. Make sure that Superclass state is handled correctly This isn't a problem. The superclass, java.lang.Object, doesn't actually have any important state that we need to worry about. Since it also already has a zeroargument constructor, we don't need to do anything. Override equals() and hashCode( ) if necessary In our current implementation of the printer server, we don't need to do this. The server never checks for equality between instances of DocumentDescription. Nor does it store them in a container object that relies on their hashcodes. Did We Cheat When Implementing Serializable for DocumentDescription? It may seem like we cheated a bit in implementing DocumentDescription. Three of the five steps in making a class serializable didn't actually result in changes to the code. Indeed, the only work we really did was implementing readObject( ) and writeObject( ). But it's not really cheating. Serialization is just designed to be easy to use. It has a good set of defaults, and, at least in the case of value objects intended to pass over the wire, the default behavior is often good enough. The Serialization Algorithm By now, you should have a pretty good feel for how the serialization mechanism works for individual classes. The next step in explaining serialization is to discuss the actual serialization algorithm in a little more detail. This discussion won't handle all the details of serialization (Though we'll come close). Instead, the idea is to cover
© Trendz Information Technologies Ltd. Page No. 120 of 220

J2EE the algorithm and protocol, so you can understand how the various hooks for customizing serialization work and how they fit into the context of an RMI application. The Data Format The first step is to discuss what gets written to the stream when an instance is serialized. Be warned: it's a lot more information than you might guess from the previous discussion. An important part of serialization involves writing out class-related metadata associated with an instance. Most instances are more than one class. For example, an instance of String is also an instance of Object. Any given instance, however, is an instance of only a few classes. These classes can be written as a sequence: C1, C2... CN, in which C1 is a superclass of C2, C2 is a superclass of C3, and so on. This is actually a linear sequence because Java is a single inheritance language for classes. We call C1the least superclass and CNthe most-derived class. See Figure 10-4.

Figure 10-4. Inheritance diagram After writing out the associated class information, the serialization mechanism stores out the following information for each instance: • • • A description of the most-derived class. Data associated with the instance, interpreted as an instance of the least superclass. Data associated with the instance, interpreted as an instance of the second least superclass.

And so on until: • Data associated with the instance, interpreted as an instance of the mostderived class. So what really happens is that the type of the instance is stored out, and then all the serializable state is stored in discrete chunks that correspond to the class structure. But there's a question still remaining: what do we mean by "a description of the most-derived class?" This is either a reference to a class description that has already been recorded (e.g., an earlier location in the stream) or the following information: • • The version ID of the class, which is an integer used to validate the. class files A boolean stating whether writeObject( )/ readObject( )are implemented
Page No. 121 of 220

© Trendz Information Technologies Ltd.

J2EE • • • • The number of serializable fields A description of each field (its name and type) Extra data produced by ObjectOutputStream's annotateClass( )method A description of its superclass if the superclass is serializable

This should, of course, immediately seem familiar. The class descriptions consist entirely of metadata that allows the instance to be read back in. In fact, this is one of the most beautiful aspects of serialization; the serialization mechanism automatically, at runtime, converts class objects into metadata so instances can be serialized with the least amount of programmer work. A Simplified Version of the Serialization Algorithm In this section, I describe a slightly simplified version of the serialization algorithm. I then proceed to a more complete description of the serialization process in the next section. Writing Because the class descriptions actually contain the metadata, the basic idea behind the serialization algorithm is pretty easy to describe. The only tricky part is handling circular references. The problem is this: suppose instance A refers to instance B. And instance B refers back to instance A. Completely writing out A requires you to write out B. But writing out B requires you to write out A. Because you don't want to get into an infinite loop, or even write out an instance or a class description more than once you need to keep track of what's already been written to the stream. (Serialization is a slow process that uses the reflection API quite heavily in addition to the bandwidth) ObjectOutputStream does this by maintaining a mapping from instances and classes to handles. When writeObject( ) is called with an argument that has already been written to the stream, the handle is written to the stream, and no further operations are necessary. If, however, writeObject( ) is passed an instance that has not yet been written to the stream, two things happen. First, the instance is assigned a reference handle, and the mapping from instance to reference handle is stored by ObjectOutputStream. The handle that is assigned is the next integer in a sequence. TIP: Remember the reset( ) method on ObjectOutputStream? It clears the mapping and resets the handle counter to 0x7E0000 .RMI also automatically resets its serialization mechanism after every remote method call. Second, the instance data is written out as per the data format described earlier. This can involve some complications if the instance has a field whose value is also a serializable instance. In this case, the serialization of the first instance is suspended, and the second instance is serialized in its place (or, if the second instance has already been serialized, the reference handle for the second instance is written out). After the second instance is fully serialized, serialization of the first instance resumes. The contents of the stream look a little bit like Figure 10-5.

© Trendz Information Technologies Ltd.

Page No. 122 of 220

J2EE

Figure 10-5. Contents of Serialization's data stream. Reading From the description of writing, it's pretty easy to guess most of what happens when readObject() is called. Unfortunately, because of versioning issues, the implementation of readObject( ) is actually a little bit more complex than you might guess. When it reads in an instance description, ObjectInputStream gets the following information: • • Descriptions of all the classes involved The serialization data from the instance

The problem is that the class descriptions that the instance of ObjectInputStream reads from the stream may not be equivalent to the class descriptions of the same classes in the local JVM. For example, if an instance is serialized to a file and then read back in three years later, there's a pretty good chance that the class definitions used to serialize the instance have changed. This means that ObjectInputStream uses the class descriptions in two ways: • • It uses them to actually pull data from the stream, since the class descriptions completely describe the contents of the stream. It compares the class descriptions to the classes it has locally and tries to determine if the classes have changed, in which case it throws an exception. If the class descriptions match the local classes, it creates the instance and sets the instance's state appropriately.

RMI Customizes the Serialization Algorithm RMI doesn't actually use ObjectOutputStream and ObjectInputStream. Instead, it uses custom subclasses so it can modify the serialization process by overriding some protected methods. In this section, we'll discuss the most important modifications that RMI makes when serializing instances. RMI makes similar changes when

© Trendz Information Technologies Ltd.

Page No. 123 of 220

J2EE deserializing instances, but they follow from, and can easily be deduced from, the description of the serialization changes. Recall that ObjectOutputStream contained the following protected methods: protected protected protected protected protected protected protected protected void annotateClass(Class cl) void annotateProxyClass(Class cl) boolean enableReplaceObject(boolean enable) Object replaceObject(Object obj) void drain( ) void writeObjectOverride(Object obj) void writeClassDescriptor(ObjectStreamClass classdesc) void writeStreamHeader( )

These all have default implementations in ObjectOutputStream. That is, annotateClass() and annotateProxyClass() do nothing. enableReplaceObject() returns false, and so on. However, these methods are still called during serialization. And RMI, by overriding these methods, customizes the serialization process. The three most important methods from the point of view of RMI are: protected void annotateClass(Class cl) protected boolean enableReplaceObject(boolean enable) protected Object replaceObject(Object obj) Let's describe how RMI overrides each of these. annotateClass( ) ObjectOutputStream calls annotateClass() when it writes out class descriptions. Annotations are used to provide extra information about a class that comes from the serialization mechanism and not from the class itself. The basic serialization mechanism has no real need for annotations; most of the information about a given class is already stored in the stream. TIP: RMI's dynamic classloading system uses annotateClass( ) to record where .class files are stored. We'll discuss this more in Chapter 19. RMI, on the other hand, uses annotations to record codebase information. That is, RMI, in addition to recording the class descriptions, also records information about the location from which it loaded the class's bytecode. Codebases are often simply locations in a file system. Incidentally, locations in a file system are often useless information, since the JVM that deserializes the instances may have a very different file system than the one from where the instances were serialized. However, codebase isn't restricted to being a location in a file system. The only restriction on codebases is that they have to be valid URLs. That is, codebase is a URL that specifies a location on the network from which the bytecode for a class can be obtained. This enables RMI to dynamically load new classes based on the serialized information in the stream.

© Trendz Information Technologies Ltd.

Page No. 124 of 220

J2EE

replaceObject( ) The idea of replacement is simple; sometimes the instance that is passed to the serialization mechanism isn't the instance that ought to be written out to the data stream. To make this more concrete, recall what happened when we called rebind( ) to register a server with the RMI registry. The following code was used in the bank example: Account_Impl newAccount = new Account_Impl(serverDescription.balance); Naming.rebind(serverDescription.name, newAccount); System.out.println("Account " + serverDescription.name + " successfully launched."); Account_Impl newAccount = new Account_Impl(serverDescription.balance); Naming.rebind(serverDescription.name, newAccount); System.out.println("Account " + serverDescription.name + " successfully launched."); This creates an instance of Account_Impl and then calls rebind( ) with that instance. Account_Impl is a server that implements the Remote interface, but not the Serializable interface. And yet, somehow, the registry, which is running in a different JVM, is sent something. What the registry actually gets is a stub. The stub for Account_Impl, which was automatically generated by rmic, begins with: public final class Account_Impl_Stub extends java.rmi.server.RemoteStub java.rmi.server.RemoteStub is a class that implements the Serializable interface. The RMI serialization mechanism knows that whenever a remote server is "sent" over the wire, the server object should be replaced by a stub that knows how to communicate with the server (e.g., a stub that knows on which machine and port the server is listening). Calling Naming.rebind( ) actually winds up passing a stub to the RMI registry. When clients make calls to Naming.lookup( ), as in the following code snippet, they also receive copies of the stub. Since the stub is serializable, there's no problem in making a copy of it: _account = (Account)Naming.lookup(_accountNameField.getText( )); In order to enable this behavior, ObjectOutputStreamcalls enableReplaceObject( ) and replaceObject( ) during the serialization process. In other words, when an instance is about to be serialized, ObjectOutputStreamdoes the following:

1. It calls enableReplaceObject( ) to see whether instance replacement is
enabled.

2. If instance replacement is enabled, it calls replaceObject( ), passing in the

instance it was about to serialize, to find out which instance it should really write to the stream. 3. It then writes the appropriate instance to the stream.
© Trendz Information Technologies Ltd. Page No. 125 of 220

J2EE

Maintaining Direct Connections A question that frequently arise as distributed applications get more complicated involves message forwarding. For example, suppose that we have three communicating programs: A, B, and C. At the start, A has a stub for B, B has a stub for C, and Chas a stub for A. See Figure 10-6.

Figure 10-6. Communication between three applications. Now, what happens if A calls a method, for example, getOtherServer( ), on B that "returns" C? The answer is that A gets a deep copy of the stub B uses to communicate with C. That is, A now has a direct connection to C; whenever A tries to send a message to C, B is not involved at all. This is illustrated in Figure 10-7.

Figure 10-7. Improved communication between three applications This is very good from a bandwidth and network latency point of view. But it can also be somewhat problematic. Suppose, for example, B implements load balancing. Since B isn't involved in the A to C communication, it has no direct way of knowing
© Trendz Information Technologies Ltd. Page No. 126 of 220

J2EE whether A is still using C, or how heavily. We'll revisit this in Chapters and, when we discuss the distributed garbage collector and the Unreferenced interface. Versioning Classes A few pages back, I described the serialization mechanism: The serialization mechanism automatically, at runtime, converts class objects into metadata so instances can be serialized with the least amount of programmer work. This is great as long as the classes don't change. When classes change, the metadata, which was created from obsolete class objects, accurately describes the serialized information. But it might not correspond to the current class implementations. The Two Types of Versioning Problems There are two basic types of versioning problems that can occur. The first occurs when a change is made to the class hierarchy (e.g., a superclass is added or removed). Suppose, for example, a personnel application made use of two serializable classes: Employee and Manager (a subclass of Employee). For the next version of the application, two more classes need to be added: Contractor and Consultant. After careful thought, the new hierarchy is based on the abstract superclass Person, which has two direct subclasses: Employee and Contractor. Consultant is defined as a subclass of Contractor, and Manager is a subclass of Employee. See Figure 10-8.

Figure 10-8. Changing the class hierarchy. While introducing Person is probably good object-oriented design, it breaks serialization. Recall that serialization relied on the class hierarchy to define the data format. The second type of version problem arises from local changes to a serializable class. Suppose, for example, that in our bank example, we want to add the possibility of handling different currencies. To do so, we define a new class, Currency, and change the definition of Money: public class Money extends ValueObject { public float amount; public Currency typeOfMoney; } This completely changes the definition of Money but doesn't change the object hierarchy at all. The important distinction between the two types of versioning problems is that the first type can't really be repaired. If you have old data lying around that was

© Trendz Information Technologies Ltd.

Page No. 127 of 220

J2EE serialized using an older class hierarchy, and you need to use that data, your best option is probably something along the lines of the following: 1. Using the old class definitions, write an application that deserializes the data into instances and writes the instance data out in a neutral format, say as tab-delimited columns of text. 2. Using the new class definitions, write a program that reads in the neutralformat data, creates instances of the new classes, and serializes these new instances. The second type of versioning problem, on the other hand, can be handled locally, within the class definition. How Serialization detects when a Class has changed In order for serialization to gracefully detect when a versioning problem has occurred, it needs to be able to detect when a class has changed. As with all the other aspects of serialization, there is a default way that serialization does this. And there is a way for you to override the default. The default involves a hashcode. Serialization creates a single hashcode, of type long, from the following information: • • • • The class name and modifiers The names of any interfaces the class implements Descriptions of all methods and constructors except private methods and constructors Descriptions of all fields except private, static, and private transient

This single long, called the class's stream unique identifier (often abbreviated suid), is used to detect when a class changes. It is an extraordinarily sensitive index. For example, suppose we add the following method to Money: public boolean isBigBucks( ) { return _cents > 5000; } We haven't changed, added, or removed any fields; we've simply added a method with no side effects at all. But adding this method changes the suid. Prior to adding it, the suid was 6625436957363978372L; afterwards, it was -3144267589449789474L. Moreover, if we had made isBigBucks( ) a protected method, the suid would have been 4747443272709729176L. TIP: These numbers can be computed using the serialVer program that ships with the JDK. For example, these were all computed by typing serialVer com.ora.rmibook.chapter10.Money at the command line for slightly different versions of the Money class. The default behavior for the serialization mechanism is a classic "better safe than sorry" strategy. The serialization mechanism uses the suid, which defaults to an extremely sensitive index, to tell when a class has changed. If so, the serialization mechanism refuses to create instances of the new class using data that was serialized with the old classes.
© Trendz Information Technologies Ltd. Page No. 128 of 220

J2EE

Implementing Your Own Versioning Scheme While this is reasonable as a default strategy, it would be painful if serialization didn't provide a way to override the default behavior. Fortunately, it does. Serialization uses only the default suid if a class definition doesn't provide one. That is, if a class definition includes a static final long named serialVersionUID, then serialization will use that static final long value as the suid. In the case of our Money example, if we included the line: private static final long serialVersionUID = 1; in our source code, then the suid would be 1, no matter how many changes we made to the rest of the class. Explicitly declaring serialVersionUID allows us to change the class, and add convenience methods such as isBigBucks( ), without losing backwards compatibility. TIP: serialVersionUID doesn't have to be private. However, it must be static, final, and long. The downside to using serialVersionUID is that, if a significant change is made (for example, if a field is added to the class definition), the suid will not reflect this difference. This means that the deserialization code might not detect an incompatible version of a class. Again, using Money as an example, suppose we had: public class Money extends ValueObject { private static final long serialVersionUID = 1; protected int _cents; and we migrated to: public class Money extends ValueObject { private static final long serialVersionUID = 1; public float amount; public Currency typeOfMoney; } The serialization mechanism won't detect that these are completely incompatible classes. Instead, when it tries to create the new instance, it will throw away all the data it reads in. Recall that, as part of the metadata, the serialization algorithm records the name and type of each field. Since it can't find the fields during deserialization, it simply discards the information. The solution to this problem is to implement your own versioning inside of readObject( ) and writeObject( ). The first line in your writeObject( ) method should begin: private void writeObject(java.io.ObjectOutputStream out) throws IOException { stream.writeInt(VERSION_NUMBER); .... }

In addition, your readObject( ) code should start with a switch statement based on the version number:
© Trendz Information Technologies Ltd. Page No. 129 of 220

J2EE

private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { int version = in.readInt( ); switch(version) { // version specific demarshalling code. ....} }private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { int version = in.readInt( ); switch(version) { // version specific demarshalling code. ....} } Doing this will enable you to explicitly control the versioning of your class. In addition to the added control you gain over the serialization process, there is an important consequence you ought to consider before doing this. As soon as you start to explicitly version your classes, defaultWriteObject( ) and defaultReadObject( ) lose a lot of their usefulness. Trying to control versioning puts you in the position of explicitly writing all the marshalling and demarshalling code. This is a trade-off you might not want to make. Performance Issues Serialization is a generic marshalling and demarshalling algorithm, with many hooks for customization. As an experienced programmer, you should be skeptical--generic algorithms with many hooks for customization tends to be slow. Serialization is not an exception to this rule. It is, at times, both slow and bandwidth-intensive. There are three main performance problems with serialization: it depends on reflection, it has an incredibly verbose data format, and it is very easy to send more data than is required. Serialization Depends on Reflection The dependence on reflection is the hardest of these to eliminate. Both serializing and deserializing require the serialization mechanism to discover information about the instance it is serializing. At a minimum, the serialization algorithm needs to find out things such as the value of serialVersionUID, whether writeObject( ) is implemented, and what the superclass structure is. What's more, using the default serialization mechanism, (or calling defaultWriteObject( ) from within writeObject( )) will use reflection to discover all the field values. This can be quite slow. TIP: Setting serialVersionUID is a simple, and often surprisingly noticeable, performance improvement. If you don't set serialVersionUID, the serialization mechanism has to compute it. This involves going through all the fields and methods and computing a hash. If you set serialVersionUID, on the other hand, the serialization mechanism simply looks up a single value.

© Trendz Information Technologies Ltd.

Page No. 130 of 220

J2EE

Serialization Has a Verbose Data Format Serialization's data format has two problems. The first is all the class description information included in the stream. To send a single instance of Money, we need to send all of the following: • • • The description of the ValueObject class The description of the Money class The instance data associated with the specific instance of Money.

This isn't a lot of information, but it's information that RMI computes and sends with every method invocation. (Recall that RMI resets the serialization mechanism with every method call.) Even if the first two bullets comprise only 100 extra bytes of information, the cumulative impact is probably significant. The second problem is that each serialized instance is treated as an individual unit. If we are sending large numbers of instances within a single method invocation, then there is a fairly good chance that we could compress the data by noticing commonalities across the instances being sent. It is easy to send more data than is required Serialization is a recursive algorithm. You pass in a single object, and all the objects that can be reached from that object by following instance variables, are also serialized. To see why this can cause problems, suppose we have a simple application that uses the Employee class: public public public Public } class Employee implements Serializable { String firstName; String lastName; String socialSecurityNumber;

In a later version of the application, someone adds a new piece of functionality. As part of doing so, they add a single additional field to Employee: public public public Public Public } class Employee implements Serializable { String firstName; String lastName; String socialSecurityNumber; Employee manager;

What happens as a result of this? On the bright side, the application still works. After everything is recompiled, the entire application, including the remote method invocations, will still work. That's the nice aspect of serialization--we added new fields, and the data format used to send arguments over the wire automatically adapted to handle our changes. We didn't have to do any work at all. On the other hand, adding a new field redefined the data format associated with Employee. Because serialVersionUID wasn't defined in the first version of the class, none of the old data can be read back in anymore. And there's an even more serious
© Trendz Information Technologies Ltd. Page No. 131 of 220

J2EE problem: we've just dramatically increased the bandwidth required by remote method calls. Suppose Bob works in the mailroom. And we serialize the object associated with Bob. In the old version of our application, the data for serialization consisted of: • • The class information for Employee The instance data for Bob

In the new version, we send: • The class information for Employee • The instance data for Bob • The instance data for Sally (who runs the mailroom and is Bob's manager) • The instance data for Henry (who is in charge of building facilities) • The instance data for Alison (Director, Corporate Infrastructure) • The instance data for Mary (VP in charge of IT) And so on... The new version of the application isn't backwards-compatible because our old data can't be read by the new version of the application. In addition, it's slower and is much more likely to cause network congestion. The Externalizable Interface To solve the performance problems associated with making a class Serializable, the serialization mechanism allows you to declare that a class is Externalizable instead. When ObjectOutputStream's writeObject() method is called, it performs the following sequence of actions:

1. It tests to see if the object is an instance of Externalizable. If so, it uses 2. If the object isn't an instance of Externalizable, it tests to see whether the
externalization to marshall the object. object is an instance of Serializable. If so, it uses serialization to marshall the object. 3. If neither of these two cases applies, an exception is thrown. Externalizableis an interface that consists of two methods: public void readExternal(ObjectInput in); public void writeExternal(ObjectOutput out); These have roughly the same role that readObject() and writeObject( ) have for serialization. There are, however, some very important differences. The first, and most obvious, is that readExternal( ) and writeExternal( ) are part of the Externalizableinterface. An object cannot be declared to be Externalizablewithout implementing these methods. However, the major difference lies in how these methods are used. The serialization mechanism always writes out class descriptions of all the serializable superclasses. And it always writes out the information associated with the instance when viewed as an instance of each individual superclasses.

© Trendz Information Technologies Ltd.

Page No. 132 of 220

J2EE Externalization gets rid of some of this. It writes out the identity of the class (which boils down to the name of the class and the appropriate serialVersionUID). It also stores the superclass structure and all the information about the class hierarchy. But instead of visiting each superclass and using that superclass to store some of the state information, it simply calls writeExternal( ) on the local class definition. In a nutshell: it stores all the metadata, but writes out only the local instance information. TIP: This is true even if the superclass implements Serializable. The metadata about the class structure will be written to the stream, but the serialization mechanism will not be invoked. This can be useful if, for some reason, you want to avoid using serialization with the superclass. For example, some of the Swing classes, while they claim to implement Serializable, do so incorrectly (and will throw exceptions during the serialization process). (JTextAreais one of the most egregious offenders.) If you really need to use these classes, and you think serialization would be useful, you may want to think about creating a subclass and declaring it to be Externalizable. Instances of your class will be written out and read in using externalization. Because the superclass is never serialized or deserialized, the incorrect code is never invoked, and the exceptions are never thrown. Comparing Externalizable to Serializable Of course, this efficiency comes at a price. Serializable can be frequently implemented by doing two things: declaring that a class implements the Serializableinterface and adding a zero-argument constructor to the class. Furthermore, as an application evolves, the serialization mechanism automatically adapts. Because the metadata is automatically extracted from the class definitions, application programmers often don't have to do anything except recompile the program. On the other hand, Externalizable isn't particularly easy to do, isn't very flexible, and requires you to rewrite your marshalling and demarshalling code whenever you change your class definitions. However, because it eliminates almost all the reflective calls used by the serialization mechanism and gives you complete control over the marshalling and demarshalling algorithms, it can result in dramatic performance improvements. To demonstrate this, I have defined the EfficientMoney class. It has the same fields and functionality as Money but implements Externalizable instead of Serializable: public class EfficientMoney extends ValueObject implements Externalizable { public static final long serialVersionUID = 1; protected int _cents; public EfficientMoney(Integer cents) { this(cents.intValue( )); } public EfficientMoney(int cents) { super(cents + " cents."); _cents = cents; }
© Trendz Information Technologies Ltd. Page No. 133 of 220

J2EE

public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { _cents = in.readInt( ); _stringifiedRepresentation = _cents + " cents."; } public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(_cents); } } We now want to compare Money with EfficientMoney. We'll do so using the following application: public class MoneyWriter { public static void main(String[] args) { writeOne( ); writeMany( ); } private static void writeOne( ) { try { System.out.println("Writing one instance"); Money money = new Money(1000); writeObject("C:\\temp\\foo", money); } catch(Exception e){} } private static void writeMany( ) { try { System.out.println("Writing many instances"); ArrayList listOfMoney = new ArrayList( ); for (int i=0; i<10000; i++) { Money money = new Money(i*100); listOfMoney.add(money); } writeObject("C:\\temp\\foo2", listOfMoney); } catch(Exception e){} } private static void writeObject(String filename, Object object) throws Exception { FileOutputStream fileOutputStream = new FileOutputStream(filename); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); long startTime = System.currentTimeMillis( ); objectOutputStream.writeObject(object); objectOutputStream.flush( ); objectOutputStream.close( ); System.out.println("Time: " + (System.currentTimeMillis( ) - startTime));
© Trendz Information Technologies Ltd. Page No. 134 of 220

J2EE } } On my home machine, averaging over 10 trial runs for both Money and EfficientMoney, I get the results shown in Table 10-1. (We need to average because the elapsed time can vary (it depends on what else the computer is doing). The size of the file is, of course, constant.) Table 10-1: Testing Money and Efficient Money Class Money Money EfficientMoney EfficientMoney Number of instances 1 10,000 1 10,000 File size 266 bytes 309 KB 199 bytes 130 KB Elapsed time 60 milliseconds 995 milliseconds 50 milliseconds 907 milliseconds

These results are fairly impressive. By simply converting a leaf class in our hierarchy to use externalization, I save 67 bytes and 10 milliseconds when serializing a single instance. In addition, as I pass larger data sets over the wire, I save more and more bandwidth--on average, 18 bytes per instance. TIP: Which numbers should we pay attention to? The single-instance costs or the 10,000-instance costs? For most applications, the singleinstance cost is the most important one. A typical remote method call involves sending three or four arguments (usually of different types) and getting back a single return value. Since RMI clears the serialization mechanism between calls, a typical remote method call looks a lot more like serializing 3 or 4 single instances than serializing 10,000 instances of the same class. If I need more efficiency, I can go further and remove ValueObject from the hierarchy entirely. The ReallyEfficientMoney class directly extends Object and implements Externalizable: public class ReallyEfficientMoney implements Externalizable { public static final long serialVersionUID = 1; protected int _cents; protected String _stringifiedRepresentation; public ReallyEfficientMoney(Integer cents) { this(cents.intValue( )); } public ReallyEfficientMoney(int cents) { _cents = cents; _stringifiedRepresentation = _cents + " cents."; }

© Trendz Information Technologies Ltd.

Page No. 135 of 220

J2EE public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { _cents = in.readInt( ); _stringifiedRepresentation = _cents + " cents."; } public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(_cents); } } ReallyEfficientMoney has much better performance than either Money or EfficientMoney when a single instance is serialized but is almost identical to EfficientMoney for large data sets. Again, averaging over 10 iterations, I record the numbers in Table 10-2. Table 10-2: Testing ReallyEfficientMoney Class ReallyEfficientMoney ReallyEfficientMoney Number of instances 1 10,000 File size 74 bytes 127 KB Elapsed time 20 milliseconds 927 milliseconds

Compared to Money, this is quite impressive; I've shaved almost 200 bytes of bandwidth and saved 40 milliseconds for the typical remote method call. The downside is that I've had to abandon my object hierarchy completely to do so; a significant percentage of the savings resulted from not including ValueObject in the inheritance chain. Removing superclasses makes code harder to maintain and forces programmers to implement the same method many times (ReallyEfficientMoney can't use ValueObject's implementation of equals( ) and hashCode( ) anymore). But it does lead to significant performance improvements.

© Trendz Information Technologies Ltd.

Page No. 136 of 220

J2EE

JAVA MAIL The design of the Java Mail API is a good example of Sun's continuing efforts to provide common API frameworks for the Java development community. Emphasizing these common frameworks, as opposed to vendor-specific solutions, bodes well for the creation of an increasingly open development environment. On the e-mail messaging front, higher level (consumer) developers can shop around for the implementation of the common API framework that best fits their needs -- or even support multiple implementations simultaneously. Lower level implementation providers can develop solutions that ensure efficient access to their mail server products. As an example of what this means, a small startup company can concentrate on developing that killer mail client and be assured of easily supporting it for any mail system environment. And the bluechip IT giant can focus on providing widespread access to its newly developed industrial-strength mail services, assured of a rich wealth of application support. The big winners are the IS customers, who can mix and match the best vendor products or solutions to develop their systems yet still swap components as requirements dictate (whether these be performance, financial, or political). One key to developing highly reusable and open API frameworks is to emphasize abstract interfaces in a way that supports existing standards but does not limit future enhancements or alternative implementations. The Java Mail API does just that! Furthermore, Sun is also rapidly developing -- or providing through third parties -default implementations and utilities for the most commonly available protocols and standards. For example, default implementations such as POP3, SMTP, and IMAP protocol servers are currently available, so you can start developing that awardwinning killer app now without having to reinvent the protocol wheel unless you want to (or really need to).
A close-up looks at the Java Mail API

The layout of packages and classes in the Java Mail API demonstrates one of the primary goals of its designers -- that the level of effort required by the developer to build an application should be dictated by the complexity of the application and level of control required by the developer for the application. In other words, keep the API as simple as possible. The example application included in this article and the examples that ship with the Java Mail API amply demonstrate this point. On first glance, the number of Java Mail API classes and the detailed layout of these classes may cause you to believe you're in for a heavy learning curve. But in reality, once you get working, you'll find that this API is a simple and handy tool for implementing robust mail/messaging functionality in your applications. Analysis of the primary Java Mail API package classes provides insight into the common mechanics of e-mail messaging systems. A high-level overview of the classes in the relative order in which they are normally encountered in a typical application reveals the simplicity of the Java Mail API. Although the Java Mail API contains many more classes than those discussed here, concentrating on some of the core classes to start with makes it easy to understand
© Trendz Information Technologies Ltd. Page No. 137 of 220

J2EE the essence of the API. The following is a detailed description of these core classes, which include javax.mail.Session, javax.mail.Store, javax.mail.Transport, javax.mail.Folder, and javax.mail.Message.
javax.mail.Session

The javax.mail.Session class is the top-level entry class for the Java Mail API, and its most commonly used methods provide the ability to control and load the classes that represent the service provider implementations (SPI) for various mail protocols. For example, instances of the javax.mail.Store and javax.mail.Session classes -described below -- are obtained via the Session class. (Note: A service provider is a developer and/or vendor that provides an implementation for an API; examples of Java Mail API implementations include POP3, SMTP, and IMAP4 -- some are available from Sun, others via third parties.)
javax.mail.Store

The javax.mail.Store class is implemented by a service provider, such as a POP Mail implementation developer, and allows for read, write, monitor, and search access for a particular mail protocol. The javax.mail.Folder class is accessed through this class and is detailed below.
javax.mail.Transport

The javax.mail.Transport class is another provider-implemented class and is used for sending a message over a specific protocol.
javax.mail.Folder

The javax.mail.Folder class is implemented by a provider; it gives hierarchical organization to mail messages and provides access to e-mail messages in the form of javax.mail.Message class objects.
javax.mail.Message

The javax.mail.Message class is implemented by a provider and models all the details of an actual e-mail message, such as the subject line, sender/recipient e-mail address, sent date, and so on. The guidelines for providers who implement the javax.mail.Message dictate that the actual fetching of e-mail message components should be delayed as long as possible in order to make this class as lightweight as possible.
The Java Mail API and JAF

One design fact worth mentioning is that the Java Mail API is tied to, or rather leverages, another Java extension: the Java Activation Framework (JAF). The JAF is intended to unify the manner of working with the multitude of data formats that are available, whether they be simple text or extremely complex documents composed of images, audio, video, and even "live" objects. In this sense, it might be useful to think of the JAF as providing for Java what plug-ins provide to a Web browser. (See this month's article on the Java Plug-in.)
A sample Java Mail application

A "list server application" serves as the focal point for a distributed group discussion system based on e-mail. As such, it is a very common and useful way for subscribers to discuss common-interest subjects. The following Java Mail API-based application is a working example of a useful middle-tier list server application. The Java Mail API makes this application easy to create (using the default POP3 and SMTP implementations) and ensures that it will easily support any provider-implemented systems that should arise. For example, the
© Trendz Information Technologies Ltd. Page No. 138 of 220

J2EE current application easily supports POP3, SMTP, and IMAP servers, and adding support for Lotus e-mail, say, would be as simple as plugging in an implementation from IBM and abstracting any hard coded references to protocols. Running the ListServer application is very simple. Just remember to include the JAR files for Java Mail, JAF, and the default POP3 implementation in the CLASSPATH, as shown in the following MS-DOS batch file example. (You can obtain these JAR files from the Java Mail home page link provided in the Resources section at the end of this article.) @echo off PATH .;d:\jdk1.1\bin set CLASSPATH=.;d:\jdk1.1\lib\classes.zip;activation.jar;mail.jar;pop3.jar java ListServer %1 %2 %3 %4 %5 %6 %7 %8 %9 Upon starting, the ListServer main() routine will read in the settings, including the appropriate mail servers, mail accounts, and update frequency. Next, an instance of a ListServer is instantiated and created, and the program enters an infinite loop of processing new messages and sleeping, until it is time to check for messages again. The use of java.lang.Properties throughout the application is worth pointing out: properties are used as a way to implicitly control the behavior of some Java Mail API methods. It should be noted that sometimes the implicit property arguments could be overridden by explicit arguments. The disadvantages of allowing implicit property argument behavior versus explicit argument behavior is (hopefully) more than balanced by the increased standardization of how applications, and especially applets, are configured without modifying Java source code. The heart of this ListServer program occurs in the process() routine, which directs the reading and broadcasting of all new messages. The significant Java Mail APIspecific code snippets in the method process() perform the following actions: • • • • Obtains a javax.mail.Session instance, which is used to obtain an instance of a javax.mail.Store instance Uses the javax.mail.Store instance to obtain the default INBOX javax.mail.Folder instance Uses the javax.mail.Folder object to fetch the array of new messages in an array of javax.mail.Message objects Creates a javax.mail.FetchProfile to (potentially) optimize the retrieval of specific message components

The use of the javax.mail.FetchProfile class is also interesting from a design-andimplementation perspective. The FetchProfile class provides the option for Java Mail protocol providers to support more efficient prefetching of Message components. The design of the Java Mail API encourages the retrieval of Message components to be delayed as long as possible (that is, until actually used). While this improves response times, certain operations, such as displaying a list of message subjects, also benefit from the FetchProfile class. The following code illustrates the use of FetchProfile when fetching Messages from a Folder: // Get attributes & flags for all messages // Message[] messages = folder.getMessages();
© Trendz Information Technologies Ltd. Page No. 139 of 220

J2EE FetchProfile fp = new FetchProfile(); fp.add(FetchProfile.Item.ENVELOPE); fp.add(FetchProfile.Item.FLAGS); fp.add("X-Mailer"); folder.fetch(messages, fp); The sendMsg() routine is called by processMsg(), and is responsible for calling routines to fully read and then broadcast a message. The first step is to set up and retrieve the default session so that the javax.mail.Transport object that is retrieved has the correct protocol and host: // create some properties and get the default Session // Properties props = new Properties(); props.put("mail.smtp.host", _smtpHost); Session session = Session.getDefaultInstance(props, null); …. …. ….

// Send newMessage // Transport transport = session.getTransport(SMTP_MAIL); transport.connect(_smtpHost, _user, _password); transport.sendMessage(newMessage, _toList);

The code for setting up the message fields such as to, from, subject, and date is very simple: // create a message // Address replyToList[] = { new InternetAddress(replyTo) }; Message newMessage = new MimeMessage(session); if (_fromName != null) newMessage.setFrom(new InternetAddress(from, _fromName + " on behalf of " + replyTo)); else newMessage.setFrom(new InternetAddress(from)); newMessage.setReplyTo(replyToList); newMessage.setRecipients(Message.RecipientType.BCC, _toList); newMessage.setSubject(subject); newMessage.setSentDate(sentDate); Setting the contents of the message requires reading in the desired contents and then calling the appropriate setContents...() routine as follows: // Set message contents // Object content = message.getContent(); String debugText = "Subject: " + subject + ", Sent date: " + sentDate; if (content instanceof Multipart) { debugMsg("Sending Multipart message (" + debugText + ")"); newMessage.setContent((Multipart)message.getContent());
© Trendz Information Technologies Ltd. Page No. 140 of 220

J2EE } else { debugMsg("Sending Text message (" + debugText + ")"); newMessage.setText((String)content); } The javax.mail.internet.MimeMessage content-reading routines are notable for their ability to read in complex, multipart, hierarchical messages with one simple call, as in the getContent() example above. The source code for ListServer is very basic but provides a fully functional list server. Furthermore, this basic list server can easily be enhanced by adding features such as automatic subscribe and unsubscribe.

© Trendz Information Technologies Ltd.

Page No. 141 of 220

J2EE ENTERPRISE JAVA BEANS Overview The Enterprise JavaBeans™ (EJB) specification defines an architecture for the development and deployment of transactional, distributed object applications-based, server-side software components. Organizations can build their own components or purchase components from third-party vendors. These server-side components, called enterprise beans, are distributed objects that are hosted in Enterprise JavaBean containers and provide remote services for clients distributed throughout the network. Enterprise JavaBeans Technology The Enterprise JavaBeans specification defines an architecture for a transactional, distributed object system based on components. The specification mandates a programming model; that is, conventions or protocols and a set of classes and interfaces, which make up the EJB API. The EJB programming model provides bean developers and EJB server vendors with a set of contracts that defines a common platform for development. The goal of these contracts is to ensure portability across vendors while supporting a rich set of functionality. The EJB Container Enterprise beans are software components that run in a special environment called an EJB container. The container hosts and manages an enterprise bean in the same manner that the Java Web Server hosts a Servlet or an HTML browser hosts a Java applet. An enterprise bean cannot function outside of an EJB container. The EJB container manages every aspect of an enterprise bean at run time including remote access to the bean, security, persistence, transactions, concurrency, and access to and pooling of resources. The container isolates the enterprise bean from direct access by client applications. When a client application invokes a remote method on an enterprise bean, the container first intercepts the invocation to ensure persistence, transactions, and security are applied properly to every operation a client performs on the bean. The container manages security, transactions, and persistence automatically for the bean, so the bean developer doesn't have to write this type of logic into the bean code itself. The enterprise bean developer can focus on encapsulating business rules, while the container takes care of everything else.

© Trendz Information Technologies Ltd.

Page No. 142 of 220

J2EE

Containers will manage many beans simultaneously in the same fashion that the Java WebServer manages many Servlets. To reduce memory consumption and processing, containers pool resources and manage the lifecycles of all the beans very carefully. When a bean is not being used, a container will place it in a pool to be reused by another client, or possibly evict it from memory and only bring it back when its needed. Because client applications don't have direct access to the beans -the container lies between the client and bean -- the client application is completely unaware of the containers resource management activities. A bean that is not in use, for example, might be evicted from memory on the server, while its remote reference on the client remains intact. When the client invokes a method on the remote reference, the container simply re-incarnates the bean to service the request. The client application is unaware of the entire process. An enterprise bean depends on the container for everything it needs. If an enterprise bean needs to access a JDBC connection or another enterprise bean, it does so through the container; if an enterprise bean needs to access the identity of its caller, obtain a reference to itself, or access properties it does so through the container. The enterprise bean interacts with its container through one of three mechanisms: callback methods, the EJBContext interface, or JNDI. •
Callback Methods

Every bean implements a subtype of the EnterpriseBean interface which defines several methods, called callback methods. Each callback method alerts the bean of a different event in its lifecycle and the container will invoke these methods to notify the bean when it's about to pool the bean, persist its state to the database, end a transaction, remove the bean from memory, etc. The callback methods give the bean a chance to do some housework immediately before or after some event. Callback methods are discussed in more detail in later sections. •
EJBContext
Page No. 143 of 220

© Trendz Information Technologies Ltd.

J2EE Every bean obtains an EJBContext object, which is a reference directly to the container. The EJBContext interface provides methods for interacting with the container so that that bean can request information about its environment like the identity of its client, the status of a transaction, or to obtain remote references to itself. •
Java Naming and Directory Interface

Java Naming and Directory Interface (JNDI) is a standard extension to the Java platform for accessing naming systems like LDAP, NetWare, file systems, etc. Every bean automatically has access to a special naming system called the Environment Naming Context (ENC). The ENC is managed by the container and accessed by beans using JNDI. The JNDI ENC allows a bean to access resources like JDBC connections, other enterprise beans, and properties specific to that bean. The EJB specification defines a bean-container contract, which includes the mechanisms (callbacks, EJBContext, JNDI ENC) described above as well as a strict set of rules that describe how enterprise beans and their containers will behave at runtime, how security access is checked, how transactions are managed, how persistence is applied, etc. The bean-container contract is designed to make enterprise beans portable between EJB containers so that enterprise beans can be developed once then run in any EJB container. Vendors like BEA, IBM, and GemStone sell application servers that include EJB containers. Ideally, any enterprise bean that conforms to the specification should be able to run in any conformant EJB container. Portability is central to the value that EJB brings to the table. Portability ensures that a bean developed for one container can be migrated to another if another brand offers more performance, features, or savings. Portability also means that the bean developer's skills can be leveraged across several EJB container brands, providing organizations and developers with better opportunities. In addition to portability, the simplicity of the EJB programming model makes EJB valuable. Because the container takes care of managing complex tasks like security, transactions, persistence, concurrency and resource management the bean developer is free to focus attention on business rules and a very simple programming model. A simple programming model means that beans can be developed faster without requiring a Ph.D. in distributed objects, transactions and other enterprise systems. EJB brings transaction processing and distributed objects development into the mainstream. Enterprise Beans To create an EJB server-side component, an enterprise bean developer provides two interfaces that define a bean's business methods, plus the actual bean implementation class. The client then uses a bean's public interfaces to create, manipulate, and remove beans from the EJB server. The implementation class, to be called the bean class, is instantiated at run time and becomes a distributed object. Enterprise beans live in an EJB container and are accessed by client applications over the network through their remote and home interfaces. The remote and home interfaces expose the capabilities of the bean and provide all the method needed to create, update, interact with, and delete the bean. A bean is a server-side component that represents a business concept like a Customer or a Hotel Clerk.

© Trendz Information Technologies Ltd.

Page No. 144 of 220

J2EE

Remote and Home Interfaces The Remote and Home interfaces represent the bean, but the container insulates the beans from direct access from client applications. Every time a bean is requested, created, or deleted, the container manages the whole process. The Home interface represents the life-cycle methods of the component (create, destroy, find) while the remote interface represents the business method of the bean. The Remote and Home interfaces extend the javax.ejb.EJBObject and javax.ejb.EJBHome interfaces respectively. These EJB interface types define a standard set of utility methods and provide common base types for all remote and home interfaces.

© Trendz Information Technologies Ltd.

Page No. 145 of 220

J2EE

Clients use the bean's home interface to obtain references to the bean's remote interface. The remote interface defines the business methods like accessor and mutator for changing a Customer's name, or business methods that perform tasks like using the HotelClerk bean to reserve a room at a hotel. Below is an example of how a Customer bean might be accessed from a client application. In this case the home interface is the CustomerHome type and the remote interface is the Customer type. CustomerHome home = // ... obtain a reference that // implements the home interface. // Use the home interface to create a // new instance of the Customer bean. Customer customer = home.create(customerID); // using a business method on the Customer. customer.setName(someName); The remote interface defines the business methods of a bean; the methods that are specific to the business concept it represents. Remote interfaces are subclassed from the javax.ejb.EJBObject interface, which is a subclass of the java.rmi.Remote interface. The importance of the remote interfaces inheritance hierarchy is discussed later. Now
© Trendz Information Technologies Ltd. Page No. 146 of 220

J2EE focus on the business methods and their meaning. Below is the definition of a remote interface for a Customer bean. import javax.ejb.EJBObject; import java.rmi.RemoteException; public interface Customer extends EJBObject { public public public public } The remote interface defines accessor and mutator methods to read and update information about a business concept. This is typical of a type of bean called an entity bean, which represents a persistent business object; business objects whose data is stored in a database. Entity beans represent business data in the database and add behavior specific to that data. Business Methods Business methods can also represent tasks that a bean performs. Although entity beans often have task-oriented methods, tasks are more typical of a type of bean called a session bean. Session beans do not represent data like entity beans. They represent business processes or agents that perform a service, like making a reservation at a hotel. Below is the definition of the remote interface for a HotelClerk bean, which is a type of session bean. import javax.ejb.EJBObject; import java.rmi.RemoteException; public interface HotelClerk extends EJBObject { public void reserveRoom(Customer cust, RoomInfo ri, Date from, Date to) throws RemoteException; public RoomInfo availableRooms(Location loc, Date from, Date to) throws RemoteException; } The business methods defined in the HotelClerk remote interface represent processes rather than simple accessors. The HotelClerk bean acts as an agent in the sense that it performs tasks on behalf of the user, but is not itself persistent in the database. You don't need information about the HotelClerk, you need the hotel clerk to perform tasks for you. This is typical behavior for a session bean. There are two basic types of enterprise beans: entity beans, which represent data in a database, and session beans, which represent processes or act as agents performing tasks. As you build an EJB application you will create many enterprise beans, each representing a different business concept. Each business concept will be Name getName() throws RemoteException; void setName(Name name) throws RemoteException; Address getAddress() throws RemoteException; void setAddress(Address address) throws RemoteException;

© Trendz Information Technologies Ltd.

Page No. 147 of 220

J2EE manifested as either an entity bean or a session bean. You will choose which type of bean a business concept becomes based on how it is intended to be used. Entity Beans For every remote interface there is an implementation class; a business object that actually implements the business methods defined in the remote interface. This is the bean class; the key element of the bean. Below is a partial definition of the Customer bean class. import javax.ejb.EntityBean; public class CustomerBean implements EntityBean { Address myAddress; Name myName; CreditCard myCreditCard; public Name getName() { return myName; } public void setName(Name name) { myName = name; } public Address getAddress() { return myAddress; } public void setAddress(Address address) { myAddress = address; } ... }
CustomerBean is the implementation class. It holds the data and provides accessor

methods and other business methods. As an entity bean, the CustomerBean provides an object view of customer data. Instead of writing database access logic in an application, the application can simply use the remote interface to the Customer bean to access customer data. Entity beans implement the javax.ejb.EntityBean type, which defines a set of notification methods that the bean uses to interact with its container. These notification methods are examined in detail later in this course.

© Trendz Information Technologies Ltd.

Page No. 148 of 220

J2EE

Session Beans The HotelClerk bean is a session bean, which is similar in many respects to an entity bean. Session beans represent a set of processes or tasks, which are performed on behalf of the client application. Session beans may use other beans to perform a task or access the database directly. A little bit of code shows a session bean doing both. The reserveRoom() method shown below uses several other beans to a accomplish a task, while the availableRooms() method uses JDBC to access the database directly. import javax.ejb.SessionBean; public class HotelClerkBean implements SessionBean { public void reserveRoom(Customer cust, RoomInfo ri, Date from, Date to) { CreditCard card = cust.getCreditCard(); RoomHome roomHome = // ... get home reference Room room = roomHome.findByPrimaryKey(ri.getID()); double amount = room.getPrice(from,to); CreditServiceHome creditHome = // ... get home reference CreditService creditAgent = creditHome.create(); creditAgent.verify(card, amount); ReservationHome resHome = // ... get home reference Reservation reservation = resHome.create(cust,room,from,to); } public RoomInfo[] availableRooms(Location loc, Date from, Date to) { // Make an SQL call to find available rooms Connection con = // ... get database connection
© Trendz Information Technologies Ltd. Page No. 149 of 220

J2EE Statement stmt = con.createStatement(); ResultSet results = stmt.executeQuery("SELECT ..."); ... return roomInfoArray; } }

You may have noticed that the bean classes defined above do not implement the remote or home interfaces. EJB doesn't require that the bean class implement these interfaces; in fact it's discouraged because the base types of the remote and home interfaces (EJBObject and EJBHome) define a lot of other methods that are implemented by the container automatically. The bean class does however provide implementations for all the business methods defined in the remote interface as well as methods. Callback methods are discussed in more detail below. Life Cycle Methods In addition to a remote interface, all beans have a home interface. The home interface provides life cycle methods for creating, destroying, and locating beans. These life cycle behaviors are separated out of the remote interface because they represent behaviors that are not specific to a single bean instance. Below is the definition of the home interface for the Customer bean. Notice that it extends the javax.ejb.EJBHome interface, which extends the java.rmi.Remote interface. import import import import javax.ejb.EJBHome; javax.ejb.CreateException; javax.ejb.FinderException; java.rmi.RemoteException;

public interface CustomerHome extends EJBHome { public Customer create(Integer customerNumber) throws RemoteException, CreateException; public Customer findByPrimaryKey(Integer customerNumber) throws RemoteException, FinderException; public Enumeration findByZipCode(int zipCode) throws RemoteException, FinderException; } The create() method is used to create a new entity. This will result in a new record in the database. A home may have many create() methods. The number and datatype of the arguments of each create() are left up to the bean developer, but the return type must be the remote interface datatype. In this case, invoking create() on the CustomerHome interface will return an instance of Customer. The findByPrimaryKey() and findByZipCode() methods are used to locate specific instance of the customer bean. Again, you may define as many find methods as you need. Back to the Remote and Home Interfaces The remote and home interfaces are used by applications to access enterprise beans at run time. The home interface allows the application to create or locate the bean, while the remote interface allows the application to invoke a bean's business methods. The below code illustrates:
© Trendz Information Technologies Ltd. Page No. 150 of 220

J2EE

CustomerHome home = // Get a reference to the CustomerHome object Customer customer = home.create(new Integer(33)); Name name = new Name("Richard", "Wayne", "Monson-Haefel"); customer.setName(name); Enumeration enumOfCustomers = home.findByZip(55410); Customer customer2 = home.findByPrimaryKey(new Integer(33)); Name name2 = customer2.getName(); // output is "Richard Wayne Monson-Haefel" System.out.println(name); The javax.ejb.EJBHome interface also defines other methods that the CustomerBean automatically inherits, including a set of remove() methods that allow the application to destroy bean instances. Enterprise Beans as Distributed Objects The remote and home interfaces are types of Java RMI Remote interfaces. The java.rmi.Remote interface is used by distributed objects to represent the bean in a different address space (process or machine). An enterprise bean is a distributed object. That means that the bean class is instantiated and lives in the container but it can be accessed by applications that live in other address spaces. To make an object instance in one address space available in another requires a little trick involving network sockets. To make the trick work, wrap the instance in a special object called a skeleton that has a network connection to another special object called a stub. The stub implements the remote interface so it looks like a business object. But the stub doesn't contain business logic; it holds a network socket connection to the skeleton. Every time a business method is invoked on the stub's remote interface, the stub sends a network message to the skeleton telling it which method was invoked. When the skeleton receives a network message from the stub, it identifies the method invoked and the arguments, and then invokes the corresponding method on the actual instance. The instance executes the business method and returns the result to the skeleton, which sends it to the stub. The diagram below illustrates:

© Trendz Information Technologies Ltd.

Page No. 151 of 220

J2EE

The stub returns the result to the application that invoked its remote interface method. From the perspective of the application using the stub, it looks like the stub does the work locally. Actually, the stub is just a dumb network object that sends the requests across the network to the skeleton, which in turn invokes the method on the actual instance. The instance does all the work, the stub and skeleton just pass the method identity and arguments back and forth across the network. In EJB, the skeleton for the remote and home interfaces is implemented by the container, not the bean class. This is to ensure that every method invoked on these reference types by a client application are first handled by the container and then delegated to the bean instance. The container must intercept these requests intended for the bean so that it can apply persistence (entity beans), transactions, and access control automatically. Distributed object protocols define the format of network messages sent between address spaces. Distributed object protocols get pretty complicated, but luckily you don't see any of it because it's handled automatically. Most EJB servers support either the Java Remote Method Protocol (JRMP) or CORBA's Internet Inter-ORB Protocol (IIOP). The bean and application programmer only see the bean class and its remote interface, the details of the network communication are hidden. With respect to the EJB API, the programmer doesn't care whether the EJB server uses JRMP or IIOP--the API is the same. The EJB specification requires that you use a specialized version the Java RMI API, when working with a bean remotely. Java RMI is an API for accessing distributed objects and is somewhat protocol agnostic -- in the same way that JDBC is database agnostic. So, an EJB server can support JRMP or IIOP, but the bean and application developer always uses the same Java RMI API. In order for the EJB server to have the option of supporting IIOP, a specialized version of Java RMI, called Java RMI-IIOP was developed. Java RMI-IIOP uses IIOP as the protocol and the Java RMI API. EJB servers don't have to use IIOP, but they do have to respect Java RMI-IIOP restrictions, so EJB 1.1 uses the specialized Java RMI-IIOP conventions and types, but the underlying protocol can be anything. Entity Type Enterprise Beans The entity bean is one of two primary bean types: entity and session. The entity bean is used to represent data in the database. It provides an object-oriented
© Trendz Information Technologies Ltd. Page No. 152 of 220

J2EE interface to data that would normally be accessed by the JDBC or some other backend API. More than that, entity beans provide a component model that allows bean developers to focus their attention on the business logic of the bean, while the container takes care of managing persistence, transactions, and access control. There are two basic kinds of entity bean: Container-Managed Persistence (CMP), and Bean-Managed Persistence (BMP). With CMP, the container manages the persistence of the entity bean. Vendor tools are used to map the entity fields to the database and absolutely no database access code is written in the bean class. With BMP, the entity bean contains database access code (usually JDBC) and is responsible for reading and writing its own state to the database. BMP entities have a lot of help with this since the container will alert the bean as to when it's necessary to make an update or read its state from the database. The container can also handle any locking or transactions, so that the database maintains integrity. Container-Managed Persistence Container-managed persistence beans are the simplest for the bean developer to create and the most difficult for the EJB sever to support. This is because all the logic for synchronizing the bean's state with the database is handled automatically by the container. This means that the bean developer doesn't need to write any data access logic, while the EJB server is supposed to take care of all the persistence needs automatically -- a tall order for any vendor. Most EJB vendors support automatic persistence to a relational database, but the level of support varies. Some provide very sophisticated Object-to-Relational mapping, while others are very limited. In this section, you will expand the CustomerBean developed earlier to a complete definition of a Container-managed persistence bean. In the next section on Beanmanaged persistence you will modify the CustomerBean to manage its own persistence. Bean Class An enterprise bean is a complete component, which is made up of at least two interfaces and a bean implementation class. All these types will be presented and their meaning and application explained, starting with the bean class, which is defined below: import javax.ejb.EntityBean; public class CustomerBean implements EntityBean { int customerID; Address myAddress; Name myName; CreditCard myCreditCard; // CREATION METHODS public Integer ejbCreate(Integer id) { customerID = id.intValue(); return null; } public void ejbPostCreate(Integer id) { }
© Trendz Information Technologies Ltd. Page No. 153 of 220

J2EE

public Customer ejbCreate(Integer id, Name name) { myName = name; return ejbCreate(id); } public void ejbPostCreate(Integer id, Name name) { } // BUSINESS METHODS public Name getName() { return myName; } public void setName(Name name) { myName = name; } public Address getAddress() { return myAddress; } public void setAddress(Address address) { myAddress = address; } public CreditCard getCreditCard() { return myCreditCard; } public void setCreditCard(CreditCard card) { myCreditCard = card; } // CALLBACK METHODS public void setEntityContext(EntityContext cntx) { } public void unsetEntityContext() { } public void ejbLoad() { } public void ejbStore() { } public void ejbActivate() { } public void ejbPassivate() { }

© Trendz Information Technologies Ltd.

Page No. 154 of 220

J2EE public void ejbRemove() { } } This is a good example of a fairly simple CMP entity bean. Notice that there is no database access logic in the bean. This is because the EJB vendor provides tools for mapping the fields in the CustomerBean to the database. The CustomerBean class, for example, could be mapped to any database providing it contains data that is similar to the fields in the bean. In this case the bean's instance fields are comprised of a primitive int and simple dependent objects (Name, Address,and CreditCard) with their own attributes. Below are the definitions for these dependent objects. // The Name class public class Name implements Serializable { public String lastName, firstName, middleName; public Name(String lastName, String firstName, String middleName) { this.lastName = lastName; this.firstName = firstName; this.middleName = middleName; } } public Name() {}

// The Address class public class Address implements Serializable { public String street, city, state, zip; public Address(String street, String city, String state, String zip) { this.street = street; this.city = city; this.state = state; this.zip = zip; } } public Address() {}

// The CreditCard class public class CreditCard implements Serializable { public String number, type, name; public Date expDate; public CreditCard(String number, String type, String name, Date expDate) { this.number = number; this.type = type;
© Trendz Information Technologies Ltd. Page No. 155 of 220

J2EE this.name = name; this.expDate = expDate; } } public CreditCard() {}

These fields are called container-managed fields because the container is responsible for synchronizing their state with the database; the container manages the fields. Container-managed fields can be any primitive data types or serializable type. This case uses both a primitive int (customerID) and serializable objects (Address, Name, CreditCard). In order to map the dependent objects to the database a fairly sophisticated mapping tool would be needed. Not all fields in a bean are automatically container-managed fields; some may be just plain instance fields for the bean's transient use. A bean developer distinguishes container-managed fields from plain instance fields by indicating which fields are container-managed in the deployment descriptor. The container-managed fields must have corresponding types (columns in RDBMS) in the database either directly or through Object-Relational mapping. The CustomerBean might, for example, map to a CUSTOMER table in the database that has the following definition: CREATE TABLE CUSTOMER { id INTEGER PRIMARY KEY, last_name CHAR(30), first_name CHAR(20), middle_name CHAR(20), street CHAR(50), city CHAR(20), state CHAR(2), zip CHAR(9), credit_number CHAR(20), credit_date DATE, credit_name CHAR(20), credit_type CHAR(10) } With container-managed persistence, the vendor must have some kind of proprietary tool that can map the bean's container-managed fields to their corresponding columns in a specific table, CUSTOMER in this case. Once the bean's fields are mapped to the database, and the Customer bean is deployed, the container will manage creating records, loading records, updating records, and deleting records in the CUSTOMER table in response to methods invoked on the Customer bean's remote and home interfaces. A subset (one or more) of the container-managed fields will also be identified as the bean's primary key. The primary key is the index or pointer to a unique record(s) in the database that makes up the state of the bean. In the case of the CustomerBean, the id field is the primary key field and will be used to locate the beans data in the database. Primitive single field primary keys are represented as their corresponding
© Trendz Information Technologies Ltd. Page No. 156 of 220

J2EE object wrappers. The primary key of the Customer bean for example is a primitive int in the bean class but to a bean's clients it will manifest itself as the java.lang.Integer type. Primary keys that are make up of several fields, called compound primary keys, will be represented by a special class defined by the bean developer. Primary keys are similar in concept to primary keys in a relational database -- actually when a relational database is used for persistence they are often the same thing. Home Interface To create a new instance of a CMP entity bean, and therefore insert data into the database, the create() method on the bean's home interface must be invoked. The Customer bean's home interface is defined by the CustomerHome interface - the definition is shown below. public interface CustomerHome extends javax.ejb.EJBHome { public Customer create(Integer customerNumber) throws RemoteException,CreateException; public Customer create(Integer customerNumber, Name name) throws RemoteException,CreateException; public Customer findByPrimaryKey(Integer customerNumber) throws RemoteException, FinderException; public Enumeration findByZipCode(int zipCode) throws RemoteException, FinderException; } Below is an example of how the home interface would be used by an application client to create a new customer: CustomerHome home = // Get a reference to the CustomerHome object Name name = new Name("John", "W", "Smith"); Customer customer = home.create(new Integer(33), name); A bean's home interface may declare zero or more create() methods, each of which must have corresponding ejbCreate() and ejbPostCreate() methods in the bean class. These creation methods are linked at run time, so that when a create() method is invoked on the home interface, the container delegates the invocation to the corresponding ejbCreate() and ejbPostCreate() methods on the bean class. When the create() method on a home interface is invoked, the container delegates the create() method call to the bean instance's matching ejbCreate() method. The ejbCreate() methods are used to initialize the instance state before a record is inserted into the database. In this case, they initialize the customerID and Name fields. When the ejbCreate() method is finished (they return null in CMP) the container reads the container-managed fields and inserts a new record into the CUSTOMER table indexed by the primary key, in this case customerID as it maps to the CUSOTMER.ID column.

© Trendz Information Technologies Ltd.

Page No. 157 of 220

J2EE In EJB, an entity bean doesn't technically exist until after its data has been inserted into the database, which occurs during the ejbCreate() method. Once the data has been inserted, the entity bean exists and can access its own primary key and remote references, which isn't possible until after the ejbCreate() method completes and the data is in the database. If a bean needs to access its own primary key or remote reference after its created, but before it services any business methods, it can do so in the ejbPostCreate() method. The ejbPostCreate() allows the bean to do any postcreate processing before it begins serving client requests. For every ejbCreate() there must be a matching (matching arguments) ejbPostCreate() method. The methods in the home interface that begins with "find" are called the find methods. These are used to query the EJB server for specific entity beans, based on the name of the method and arguments passed. Unfortunately, there is no standard query language defined for find methods, so each vendor will implement the find method differently. In CMP entity beans, the find methods are not implemented with matching methods in the bean class; containers implement them when the bean is deployed in a vendor specific manner. The deployer will use vendor specific tools to tell the container how a particular find method should behave. Some vendors will use Object-Relational mapping tools to define the behavior of a find method while others will simply require the deployer to enter the appropriate SQL command. There are two basic kinds of find methods: single-entity and multi-entity find methods. Single-entity find methods return a remote reference to the one specific entity bean that matches the find request. If no entity beans are found, the method throws an ObjectNotFoundException. Every entity bean must define the single-entity find method with the method name findByPrimaryKey(), which takes the bean's primary key type as an argument. (In the above example you used the Integer type which wrapped the int type of the id field in the bean class.) The multi-entity find methods return a collection (Enumeration or Collection type) of entities that match the find request. If no entities are found, the multi-entity find returns an empty collection. (Note that an empty collection is not the same thing as a null reference.) Remote Interface Every entity bean must define a remote interface in addition to the home interface. The remote interface defines the business methods of the entity bean. The following is the remote interface definition for the Customer bean: import javax.ejb.EJBObject; import java.rmi.RemoteException; public interface Customer extends EJBObject { public Name getName() throws RemoteException; public void setName(Name name) throws RemoteException; public Address getAddress() throws RemoteException; public void setAddress(Address address) throws RemoteException;
© Trendz Information Technologies Ltd. Page No. 158 of 220

J2EE

public CreditCard getCreditCard() throws RemoteException; public void setCreditCard(CreditCard card) throws RemoteException; } Below is an example of how a client application would use the remote interface to interact with a bean: Customer customer = // ... obtain a remote reference to the bean // get the customer's address Address addr = customer.getAddress(); // change the zip code addr.zip = "56777"; // update the customer's address customer.setAddress(addr); The business methods in the remote interface are delegated to the matching business methods in the bean instance. In the Customer bean, the business methods are all simple accessors and mutators, but they could be more complicated. In other words, an entity's business methods are not limited to reading and writing data. They can also perform tasks and computations. If customers had, for example, a loyalty program that rewarded frequent use, there might be methods to upgrade membership in the program based on an accumulation of overnight stays. See below: import javax.ejb.EJBObject; import java.rmi.RemoteException; public interface Customer extends EJBObject { public MembershipLevel addNights(int nights_stayed) throws RemoteException; public MembershipLevel upgradeMembership() throws RemoteException; public MembershipLevel getMembershipLevel() throws RemoteException; } ... Simple accessor business methods go here

The addNights() and upgradeMembership() methods are more sophisticated than simple accessor methods. They apply business rules to change the membership level and go beyond reading and writing data.

© Trendz Information Technologies Ltd.

Page No. 159 of 220

J2EE

Callback Methods The bean class defines create methods that match methods in the home interface and business methods that match methods in the remote interface. The bean class also implements a set of callback methods that allow the container to notify the bean of events in its lifecycle. The callback methods are defined in the javax.ejb.EntityBean interface that is implemented by all entity beans, including the CustomerBean class. The EntityBean interface has the following definition. Notice that the bean class implements these methods. public interface javax.ejb.EntityBean { public void setEntityContext(); public void unsetEntityContext(); public void ejbLoad(); public void ejbStore(); public void ejbActivate(); public void ejbPassivate(); } public void ejbRemove();

The setEntityContext() method provides the bean with an interface to the container called the EntityContext. The EntityContext interface contains methods for obtaining information about the context under which the bean is operating at any particular moment. The EntityContext interface is used to access security information about the caller; to determine the status of the current transaction or to force a transaction rollback; or to get a reference to the bean itself, its home, or its primary key. The EntityContext is only set once in the life of a entity bean instance, so its reference should be put into one of the bean instance's fields if it will be needed later. The Customer bean above doesn't use the EntityContext, but it could. For example, it could use the EntityContext to validate the caller's membership in a particular security role. Below is an example, where the EntityContext is used to validate that the caller is a Manager, the only role (security identity) that can set the credit card type on a customer to be a WorldWide card, the no-limit card of the super wealthy. (Customers with this card are automatically tagged for extra service.) import javax.ejb.EntityBean; public class CustomerBean implements EntityBean { int customerID; Address myAddress; Name myName; CreditCard myCreditCard; EntityContext ejbContext;

© Trendz Information Technologies Ltd.

Page No. 160 of 220

J2EE // CALLBACK METHODS public void setEntityContext(EntityContext cntx) { ejbContext = cntx } public void unsetEntityContext() { ejbContext = null; } // BUSINESS METHODS public void setCreditCard(CreditCard card) { if (card.type.equals("WorldWide")) if (ejbContext.isCallerInRole("Manager")) myCreditCard = card; else throw new SecurityException(); else myCreditCard = card; } public CreditCard getCreditCard() { return myCreditCard; } ... } The unsetEntityContext() method is used at the end of the bean's lifecycle -- before the instance is evicted from memory -- to dereference the EntityContext and perform any last minuet clean-up. The ejbLoad() and ejbStore() methods in CMP entities are invoked when the entity bean's state is being synchronized with the database. The ejbLoad() is invoked just after the container has refreshed the bean container-managed fields with its state from the database. The ejbStore() method is invoked just before the container is about to write the bean container-managed fields to the database. These methods are used to modify data as its being synchronized. This is common when the data stored in the database is different than the data used in the bean fields. The methods might be used, for example, to compress data before it is stored and decompress it when it is retrieved from the database. In the Customer bean the ejbLoad() and ejbStore() methods might be used to convert the dependent objects (Name, Address, CreditCard) to simple String objects and primitive types, if the EJB container is not sophisticated enough to map the dependent objects to the CUSTOMER table. Below is an example of how the bean might be modified. import javax.ejb.EntityBean; public class CustomerBean implements EntityBean { //container-managed fields int customerID; String lastName;
© Trendz Information Technologies Ltd. Page No. 161 of 220

J2EE String firstName; String middleName; ... // not-container-managed fields Name myName; Address myAddress; CreditCard myCreditCard; // BUSINESS METHODS public Name getName() { return myName; } public void setName(Name name) { myName = name; } ... public void ejbLoad() { if (myName == null) myName = new Name(); myName.lastName = lastName; myName.firstName = firstName; myName.middleName = middleName; ... } public void ejbStore() { lastName = myName.lastName; firstName = myName.firstName; middleName = myName.middleName; ... } }

The ejbPassivate() and ejbActivate() methods are invoked on the bean by the container just before the bean is passivated and just after the bean is activated, respectively. Passivation in entity beans means that the bean instance is disassociated with its remote reference so that the container can evict it from memory or reuse it. It's a resource conservation measure the container employs to reduce the number of instances in memory. A bean might be passivated if it hasn't been used for a while or as a normal operation performed by the container to maximize reuse of resources. Some containers will evict beans from memory, while others will reuse instances for other more active remote references. The ejbPassivate() and ejbActivate() methods provide the bean with a notification as to when its about to be passivated (disassociated with the remote reference) or activated (associated with a remote reference).

© Trendz Information Technologies Ltd.

Page No. 162 of 220

J2EE

Bean-Managed Persistence The bean-managed persistence (BMP) enterprise bean manages synchronizing its state with the database as directed by the container. The bean uses a database API (usually JDBC) to read and write its fields to the database, but the container tells it when to do each synchronization operation and manages the transactions for the bean automatically. Bean-managed persistence gives the bean developer the flexibility to perform persistence operations that are too complicated for the container or to use a data source that is not supported by the container -- custom and legacy databases for example. In this section, you'll modify the CustomerBean class to be a BMP bean instead of a CMP bean. This modification will not impact the remote or home interface at all. In fact, you won't modify the original CustomerBean directly. Instead, you'll change it to bean-managed persistence by extending the bean and overriding the appropriate methods. Below is the definition of the class that will extend the Customer bean class to make it a BMP entity. In most cases, you will not extend a bean to make it BMP, you will just implement the bean as BMP directly. This strategy (extending the CMP bean) is done for two reasons: it allows the bean to be either a CMP or BMP bean; and it conveniently cuts down on the amount of code needed to display. Below is the definition of the BMP class which will be added to as this section proceeds: public class CustomerBean_BMP extends CustomerBean { public void ejbLoad() { // override implementation } public void ejbStore() { // override implementation } public void ejbCreate() { // override implementation } public void ejbRemove() { // override implementation } private Connection getConnection() { // new helper method } } With BMP beans, the ejbLoad() and ejbStore() methods are used differently by the container and bean than was the case in CMP. In BMP, the ejbLoad() and ejbStore() methods contain code to read the bean's data from the database and to write changes to the database, respectively. These methods are called on the bean automatically, when the EJB server decides it's a good time to read or write data. The CustomerBean_BMP bean manages its own persistence. In other words, the ejbLoad() and ejbStore() methods must include database access logic, so that the bean can load and store its data when the EJB container tells it to. The container will execute the ejbLoad() and ejbStore() methods automatically when appropriate.

© Trendz Information Technologies Ltd.

Page No. 163 of 220

J2EE The ejbLoad() method is usually invoked by the container at the beginning of a transaction, just before the container delegates a business method to the bean. The code below shows how to implement the ejbLoad() method using JDBC. import java.sql.Connection; public class CustomerBean_BMP extends CustomerBean { public void ejbLoad() { Connection con; try { Integer primaryKey = (Integer)ejbContext.getPrimaryKey(); con = this.getConnection(); Statement sqlStmt = con.createStatement("SELECT * FROM Customer " + " WHERE customerID = " + primaryKey.intValue()); ResultSet results = sqlStmt.executeQuery(); if (results.next()) { // get the name information from the customer table myName = new Name(); myName.first = results.getString("FIRST_NAME"); myName.last = results.getString("LAST_NAME"); myName.middle = results.getString("MIDDLE_NAME"); // get the address information from the customer table myAddress = new Address(); myAddress.street = results.getString("STREET"); myAddress.city = results.getString("CITY"); myAddress.state = results.getString("STATE"); myAddress.zip = results.getInt("ZIP"); // get the credit card information from the customer table myCreditCard = new CreditCard(); myCreditCard.number = results.getString("CREDIT_NUMBER"); myCreditCard.expDate = results.getString("CREDIT_DATE"); myCreditCard.type = results.getString("CREDIT_TYPE"); myAddress.name = results.getInt("CREDIT_NAME"); } } catch (SQLException sqle) { throw new EJBException(sqle); } finally { if (con!=null) con.close(); } } } In the ejbLoad() method, use the ejbContext() reference to the bean's EntityContext to obtain the instance's primary key. This ensures that you use the correct index to the database. Obviously, the CustomerBean_BMP will need to use the inherited setEntityContext() and unsetEntityContext() methods as illustrated earlier.

© Trendz Information Technologies Ltd.

Page No. 164 of 220

J2EE The ejbStore() method is invoked by the container on the bean, at the end of a transaction, just before the container attempts to commit all changes to the database. import java.sql.Connection; public class CustomerBean_BMP extends CustomerBean { public void ejbLoad() { ... read data from database } public void ejbStore() { Connection con; try { Integer primaryKey = (Integer)ejbContext.getPrimaryKey(); con = this.getConnection(); PreparedStatement sqlPrep = con.prepareStatement( "UPDATE customer set " + "last_name = ?, first_name = ?, middle_name = ?, " + "street = ?, city = ?, state = ?, zip = ?, " + "card_number = ?, card_date = ?, " + "card_name = ?, card_name = ?, " + "WHERE id = ?" ); sqlPrep.setString(1,myName.last); sqlPrep.setString(2,myName.first); sqlPrep.setString(3,myName.middle); sqlPrep.setString(4,myAddress.street); sqlPrep.setString(5,myAddress.city); sqlPrep.setString(6,myAddress.state); sqlPrep.setString(7,myAddress.zip); sqlPrep.setInt(8, myCreditCard.number); sqlPrep.setString(9, myCreditCard.expDate); sqlPrep.setString(10, myCreditCard.type); sqlPrep.setString(11, myCreditCard.name); sqlPrep.setInt(12,primaryKey.intValue()); sqlPrep.executeUpdate(); } catch (SQLException sqle) { throw new EJBException(sqle); } finally { if (con!=null) con.close(); } } } In both the ejbLoad() and ejbStore() methods the bean synchronizes its own state with the database using JDBC. If you studied the code carefully you may have noticed that the bean obtains its database connection from the mysterious this.getConnection()
© Trendz Information Technologies Ltd. Page No. 165 of 220

J2EE method invocation, a method yet to be implemented. The getConnection() method is not a standard EJB method, its just a private helper method implemented to conceal the mechanics of obtaining a database connection. Below is the definition of the getConnection() method. import java.sql.Connection; public class CustomerBean_BMP extends CustomerBean { public void ejbLoad() { ... read data from database } public void ejbStore() { ... write data to database } private Connection getConnection() throws SQLException { InitialContext jndiContext = new InitialContext(); DataSource source = (DataSource) jndiContext.lookup("java:comp/env/jdbc/myDatabase"); return source.getConnection();

} }

Database connections are obtained from the container using a default JNDI context called the JNDI Environment Naming Context (ENC). The ENC provides access to transactional, pooled, JDBC connections through the standard connection factory, the javax.sql.DataSource type. In BMP, the ejbLoad() and ejbStore() methods are invoked by the container to synchronize the bean instance with data in the database. To insert and remove entities in the database, the ejbCreate() and ejbRemove() methods are implemented with similar database access logic. The ejbCreate() methods are implemented so that a new record is inserted into the database and the ejbRemove() methods are implemented so that the entity's data is deleted from the database. The ejbCreate() methods and the ejbRemove() method of a BMP entity are invoked by the container in response to invocations on their corresponding methods in the home and remote interfaces. The implementations of these methods are shown below. public void ejbCreate(Integer id) { this.customerID = id.intValue(); Connection con; try { con = this.getConnection(); Statement sqlStmt = con.createStatement("INSERT INTO customer id VALUES (" + customerID + ")"); sqlStmt.executeUpdate(); return id; } catch(SQLException sqle) {
© Trendz Information Technologies Ltd. Page No. 166 of 220

J2EE throw new EJBException(sqle); } finally { if (con!=null) con.close(); } } public void ejbRemove() { Integer primaryKey = (Integer)ejbContext.getPrimaryKey(); Connection con; try { con = this.getConnection(); Statement sqlStmt = con.createStatement("DELETE FROM customer WHERE id = " primaryKey.intValue()); sqlStmt.executeUpdate(); } catch(SQLException sqle) { throw new EJBException(sqle); } finally { if (con!=null) con.close(); } } In BMP, the bean class is responsible for implementing the find methods defined in the home interface. For each find method defined in the home interface there must be corresponding ejbFind() method in the bean class. The ejbFind() methods locate the appropriate bean records in the database and return their primary keys to the container. The container converts the primary keys into bean references and returns them to the client. Below is an example implementation of the ejbFindByPrimaryKey() method in the CustomerBean_BMP class, which corresponds to the findByPrimaryKey() defined in the CustomerHome interface. public Integer ejbFindByPrimaryKey(Integer primaryKey) throws ObjectNotFoundException { Connection con; try { con = this.getConnection(); Statement sqlStmt = con.createStatement("SELECT * FROM Customer " + " WHERE customerID = " + primaryKey.intValue()); ResultSet results = sqlStmt.executeQuery(); if (results.next()) return primaryKey; else throw ObjectNotFoundException();

} catch (SQLException sqle) {

© Trendz Information Technologies Ltd.

Page No. 167 of 220

J2EE throw new EJBException(sqle); } finally { if (con!=null) con.close(); } } Single-entity find methods like the one above return a single primary key or throw the ObjectNotFoundException if no matching record is located. Multi-entity find methods return a collection (java.util.Enumeration or java.util.Collection) of primary keys. The container converts the collection of primary keys into a collection of remote references, which are returned to the client. Below is an example of how the multi-entity ejbFindByZipCode() method, which corresponds to the findByZipCode() method defined in the CustomerHome interface, would be implemented in the CustomerBean_BMP class. public Enumeration ejbFindByZipCode(int zipCode) { Connection con; try { con = this.getConnection(); Statement sqlStmt = con.createStatement("SELECT id FROM Customer " + " WHERE zip = " +zipCode); ResultSet results = sqlStmt.executeQuery(); Vector keys = new Vector(); while(results.next()){ int id = results.getInt("id"); keys.addElement(new Integer(id)); } return keys.elements(); } catch (SQLException sqle) { throw new EJBException(sqle); } finally { if (con!=null) con.close(); } } If no matching bean records are found, an empty collection is returned to the container, which returns an empty collection to the client. With the implementation of all these methods and a few minor changes to the bean's deployment descriptor, the CustomerBean_BMP is ready to be deployed as a BMP entity. Session Type Enterprise Beans Session beans are used to manage the interactions of entity and other session beans, access resources, and generally perform tasks on behalf of the client. Session

© Trendz Information Technologies Ltd.

Page No. 168 of 220

J2EE beans correspond to the controller in a model-view-controller architecture because they encapsulate the business logic of a 3-tier architecture. There are two basic kinds of session bean: Stateless and Stateful. Stateless session beans are made up of business methods that behave like procedures; they operate only on the arguments passed to them when they are invoked. Stateless beans are called "stateless" because they are transient; they do not maintain business state between method invocations. Stateful session beans encapsulate business logic and state specific to a client. Stateful beans are called "stateful" because they do maintain business state between method invocations, held in memory and not persistent. Stateless Session Beans Stateless session beans, like all session beans, are not persistent business objects as are entity beans. They do not represent data in the database. Instead, they represent business processes or tasks that are performed on behalf of the client using them. The business methods in a stateless bean act more like traditional procedures in a legacy transaction-processing monitor. Each invocation of a stateless business method is independent from previous invocations. Because stateless session beans are "stateless" they are easier for the EJB container to manage, so they tend to process requests faster and use less resources. But this performance advantage comes at a price; stateless session beans are stupid, they don't remember anything from one method invocation to the next. An example of a stateless session bean is a CreditService bean, representing a credit service that can validate and process credit card charges. A Hotel chain might develop a CreditService bean to encapsulate the process of verifying a credit card number, making a charge, and recording the charge in the database for accounting purposes. Below are the remote and home interfaces for the CreditService bean. // remote interface public interface CreditService extends javax.ejb.EJBObject { public void verify(CreditCard card, double amount) throws RemoteException, CreditServiceException; public void charge(CreditCard card, double amount) throws RemoteException, CreditServiceException; } // home interface public interface CreditServiceHome extends java.ejb.EJBHome { public CreditService create() throws RemoteException, CreateException; } The remote interface, CreditService, defines two methods, verify() and charge() which are used by the Hotel to verify and charge credit cards. The Hotel might use the verify() method to make a reservation, but not charge the customer. The charge() method would be used to charge a customer for a room. The home interface, CreditServiceHome provides one create() method with no arguments. All home interfaces for stateless session beans will define just one method, a no-argument create() method, because session beans do not have find methods and they cannot be initiated with any arguments when they are created. Stateless session beans do not have find methods, because stateless beans are all equivalent and are not
© Trendz Information Technologies Ltd. Page No. 169 of 220

J2EE persistent. In other words, there is no unique stateless session beans that can be located in the database. Because stateless session beans are not persisted, they are transient services. Every client that uses the same type of session bean gets the same service. Below is the bean class definition for the CreditService bean. This bean encapsulates access to the Acme Credit Card processing services. Specifically, this bean accesses the Acme secure web server and posts requests to validate or charge the customer's credit card. import javax.ejb.SessionBean; public class CreditServiceBean implements SessionBean { URL acmeURL; HttpURLConnection acmeCon; public void ejbCreate() { try { InitialContext jndiContext = new InitialContext(); URL acmeURL = (URL) jndiContext.lookup("java:comp/ejb/env/url/acme"); acmeCon = acmeURL.openConnection(); } catch (Exception e) { throws new EJBException(e); } } public void verify(CreditCard card, double amount) { String response = post("verify:" + card.postString() + ":" + amount); if (response.substring("approved")== -1) throw new CreditServiceException("denied"); } public void charge(CreditCard card, double amount) throws CreditCardException { String response = post("charge:" + card.postString() + ":" + amount); if (response.substring("approved")== -1) throw new CreditServiceException("denied"); } private String post(String request) { try { acmeCon.connect(); acmeCon.setRequestMethod("POST "+request); String response = acmeCon.getResponseMessage(); } catch (IOException ioe) { throw new EJBException(ioe); } }
© Trendz Information Technologies Ltd. Page No. 170 of 220

J2EE

public void ejbRemove() { acmeCon.disconnect(); } public void setSessionContext(SessionContext cntx) {} public void ejbActivate() {} public void ejbPassivate() {} } The CreditService stateless bean demonstrates that a stateless bean can represent a collection of independent but related services. In this case credit card validation and charges are related but not necessarily interdependent. Stateless beans might be used to access unusual resources -- as is the case with the CreditService bean -databases or to perform complex computations. The CreditService bean is used as an example in this tutorial to demonstrate the service nature of a stateless bean and to provide a context for discussing the behavior of the call back methods. The use of a stateless session beans is not limited to the behavior illustrated in this example; stateless beans can be used to perform any kind of service. The CreditServiceBean class uses a URL resource factory (acmeURL()) to obtain and maintain a reference to the Acme web server which exists on another computer very far away. The CreditServiceBean uses the acmeURL() to obtain a connection to the web server and post requests for the validation and charge of credit cards. The CreditService bean is used by clients instead of a direct connection so that the service can be better managed by the EJB container, which will pool connections and managed transactions and security automatically for the EJB client. The ejbCreate() method is invoked at the beginning of its lifetime and is invoked only once. The ejbCreate() method is a convenient method for initiating resource connections and variables that will be of used to the stateless bean for its lifetime. In the example above, the CreditServiceBean uses the ejbCreate() to obtain a reference to the HttpURLConnection factory, which it will use throughout its lifetime to obtain connections to the Acme web server. The CreditServiceBean uses the JNDI ENC to obtain a URL connection factory in the same way that the CustomerBean used the JNDI ENC to obtain a DataSource resource factory for JDBC connections. The JNDI ENC is a default JNDI context that all beans have access to automatically. The JNDI ENC is used to access static properties, other beans, and resource factories like the java.net.URL and JDBC javax.sql.DataSource. In addition, the JNDI ENC also provides access to JavaMail and Java Messaging Service resource factories. The ejbCreate() and ejbRemove() methods are each only invoked once in its lifetime by the container; when the bean is first created and when it's finally destroyed. Invocations of the create() and remove() methods on its home and remote interfaces by the client do not result in invocations on the ejbCreate() and ejbRemove() methods on the bean instance. Instead, an invocation of the create() method provides the client with a reference to the stateless bean type and the remove() methods invalidate the reference. The container will decide when bean instances are actually created and destroyed and will invoke the ejbCreate() and ejbRemove() methods at
© Trendz Information Technologies Ltd. Page No. 171 of 220

J2EE these times. This allows stateless instances to be shared between many clients without impacting the clients' references. In the CreditServiceBean, the ejbCreate() and ejbRemove() methods are used to obtain a URL connection at the beginning the bean instance's life and to disconnect from it at the end of the bean instance's life. Between the times that the URL connection is obtained and disconnected it is used by the business methods. This approach is used to reduce the number of times that a connection needs to be obtained and disconnected, conserving resources. It may seem wasteful to maintain the URL connection between method invocations, but stateless session beans are designed to be shared between many clients, so that they are in constant use. As soon as a stateless instance completes a method invocation for a client, it can immediately service another client. Ideally, there is little down time for a stateless session bean instance, so it makes sense to maintain the URL connection. The verify() and charge() methods delegate their requests to the post() method, a private helper method. The post() method uses an HttpURLConnection to submit the credit card information to the Acme web server and return the reply to the verify() or charge() method. The HttpURLConnection may have been disconnected automatically by the container -- this might occur if, for example, a lot of time elapsed since its last use -- so the post() method always invokes the connect() method, which does nothing if the connection is already established. The verify() and charge() methods parse the return value looking for the substring "approved" which indicates that the credit card was not denied. If "approved" was not found, its assumed that the card was denied and a business exception is thrown. The setSessionContext() method provides the bean instance with a reference to the SessionContext which serves the same purpose as the EntityContext did for the CustomerBean in the section on Entity beans. The SessionContext is not used in this example. The ejbActivate() and ejbPassivate() methods are not implemented in the CreditService bean because passivation is not used in stateless session beans. These methods are defined in the javax.ejb.SessionBean interface for the Stateful session beans, and so an empty implementation must be provided in stateless session beans. Stateless session bean will never provide anything but empty implementations of these methods. Stateless session beans can also be used to access the database as well as coordinate the interaction of other bean to accomplish a task. Below is the definition of the HotelClerkBean shown earlier in this tutorial: import javax.ejb.SessionBean; import javax.naming.InitialContext; public interface HotelClerkBean implements SessionBean { InitialContext jndiContext; public void ejbCreate() {} public void reserveRoom(Customer cust, RoomInfo ri, Date from, Date to) { CreditCard card = cust.getCreditCard();
© Trendz Information Technologies Ltd. Page No. 172 of 220

J2EE

RoomHome roomHome = (RoomHome) getHome("java:comp/env/ejb/RoomEJB", RoomHome.class); Room room = roomHome.findByPrimaryKey(ri.getID()); double amount = room.getPrice(from,to); CreditServiceHome creditHome = (CreditServiceHome) getHome( "java:comp/env/ejb/CreditServiceEJB", CreditServiceHome.class); CreditService creditAgent = creditHome.create(); creditAgent.verify(card, amount); ReservationHome resHome = (ReservationHome) getHome( "java:comp/env/ejb/ReservationEJB", ReservationHome.class); Reservation reservation = resHome.create(cust.getName(), room,from,to);

}

public RoomInfo[] availableRooms(Location loc, Date from, Date to) { // do a SQL call to find available rooms Connection con = db.getConnection(); Statement stmt = con.createStatement(); ResultSet results = stmt.executeQuery("SELECT ..."); ... return roomInfoArray; } private Object getHome(String path, Class type) { Object ref = jndiContext.lookup(path); return PortableRemoteObject.narrow(ref,type); }

}

The HotelClerkBean is also a stateless bean. All the information needed to process a reservation or to query a list of available rooms is obtained from the method arguments. In the reserveRoom() method, operations on several other beans (Room, CreditService, and Reservation) are coordinated to accomplish one larger task, reserving a room for a customer. This is an example of a session bean managing the interactions of other beans on behalf of the client. The availableRooms() method is used to query the database and obtain a list of rooms -- the information is returned to the client as a collection of data wrappers defined by the RoomInfo class. The use of this class, shown below, is a design pattern that provides the client with a lightweight wrapper of just the information needed. public class RoomInfo { public int id; public int bedCount; public boolean smoking; }
© Trendz Information Technologies Ltd. Page No. 173 of 220

J2EE

To obtain a reference to another bean, as is done three times in the reserveRoom() method, the private getHome() helper method is used. The getHome() method uses the JNDI ENC to obtain references to other beans. private Object getHome(String path, Class type) { Object ref = jndiContext.lookup(path); return PortableRemoteObject.narrow(ref,type); } In the EJB 1.1 specification, RMI over IIOP is the specified programming model, so CORBA references types must be supported. CORBA references cannot be cast using Java native casting. Instead the PortableRemoteObject.narrow() method must be used to explicitly narrow a reference from one type to its subtype. Since JNDI always returns an Object type, all bean references should be explicitly narrowed to support portability between containers. Stateful Session Beans Stateful session beans are dedicated to one client and maintain conversational-state between method invocations. Unlike stateless session beans, clients do not share stateful beans. When a client creates a stateful bean, that bean instance is dedicated to service only that client. This makes it possible to maintain conversational-state, which is business state that can be shared by methods in the same stateful bean. As an example, the HotelClerk bean can be modified to be a stateful bean which can maintain conversational-state between method invocations. This would be useful, for example, if you want the HotelClerk bean to be able to take many reservations, but then process them together under one credit card. This occurs frequently, when families need to reserve two or more rooms or when corporations reserve a block of rooms for some event. Below the HotelClerkBean is modified to be a stateful bean. import javax.ejb.SessionBean; import javax.naming.InitialContext; public class HotelClerkBean implements SessionBean { InitialContext jndiContext; //conversational-state Customer cust; Vector resVector = new Vector(); public void ejbCreate(Customer customer) {} cust = customer; } public void addReservation(Name name, RoomInfo ri, Date from, Date to) { ReservationInfo resInfo = new ReservationInfo(name,ri,from,to); resVector.addElement(resInfo); }

© Trendz Information Technologies Ltd.

Page No. 174 of 220

J2EE public void reserveRooms() { CreditCard card = cust.getCreditCard(); Enumeration resEnum = resVector.elements(); while (resEnum.hasMoreElements()) { ReservationInfo resInfo = (ReservationInfo) resEnum.nextElement(); RoomHome roomHome = (RoomHome) getHome("java:comp/env/ejb/RoomEJB", RoomHome.class); Room room = roomHome.findByPrimaryKey(resInfo.roomInfo.getID()); double amount = room.getPrice(resInfo.from,restInfo.to); CreditServiceHome creditHome = (CreditServiceHome) getHome("java:comp/env/ejb/CreditServiceEJB", CreditServiceHome.class); CreditService creditAgent = creditHome.create(); creditAgent.verify(card, amount); ReservationHome resHome = (ReservationHome) getHome("java:comp/env/ejb/ReservationEJB", ReservationHome.class); Reservation reservation = resHome.create(resInfo.getName(), resInfo.roomInfo,resInfo.from,resInfo.to);

}

public RoomInfo[] availableRooms(Location loc, Date from, Date to) { // Make an SQL call to find available rooms } private Object getHome(String path, Class type) { Object ref = jndiContext.lookup(path); return PortableRemoteObject.narrow(ref,type); } } In the stateful version of the HotelClerkBean class, the conversational state is the Customer reference, which is obtained when the bean is created, and the Vector of ReservationInfo objects. By maintaining the conversational-state in the bean, the client is absolved of the responsibility of keeping track of this session state. The bean keeps track of the reservations and processes them in a batch when the serverRooms() method is invoked. To conserve resources, stateful session beans may be passivated when they are not in use by the client. Passivation in stateful session beans is different then for entity beans. In stateful beans, passivation means the bean conversational-state is written to a secondary storage (often disk) and the instance is evicted from memory. The client's reference to the bean is not affected by passivation, it remains alive and usable while the bean is passivated. When the client invokes a method on a bean
© Trendz Information Technologies Ltd. Page No. 175 of 220

J2EE that is passivated, the container will activate the bean by instantiating a new instance and populating its conversational-state with the state written to secondary storage. This passivation/activation process is often accomplished using simple Java serialization but it can be implemented in other proprietary ways as long as the mechanism behaves the same as normal serialization. (One exception to this is that transient fields do not need to be set to their default initial values when a bean is activated.) Stateful session beans, unlike stateless beans, do use the ejbActivate() and ejbPassivate() methods. The container will invoke these methods to notify the bean when its about to passivated (ejbPassivate()) and immediately following activation (ejbActivate()). Bean developers should use these method to close open resources and to do other clean-up before the instance's state is written to secondary storage and evicted from memory. The ejbRemove() method is invoked on the stateful instance when the client invokes the remove() method on the home or remote interface. The bean should use the ejbRemove() method to do the same kind of clean-up performed in the ejbPassivate() method. Deploying Enterprise JavaBeans Technology Solutions As mentioned previously, the container handles persistence, transactions, concurrency, and access control automatically for the enterprise beans. The EJB specification describes a declarative mechanism for how these things will be handled, through the use of an XML deployment descriptor. When a bean is deployed into a container, the container reads the deployment descriptor to find out how transaction, persistence (entity beans), and access control should be handled. The person deploying the bean will use this information and specify additional information to hook the bean up to these facilities at run time. A deployment descriptor has a predefined format that all EJB compliant beans must use and all EJB compliant servers must know how to read. This format is specified in an XML Document Type Definition, or DTD. The deployment descriptor describes the type of bean (session or entity) and the classes used for the remote, home, and bean class. It also specifies the transactional attributes of every method in the bean, which security roles can access each method (access control), and whether persistence in the entity beans is handled automatically or is preformed by the bean. Below is an example of a XML deployment descriptor used to describe the Customer bean: <?xml version="1.0"?> <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd"> <ejb-jar> <enterprise-beans> <entity> <description> This bean represents a customer </description> <ejb-name>CustomerBean</ejb-name> <home>CustomerHome</home>
© Trendz Information Technologies Ltd. Page No. 176 of 220

J2EE <remote>Customer</remote> <ejb-class>CustomerBean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>Integer</prim-key-class> <reentrant>False</reentrant> <cmp-field><field-name>myAddress</field-name></cmp-field> <cmp-field><field-name>myName</field-name></cmp-field> <cmp-field><field-name>myCreditCard</field-name></cmp-field> </entity> </enterprise-beans> <assembly-descriptor> <security-role> <description> This role represents everyone who is allowed full access to the Customer bean. </description> <role-name>everyone</role-name> </security-role> <method-permission> <role-name>everyone</role-name> <method> <ejb-name>CustomerBean</ejb-name> <method-name>*</method-name> </method> </method-permission> <container-transaction> <description> All methods require a transaction </description> <method> <ejb-name>CustomerBean</ejb-name> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar> EJB-capable application servers usually provide tools, which can be used to build the deployment descriptors; this greatly simplifies the process. When a bean is to be deployed, its remote, home, and bean class files and the XML deployment descriptor must be packaged into a JAR file. The deployment descriptor must be stored in the JAR under the special name META-INF/ejb-jar.xml. This JAR file, called an ejb-jar, is vendor neutral; it can be deployed in any EJB container that supports the complete EJB specification. When a bean is deployed in an EJB container its XML deployment descriptor is read from the JAR to determine how to manage the bean at runtime. The person deploying the bean will map attributes of the deployment descriptor to the container's environment. This will include mapping
© Trendz Information Technologies Ltd. Page No. 177 of 220

J2EE access security to the environment's security system, adding the bean to the EJB container's naming system, etc. Once the bean developer has finished deploying the bean it will become available for client applications and other beans to use. Enterprise JavaBeans Clients Enterprise JavaBeans clients may be standalone applications, servlets, applets, or even other enterprise beans. For instance, the HotelClerk session bean shown above was a client of the Room entity beans. All clients use the server bean's home interface to obtain references to the server bean. This reference has the server bean's remote interface datatype, therefore the client interacts with the server bean solely through the methods defined in the remote interface. The remote interface defines the business methods, such as accessor and mutator methods for changing a customer's name, or business methods that perform tasks like using the HotelClerk bean to reserve a room at a hotel. Below is an example of how a Customer bean might be accessed from a client application. In this case the home interface is CustomerHome and the remote interface is Customer. CustomerHome home; Object ref; // Obtain a reference to the CustomerHome ref = jndiContext.lookup("java:comp/env/ejb/Customer"); // Cast object returned by the JNDI lookup to the // appropriate datatype home = PortableRemoteObject.narrow(ref, CustomerHome.class); // Use the home interface to create a // new instance of the Customer bean. Customer customer = home.create(customerID); // Use a business method on the Customer. customer.setName(someName); A client first obtains a reference to the home interface by using JNDI ENC to lookup the server beans. In EJB 1.1, Java RMI-IIOP is the specified programming model. As a consequence, all CORBA references types must be supported. CORBA references cannot be cast using Java native casting. Instead the PortableRemoteObject.narrow() method must be used to explicitly narrow a reference from one type to its subtype. Since JNDI always returns an Object type, all bean references should be explicitly narrowed to support portability between containers. After the home interface is obtained, the client uses the methods defined on the home interface to create, find, or remove the server bean. Invoking one of the create() methods on the home interface returns the client a remote reference to the server bean, which the client uses to perform its job.

© Trendz Information Technologies Ltd.

Page No. 178 of 220

J2EE
EJB 2.0 FEATURES

EJB QL EJB QL is a SQL like language used to provide a standard syntax for finder methods to locate beans. Also provides for select methods, private query methods only useable internally by the bean class. Why an EJB Query Language? The specification for Enterprise Java Beans 1.1 doesn't offer a standard way to define queries for finder methods in entity beans with container-managed persistence (CMP). So EJB container providers have defined their own query syntax for the finder methods of entity beans. For example, BEA's WebLogic Application Server v. 5.1 defines a query language called WLQL. Because of this, developers have to redefine queries for the finder methods whenever an application is moved from one vendor's application server to another's. Obviously, this makes applications built using CMP less portable. What's more, EJB 1.1 offered no standard way to define a query for an entity bean with CMP to navigate with other entity beans in a variety of code contexts, relationships, or associations. There was no proper mechanism to define queries to navigate from one entity bean to its dependent classes and the member variables of those dependent classes. EJB 2.0 deals with these shortcomings by defining the EJB Query Language. EJB QL is based on the SQL-92 specification for defining various finder and select methods of entity beans with CMP. The EJB QL query string consists of three clauses: SELECT, FROM, and WHERE. Among other things, EJB QL offers a standard way to define relationships between entity beans and dependent classes by introducing abstract schema types and relationships in the deployment descriptor. EJB QL also defines queries for navigation using abstract schema names and relationships. What is EJB QL? The following syntax is the basic format of the EJB QL query: EJB QL ::= select_clause from_clause [ where_clause] The EJB QL must always contain SELECT and FROM clauses. The WHERE clause is optional. The FROM clause provides declarations for the identification variables based on abstract schema name, for navigating through the schema. The SELECT clause uses these identification variables to define the return type of the query, and the WHERE clause defines the conditional query. The query for EJB QL is defined in the deployment descriptor using the <query> tag as shown below: <query> <query-method> <method-name></method-name> <method-params> <method-param></method-param>
© Trendz Information Technologies Ltd. Page No. 179 of 220

J2EE </method-params> </query-method> <result-type-mapping></result-type-mapping> <ejb-ql></ejb-ql> </query> You specify the name of the finder or select method in <method-name> and the parameters in <method-param>. The <result-type-mapping> indicates the return type, and can contain either Local (the default) or Remote values. The query string is in the <ejb-ql> tag. I will give a brief description of the finder and select methods since these methods use EJB QL to define the queries. EJB 2.0 defines the finder and select methods for entity beans. The select method is a new addition to the specification. Finder Methods: Finder methods get either a single or a collection of entity bean instances from the persistence store through a relational database. These methods define the home interface(s) of an entity bean. Hence, they are exposed to the client. A home interface can either be a Remote Home interface, EJBHome, or a Local Home interface, EJBLocalHome. The return type of the finder method defined in the remote home interface is either the entity bean's remote interface or a collection of objects implementing the entity bean's remote interface. The return type of the finder method defined in the local home interface is either the entity bean's local interface or a collection of objects implementing the entity bean's local interface. For example: // Remote Home Interface public interface OrderHome extends javax.ejb.EJBHome { ... public Order findByPrimaryKey(int orderId) throws FinderException,RemoteException; public Order findByBiggestOrder() throws FinderException,RemoteException; public java.util.Collection findAllOrders(String supplierName) throws FinderException,RemoteException; } // Local Home Interface public interface OrderHome extends javax.ejb.EJBLocalHome { ... public Order findByPrimaryKey(int orderId) throws FinderException; public Order findBiggestOrder() throws FinderException; public java.util.Collection findAllOrders(String supplierName) throws FinderException; } Select Methods: Select methods exist in the entity bean as a special type of query method. They are not declared in the home interface; therefore, they are not exposed to the client. The finder methods are not useful to access cmp-field, or any remote interface instance defined in cmr-field. Using select methods, an entity bean returns an instance of cmp-field type, or the remote interfaces represented by the cmr-field. Select methods are usually two types. • • ejbSelect<METHOD> ejbSelect<METHOD>InEntity
Page No. 180 of 220

© Trendz Information Technologies Ltd.

J2EE

Example: public abstract class OrderBean implements javax.ejb.EntityBean { ... public abstract java.util.Collection ejbSelectAllOrderedProducts(Date date) throws FinderException; ... public abstract java.util.Collection ejbSelectAllOrderedProductsInEntity(Date date) throws FinderException; } The ejbSelect<METHOD> is not associated with a particular instance of the entity bean. So in the above example, the ejbSelectAllOrderProducts returns a collection of all products associated with all orders. Therefore, the ejbSelect<METHOD>InEntity is specific to the entity instance executed. The above ejbSelectAllOrderProductsInEntity returns all of the products associated with that instance of OrderBean. Here the Order example explains each clause in detail. The relationship between OrderEJB, LineItemEJB, ProductEJB and AddressEJB are shown in the following diagram:

The relationships, as defined in the deployment descriptor, are shown below: <relationships> <!-ONE-TO-MANY: Order LineItem --> <ejb-relation> <ejb-relation-name>Order-LineItem</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> order-has-lineitems </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>OrderEJB</ejb-name>
© Trendz Information Technologies Ltd. Page No. 181 of 220

J2EE </relationship-role-source> <cmr-field> <cmr-field-name>lineItems</cmr-field-name> <cmr-field-type>java.util.Collection </cmr-field-type> </cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name>lineitem-belongsto-order </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <cascade-delete/> <relationship-role-source> <ejb-name>LineItemEJB</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>order</cmr-field-name> </cmr-field> </ejb-relationship-role> </ejb-relation> <!-ONE-TO-MANY unidirectional relationship: Product is not aware of its relationship with LineItem --> <ejb-relation> <ejb-relation-name>Product-LineItem</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name>product-has-lineitems</ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>ProductEJB</ejb-name> </relationship-role-source> <!-- since Product does not know about LineItem there is no cmr field in Product for accessing Lineitem --> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name>lineitem-for-product</ejb-relationship-role-name> <multiplicity>Many</multiplicity> <relationship-role-source> <ejb-name>LineItemEJB</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>product</cmr-field-name> </cmr-field> </ejb-relationship-role> </ejb-relation> </relationships>

© Trendz Information Technologies Ltd.

Page No. 182 of 220

J2EE

FROM Clause The FROM clause defines the domain of the query by declaring the identification variables. Identification variables cannot be declared in the SELECT and WHERE clauses. Instead, the SELECT and WHERE clauses can use only those identification variables defined in the FROM clause. You can define multiple identification variables in the FROM clause. Any valid identifier may be used as an identification variable, though there are few restrictions (see sidebar). Identification variables are case insensitive. The identification variable declaration consists of either a range variable declaration or a collection member declaration. Next, we will look at a simple query string which uses both the range and collection variable declarations from the FROM clause. For example, to select all orders containing Floppy Drive products, the query is: SELECT OBJECT(o) FROM Order o, IN (o.lineItems) li WHERE li.product.product_type='Floppy Drive' Here the FROM clause declares the identifier "o" as a range variable and "li" as a collection member variable. A range variable declares the abstract schema type, which uses the reserved identifier, AS. A declared collection member variable uses the following: • • • reserved identifier, IN abstract-schema-types of range variables and abstract-schema-types of associated entity beans.

The range variable "o" designates the abstract schema type, Order. Similarly, the identification variables: "li" is the abstract schema type, LineItem, and li.product is the abstract schema type, Product. The expression li.product.product_type in the WHERE clause is a java.lang.String type. Since all clauses are evaluated from left to right in EJB QL, the identification variable "li" utilizes the results of the navigation on "o". The identifier OBJECT in the SELECT clause is required, because the OBJECT operator must qualify all stand-alone identification variables in the SELECT clause. You may also declare a range variable using the optional identifier, AS. Therefore, the FROM clause in the above query becomes: FROM Order AS o, IN (o.lineItems) li Also, you may define more than one range variable in the FROM clause. For example: FROM Order AS o, IN (o.lineItems) li, Product p

© Trendz Information Technologies Ltd.

Page No. 183 of 220

J2EE

WHERE Clause The WHERE clause defines conditional expressions to select objects or values that satisfy the expression. For example, a WHERE clause follows: Where_clause ::= WHERE conditional_expression All of the identification variables in a WHERE clause in EJB QL must be declared from a FROM clause. You may also pass input parameters for the finder and select methods. The input parameters are only in the WHERE clause of a query. Input parameters are designated by a question mark (?) prefix, followed by a onebased index of the parameter in the method declaration (i.e., ?1, ?2). public abstract class OrderBean implements javax.ejb.EntityBean { ... //method-a public abstract java.util.Collection ejbSelectLineItems(int quantity) throws FinderException; ... //method-b public abstract java.util.Collection ejbSelectAllProducts(String product_type, double price) throws FinderException; } For example, the select method query for selecting Line Items (method-a) is: SELECT OBJECT (o) FROM Order AS o IN (o.lineItems) li WHERE li.quantity = ?1 Similarly, the select method query for choosing all products based on name and price is: SELECT OBJECT (o) FROM Order AS o IN(o.lineItems) li WHERE li.product.product_type=?1 AND li.product.price=?2 The query for method-a is in the following deployment descriptor: <query> <description> Method to find order specified no of lineItems</description> <query-method> <method-name>ejbSelectLineItems</method-name> <method-params> <method-param>int</method-param> </method-params>
© Trendz Information Technologies Ltd. Page No. 184 of 220

J2EE </query-method> <result-type-mapping>Local</result-type-mapping> <ejb-ql> SELECT OBJECT (o) FROM Order AS o IN (o.lineItems) li WHERE li.quantity = ?1 </ejb-ql> </query> In the same way, you may define the WHERE clause with input parameters. The number of distinct input parameters in an EJB QL query must be the same as the number of input parameters for the finder and select methods. It is not required to use all of the input parameters for the finder or select methods in a query, though. You can also pass an input parameter that corresponds to a particular EJBObject or EJBLocalObject. Containers map these input parameters to the abstract-schema-type values. Next, I will show the various comparison operators available for use with the WHERE clause. In addition to the navigation operator (.) in the queries above, EJB QL supports the fundamental arithmetic operators (i.e., unary, multiplication and division, addition and subtraction), comparison operators (i.e., =, >, >=, <,<=, <>) and logical operators (i.e., NOT,OR, AND). You can also use the comparison operators BETWEEN or NOT BETWEEN in a query. For example, the query to select all Line Items with a quanitity between 100 and 200 is shown here: SELECT OBJECT (li) FROM lineItems AS li WHERE li.quantity BETWEEN 100 and 200 Using comparison operators >= and <=, the WHERE clause is now in the following expression: li.quantity >= 100 AND li.quantity <= 200 The following query selects all Line Items with a quantity less than 100 or more than 200: SELECT OBJECT (li) FROM lineItems AS li WHERE li.quantity NOT BETWEEN 100 and 200 (or) SELECT OBJECT (li) FROM lineItems AS li WHERE li.quantity < 100 AND li.quantity > 200 EJB QL also supports the IN and LIKE expressions. For example, to select the address(es) of an office in various cities, the query expression of the WHERE clause is: address.city IN ('San Jose', 'New York', 'Florida') The expression results are true for Florida and false for Texas. Usage of NOT IN is just the opposite of the above:

© Trendz Information Technologies Ltd.

Page No. 185 of 220

J2EE address.city NOT IN ('San Jose', 'New York', 'Florida') Here, the expression results are true for Texas and false for Florida. An IN expression must contain at least one string-literal in the comma-separated string literal list. You use the comparison operator [NOT] LIKE in the WHERE clause to select a particular value. The syntax of the LIKE expression is below: single_valued_path_expression [NOT] LIKE pattern-value [ESCAPE escape-character] The single_valued_path_expression must result in a String value. You use any string literal in the pattern-value. An underscore (_) represents any single character and a percent (%) any sequence of characters, including an empty sequence. The escapecharacter is a single character string literal, and is for escaping the special meaning of underscore and percent characters in pattern-value. For example, the following query selects all employees whose names start with CHRIS: SELECT OBJECT (emp) FROM employee as emp WHERE emp.name LIKE 'CHRIS%' And to select all employees whose names don't start with CHRIS, use the following: SELECT OBJECT (emp) FROM employee as emp WHERE emp.name NOT LIKE 'CHRIS%' If the value of emp.name in the above expression is NULL, then the value of the expression is unknown. To avoid this, check whether a single_valued_path_expression is NULL by using the IS NULL operator. The following expression returns true when an employee's name is a NULL value. emp.name IS NULL EJB QL also provides the IS EMPTY comparison operator to check whether a collection object of a query string return type contains empty values. EJB QL provides the MEMBER [OF] identifier to check whether the value of a single_valued_path expression is a member of collection designated by the collection_valued_path expression. The only identifiers that use a collection valued path expression are the comparison expressions: IS [NOT] EMPTY and [NOT] MEMBER [OF]. Note that in EJB QL queries, any comparison or arithmetic operations with a NULL value or an unknown value always yields an unknown value. Path expressions with NULL values during evaluation return NULL values. The SELECT clause The SELECT clause denotes the result of the query. The SELECT clause syntax is below, in BNF format:

© Trendz Information Technologies Ltd.

Page No. 186 of 220

J2EE SELECT [DISTINCT] {single_valued_path_expression | OBJECT (identification_variable) DISTINCT works in the same way as SQL in selecting unique values from the query result. You may also restrict the return type to contain only unique values by declaring java.util.Set as the return type for the finder or select methods. Since java.util.Set doesn't allow duplicate values, whenever the return type is java.util.Set, the container internally applies DISTINCT to the query. Therefore, it is not required to explicitly use the DISTINCT identifier in the query string. But when the return type is a java.util.Collection, then it requires an explicit DISTINCT identifier in the query expression to get unique values. The SELECT clause determines the type of values returned by a query. For example, to get all orders, the query is: SELECT OBJECT(o) FROM order o Here, the order is the abstract-schema-name for OrderEJB. Similarly, to get all products that are associated with a line item: SELECT li.product FROM Order As o, IN(o.lineItems) li These line items are the cmr-field name of LineItemsEJB. Now, we see the following query, to get all line items related to an Order: SELECT o.lineItems FROM Order As o Looking carefully, the above query doesn't work, because the return type of the query is not a single-valued expression. The earlier query to get all products associated with line items works fine. This is because the relationship between line item and product is one-to-one, whereas the relationship between order and line items is one-to-many. The single valued path expression is the single_valued_cmr_field, which is a cmr-field name in one-to-one or many-to-one relationship. Since the relationship between order and line is one-to-many, the result yields a collection_valued_path_expression type. Therefore, the SELECT clause must be specified to return a single valued expression. The SELECT clause of a query defined for a finder method must always correspond to the abstract schema type of entity bean for which the finder method is defined. The SELECT clause of a query defined for a select method returns abstract schema types of other entity beans, as well as the values for cmp-fields. Now, you will see some queries of select methods whose return type is that of cmpfield. To select the names of all products that have been ordered: SELECT DISTICT li.product.name FROM order o, IN (o.lineItems) li Here, order is the abstract-type-name of OrderEJB. lineItems and products are cmrfield names. name is the cmp-field name defined for the entity bean ProductEJB.

© Trendz Information Technologies Ltd.

Page No. 187 of 220

J2EE EJB QL also provides built-in functions for performing simple operations on objects of String class and primitive types. Specifically, EJB QL provides the following built-in functions: String Functions: • • • • CONCAT (String, String) - This function returns the concatenated string value. SUBSTRING (String, start, length) - This function returns the substring of the original string. LOCATE (String, String [, start]) This function returns int. LENGTH (String) This function returns the length of the string passed as parameter.

Arithmetic Functions: • • ABS (number) SQRT (double)

Advantages • EJB QL provides a standard way to define queries for entity beans in a portable way. An entity bean with EJB QL defined for its finder and select methods may be portable across any EJB container that adheres to the EJB 2.0 specification container managed persistence. An EJB Container parses and validates EJB QL queries before entity beans are deployed, since EJB QL uses abstract schema types and cmr-fields to navigate across entity beans.

Limitations • Some of the useful features of SQL are not yet provided by EJB QL. For example, the ORDER BY identifier, which becomes very handy as the application becomes large and complex, is not yet supported in EJB QL. Some of the application servers may provide these features, but usage of the same may limit portability across application servers. Date and time values should be passed as millisecond value using Java primitive type, long. EJB QL does not support fixed decimal comparison in arithmetic expressions. String and Boolean comparison is restricted to = and <>. However, the builtin functions(CONCAT, SUBSTRING, etc.) can be used to perform other operations on String. EJB QL does not support comments.

• • • •

Summary The addition of EJB QL to the new EJB 2.0 specification justifies the distributed component architecture as the standard way of defining queries. EJB QL allows applications to be more portable. I believe future versions of EJB QL may provide support for more built-in functions, as well as other SQL features like ORDER BY. In the EJB 2.0 specification, the data model for CMP does not currently support inheritance; therefore, you cannot compare objects or value classes of different types. This may be addressed in future versions of EJB QL.

© Trendz Information Technologies Ltd.

Page No. 188 of 220

J2EE

MESSAGE DRIVEN BEANS Stateless, server-side transaction aware asynchronous messages from a JMS provider components, receive and process

Message-Driven Beans (MDB) are stateless, server-side, transaction-aware components for processing asynchronous JMS messages. Newly introduced in EJB 2.0, message-driven beans process messages delivered via the Java Message Service. Message-driven beans can receive JMS messages and process them. While a message-driven bean is responsible for processing messages, its container takes care of automatically managing the component's entire environment, including transactions, security, resources, concurrency, and message acknowledgment. One of the most important aspects of message-driven beans is that they can consume and process messages concurrently. This capability provides a significant advantage over traditional JMS clients, which must be custom-built to manage resources, transactions, and security in a multithreaded environment. The messagedriven bean containers provided by EJB manage concurrency automatically, so the bean developer can focus on the business logic of processing the messages. The MDB can receive hundreds of JMS messages from various applications and process them all at the same time, because numerous instances of the MDB can execute concurrently in the container. A message-driven bean is a complete enterprise bean, just like a session or entity bean, but there are some important differences. While a message-driven bean has a bean class and XML deployment descriptor, it does not have component interfaces. The component interfaces are absent because the message-driven bean is not accessible via the Java RMI API; it responds only to asynchronous messages. The ReservationProcessor EJB The ReservationProcessor EJB is a message-driven bean that receives JMS messages notifying it of new reservations. The ReservationProcessor EJB is an automated version of the TravelAgent EJB that processes reservations sent via JMS by other travel organizations. It requires no human intervention; it is completely automated. The JMS messages that notify the ReservationProcessor EJB of new reservations might come from another application in the enterprise or an application in some other organization. When the ReservationProcessor EJB receives a message, it creates a new Reservation EJB (adding it to the database), processes the payment using the ProcessPayment EJB, and sends out a ticket. This process is illustrated in Figure 13-3.

© Trendz Information Technologies Ltd.

Page No. 189 of 220

J2EE

Figure 13-3. The ReservationProcessor EJB processing reservations The ReservationProcessorBean Class Here is a partial definition of the ReservationProcessorBean class. Some methods are left empty; they will be filled in later. Notice that the onMessage() method contains the business logic of the bean class; it is similar to the business logic developed in the bookPassage() method of the TravelAgent EJB in Chapter 12. Here's the code: package com.titan.reservationprocessor; import import import import import import import import import javax.jms.Message; javax.jms.MapMessage; com.titan.customer.*; com.titan.cruise.*; com.titan.cabin.*; com.titan.reservation.*; com.titan.processpayment.*; com.titan.travelagent.*; java.util.Date;

public class ReservationProcessorBean implements javax.ejb.MessageDrivenBean, javax.jms.MessageListener { MessageDrivenContext ejbContext; Context jndiContext; public void setMessageDrivenContext(MessageDrivenContext mdc) { ejbContext = mdc; try { jndiContext = new InitialContext(); } catch(NamingException ne) { throw new EJBException(ne);
© Trendz Information Technologies Ltd. Page No. 190 of 220

J2EE }

}

public void ejbCreate() {} public void onMessage(Message message) { try { MapMessage reservationMsg = (MapMessage)message; Integer customerPk = (Integer)reservationMsg.getObject("CustomerID"); Integer cruisePk = (Integer)reservationMsg.getObject("CruiseID"); Integer cabinPk = (Integer)reservationMsg.getObject("CabinID"); double price = reservationMsg.getDouble("Price"); // get the credit card Date expirationDate = new Date(reservationMsg.getLong("CreditCardExpDate")); String cardNumber = reservationMsg.getString("CreditCardNum"); String cardType = reservationMsg.getString("CreditCardType"); CreditCardDO card = new CreditCardDO(cardNumber, expirationDate, cardType); CustomerRemote customer = getCustomer(customerPk); CruiseLocal cruise = getCruise(cruisePk); CabinLocal cabin = getCabin(cabinPk); ReservationHomeLocal resHome = (ReservationHomeLocal) jndiContext.lookup("java:comp/env/ejb/ReservationHomeLocal"); ReservationLocal reservation = resHome.create(customer, cruise, cabin, price, new Date()); Object ref = jndiContext.lookup ("java:comp/env/ejb/ProcessPaymentHomeRemote"); ProcessPaymentHomeRemote ppHome = (ProcessPaymentHomeRemote) PortableRemoteObject.narrow(ref, ProcessPaymentHomeRemote.class); ProcessPaymentRemote process = ppHome.create(); process.byCredit(customer, card, price); TicketDO ticket = new TicketDO(customer,cruise,cabin,price); deliverTicket(reservationMsg, ticket); } catch(Exception e) { throw new EJBException(e); }

}

public void deliverTicket(MapMessage reservationMsg, TicketDO ticket) {

© Trendz Information Technologies Ltd.

Page No. 191 of 220

J2EE // send it to the proper destination } public CustomerRemote getCustomer(Integer key) throws NamingException, RemoteException, FinderException { // get a remote reference to the Customer EJB } public CruiseLocal getCruise(Integer key) throws NamingException, FinderException { // get a local reference to the Cruise EJB } public CabinLocal getCabin(Integer key) throws NamingException, FinderException { // get a local reference to the Cabin EJB } public void ejbRemove() { try { jndiContext.close(); ejbContext = null; } catch(NamingException ne) { /* do nothing */ } }

}

MessageDrivenBean Interface The Message-Driven Bean class is required to implement the javax.ejb.MessageDrivenBean interface, which defines callback methods similar to those in entity and session beans. Here is the definition of the MessageDrivenBean interface: package javax.ejb; public interface MessageDrivenBean extends javax.ejb.EnterpriseBean { public void setMessageDrivenContext(MessageDrivenContext context) throws EJBException; public void ejbRemove() throws EJBException; } The setMessageDrivenContext() method is called at the beginning of the MDB's life cycle and provides the MDB instance with a reference to its MessageDrivenContext: MessageDrivenContext ejbContext; Context jndiContext; public void setMessageDrivenContext(MessageDrivenContext mdc) { ejbContext = mdc; try { jndiContext = new InitialContext(); } catch(NamingException ne) { throw new EJBException(ne); } }

© Trendz Information Technologies Ltd.

Page No. 192 of 220

J2EE The setMessageDrivenContext() method in the ReservationProcessorBean class sets the ejbContext instance field to the MessageDrivenContext, which was passed into the method. It also obtains a reference to the JNDI ENC, which it stores in the jndiContext. MDBs may have instance fields that are similar to a stateless session bean's instance fields. These instance fields are carried with the MDB instance for its lifetime and may be reused every time it processes a new message. Unlike stateful session beans, MDBs do not have conversational state and are not specific to a single JMS client. MDB instances are used to processes messages from many different JMS clients and are tied to a specific topic or queue from which they receive messages, not to a specific JMS client. They are stateless in the same way that stateless session beans are stateless. ejbRemove() provides the MDB instance with an opportunity to clean up any resources it stores in its instance fields. In this case, we use it to close the JNDI context and set the ejbContext field to null. These operations are not absolutely necessary, but they illustrate the kind of operation that an ejbRemove() method might do. Note that ejbRemove() is called at the end of the MDB's life cycle, before it is garbage collected. It may not be called if the EJB server hosting the MDB fails or if an EJBException is thrown by the MDB instance in one of its other methods. When an EJBException (or any RuntimeException type) is thrown by any method in the MDB instance, the instance is immediately removed from memory and the transaction is rolled back. MessageDrivenContext The MessageDrivenContext simply extends the EJBContext; it does not add any new methods. The EJBContext is defined as: package javax.ejb; public interface EJBContext { // transaction methods public javax.transaction.UserTransaction getUserTransaction() throws java.lang.IllegalStateException; public boolean getRollbackOnly() throws java.lang.IllegalStateException; public void setRollbackOnly() throws java.lang.IllegalStateException; // EJB home methods public EJBHome getEJBHome(); public EJBLocalHome getEJBLocalHome(); // security methods public java.security.Principal getCallerPrincipal(); public boolean isCallerInRole(java.lang.String roleName); // deprecated methods public java.security.Identity getCallerIdentity(); public boolean isCallerInRole(java.security.Identity role); public java.util.Properties getEnvironment(); } Only the transactional methods the MessageDrivenContext inherits from EJBContext are available to message-driven beans. The home methods--getEJBHome() and getEJBLocalHome()--throw a RuntimeException if invoked, because MDBs do not
© Trendz Information Technologies Ltd. Page No. 193 of 220

J2EE have home interfaces or EJB home objects. The security methods-getCallerPrincipal() and isCallerInRole()--also throw a RuntimeException if invoked on a MessageDrivenContext. When an MDB services a JMS message there is no "caller," so there is no security context to be obtained from the caller. Remember that JMS is asynchronous and doesn't propagate the sender's security context to the receiver--that wouldn't make sense, since senders and receivers tend to operate in different environments. MDBs usually execute in a container-initiated or bean-initiated transaction, so the transaction methods allow the MDB to manage its context. The transaction context is not propagated from the JMS sender, but rather is either initiated by the container or by the bean explicitly using javax.jta.UserTransaction. The transaction methods in the EJBContext are explained in more detail in Chapter 14. Message-driven beans also have access to their own JNDI environment naming contexts (ENCs), which provide the MDB instances access to environment entries, other enterprise beans, and resources. For example, the ReservationProcessor EJB takes advantage of the JNDI ENC to obtain references to the Customer, Cruise, Cabin, Reservation, and ProcessPayment EJBs as well as a JMS QueueConnectionFactory and Queue for sending out tickets. MessageListener Interface In addition to the MessageDrivenBean interface, MDBs implement the javax.jms.MessageListener interface, which defines the onMessage() method; bean developers implement this method to process JMS messages received by a bean. It's in the onMessage() method that the bean processes the JMS message: package javax.jms; public interface MessageListener { public void onMessage(Message message); } It's interesting to consider why the MDB implements the MessageListener interface separately from the MessageDrivenBean interface. Why not just put the onMessage() method, MessageListener's only method, in the MessageDrivenBean interface so that there is only one interface for the MDB class to implement? This was the solution taken by an early proposed version of EJB 2.0. However, it was quickly realized that message-driven beans could, in the future, process messages from other types of systems, not just JMS. To make the MDB open to other messaging systems, it was decided that it should implement the javax.jms.MessageListener interface separately, thus separating the concept of the message-driven bean from the types of messages it can process. In a future version of the specification, other types of MDB might be available for technologies such as SMTP (email) or JAXM ( Java API for XML Messaging) for ebXML. These technologies will use methods other than onMessage(), which is specific to JMS. The onMessage( ) method: Workflow and integration for B2B The onMessage() method is where all the business logic goes. As messages arrive, they are passed to the MDB by the container via the onMessage() method. When the method returns, the MDB is ready to process a new message. In the ReservationProcessor EJB, the onMessage() method extracts information about a reservation from a MapMessage and uses that information to create a reservation in the system:
© Trendz Information Technologies Ltd. Page No. 194 of 220

J2EE

public void onMessage(Message message) { try { MapMessage reservationMsg = (MapMessage)message; Integer customerPk = (Integer)reservationMsg.getObject("CustomerID"); Integer cruisePk = (Integer)reservationMsg.getObject("CruiseID"); Integer cabinPk = (Integer)reservationMsg.getObject("CabinID"); double price = reservationMsg.getDouble("Price"); // get the credit card Date expirationDate = new Date(reservationMsg.getLong("CreditCardExpDate")); String cardNumber = reservationMsg.getString("CreditCardNum"); String cardType = reservationMsg.setString("CreditCardType"); CreditCardDO card = new CreditCardDO(cardNumber, expirationDate, cardType); JMS is frequently used as an integration point for business-to-business applications, so it's easy to imagine the reservation message coming from one of Titan's business partners (perhaps a third-party processor or branch travel agency). The ReservationProcessor EJB needs to access the Customer, Cruise, and Cabin EJBs in order to process the reservation. The MapMessage contains the primary keys for these entities; the ReservationProcessor EJB uses helper methods (getCustomer(), getCruise(), and getCabin()) to look up the entity beans and obtain EJB object references to them: public void onMessage(Message message) { ... CustomerRemote customer = getCustomer(customerPk); CruiseLocal cruise = getCruise(cruisePk); CabinLocal cabin = getCabin(cabinPk); ... } public CustomerRemote getCustomer(Integer key) throws NamingException, RemoteException, FinderException { Object ref = jndiContext.lookup("java:comp/env/ejb/CustomerHomeRemote"); CustomerHomeRemote home = (CustomerHomeRemote) PortableRemoteObject.narrow(ref, CustomerHomeRemote.class); CustomerRemote customer = home.findByPrimaryKey(key); return customer; } public CruiseLocal getCruise(Integer key) throws NamingException, FinderException { CruiseHomeLocal home = (CruiseHomeLocal) jndiContext.lookup("java:comp/env/ejb/CruiseHomeLocal"); CruiseLocal cruise = home.findByPrimaryKey(key);
© Trendz Information Technologies Ltd. Page No. 195 of 220

J2EE return cruise; } public CabinLocal getCabin(Integer key) throws NamingException, FinderException{ CabinHomeLocal home = (CabinHomeLocal) jndiContext.lookup("java:comp/env/ejb/CabinHomeLocal"); CabinLocal cabin = home.findByPrimaryKey(key); return cabin;

}

Once the information is extracted from the MapMessage, it is used to create a reservation and process the payment. This is basically the same workflow that was used by the TravelAgent EJB. A Reservation EJB is created that represents the reservation itself, and a ProcessPayment EJB is created to process the credit card payment: ReservationHomeLocal resHome = (ReservationHomeLocal) jndiContext.lookup("java:comp/env/ejb/ReservationHomeLocal"); ReservationLocal reservation = resHome.create(customer, cruise, cabin, price, new Date()); Object ref = jndiContext.lookup("java:comp/env/ejb/ProcessPaymentHomeRemote"); ProcessPaymentHomeRemote ppHome = (ProcessPaymentHomeRemote) PortableRemoteObject.narrow (ref, ProcessPaymentHomeRemote.class); ProcessPaymentRemote process = ppHome.create(); process.byCredit(customer, card, price); TicketDO ticket = new TicketDO(customer,cruise,cabin,price); deliverTicket(reservationMsg, ticket); This illustrates that, like a session bean, the MDB can access any other entity or session bean and use that bean to complete a task. In this way, the MDB fulfills its role as an integration point in B2B application scenarios. MDB can manage a process and interact with other beans as well as resources. For example, it is commonplace for an MDB to use JDBC to access a database based on the contents of the message it is processing. Sending messages from a Message-Driven Bean MDB can also send messages using JMS. The deliverTicket() method sends the ticket information to a destination defined by the sending JMS client: public void deliverTicket(MapMessage reservationMsg, TicketDO ticket) throws NamingException, JMSException{ Queue queue = (Queue)reservationMsg.getJMSReplyTo(); QueueConnectionFactory factory = (QueueConnectionFactory)
© Trendz Information Technologies Ltd. Page No. 196 of 220

J2EE jndiContext.lookup("java:comp/env/jms/QueueFactory"); QueueConnection connect = factory.createQueueConneciton(); QueueSession session = connect.createQueueSession(true,0); QueueSender sender = session.createSender(queue); ObjectMessage message = session.createObjectMessage(); message.setObject(ticket); sender.send(message); connect.close(); } As stated earlier, every message type has two parts: a message header and a message body (a.k.a. payload). The message header contains routing information and may also have properties for message filtering and other attributes, including a JMSReplyTo attribute. When a JMS client sends a message, it may set the JMSReplyTo attribute to be any destination accessible to its JMS provider. In the case of the reservation message, the sender set the JMSReplyTo attribute to the queue to which the resulting ticket should be sent. Another application can access this queue to read tickets and distribute them to customers or store the information in the sender's database. You can also use the JMSReplyTo address to report business errors that occur while processing the message. For example, if the Cabin is already reserved, the ReservationProcessor EJB might send an error message to the JMSReplyTo queue explaining that the reservation could not be processed. Including this type of error handling is left as an exercise for the reader. XML Deployment Descriptor MDBs have XML deployment descriptors, just like entity and session beans. They can be deployed alone or, more often than not, together with other enterprise beans. For example, the ReservationProcessor EJB would have to be deployed in the same JAR using the same XML deployment descriptor as the Customer, Cruise, and Cabin beans if it's going to use their local interfaces. Here's the XML deployment descriptor that defines the ReservationProcessor EJB. This deployment descriptor also defines the Customer, Cruise, Cabin, and other beans, but these are left out here for brevity: <enterprise-beans> ... <message-driven> <ejb-name>ReservationProcessorEJB</ejb-name> <ejb-class> com.titan.reservationprocessor.ReservationProcessorBean </ejb-class> <transaction-type>Container</transaction-type> <message-selector>MessageFormat = 'Version 3.4'</message-selector>
© Trendz Information Technologies Ltd. Page No. 197 of 220

J2EE <acknowledge-mode>Auto-acknowledge</acknowledge-mode> <message-driven-destination> <destination-type>javax.jms.Queue</destination-type> </message-driven-destination> <ejb-ref> <ejb-ref-name>ejb/ProcessPaymentHomeRemote</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <home>com.titan.processpayment.ProcessPaymentHomeRemote</home> <remote>com.titan.processpayment.ProcessPaymentRemote</remote> </ejb-ref> <ejb-ref> <ejb-ref-name>ejb/CustomerHomeRemote</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <home>com.titan.customer.CustomerHomeRemote</home> <remote>com.titan.customer.CustomerRemote</remote> </ejb-ref> <ejb-local-ref> <ejb-ref-name>ejb/CruiseHomeLocal</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <local-home>com.titan.cruise.CruiseHomeLocal</local-home> <local>com.titan.cruise.CruiseLocal</local> </ejb-local-ref> <ejb-local-ref> <ejb-ref-name>ejb/CabinHomeLocal</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <local-home>com.titan.cabin.CabinHomeLocal</local-home> <local>com.titan.cabin.CabinLocal</local> </ejb-local-ref> <ejb-local-ref> <ejb-ref-name>ejb/ReservationHomeLocal</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <local-home>com.titan.reservation.ReservationHomeLocal</local-home> <local>com.titan.reservation.ReservationLocal</local> </ejb-local-ref> <security-identity> <run-as> <role-name>everyone</role-name> </run-as> </security-identity> <resource-ref> <res-ref-name>jms/QueueFactory</res-ref-name> <res-type>javax.jms.QueueConnectionFactory</res-type> <res-auth>Container</res-auth> </resource-ref> </message-driven> ... </enterprise-beans> An MDB is declared in a <message-driven> element within the <enterprise-beans> element, alongside <session> and <entity> beans. Similar to <session> bean types, it defines an <ejb-name>, <ejb-class>, and <transaction-type>, but it does not define component interfaces (local or remote). MDBs do not have component interfaces, so these definitions aren't needed.
© Trendz Information Technologies Ltd. Page No. 198 of 220

J2EE

<message-selector> An MDB can also declare a <message-selector> element, which is unique to message-driven beans: <message-selector>MessageFormat = 'Version 3.4'</message-selector> Message selectors allow an MDB to be more selective about the messages it receives from a particular topic or queue. Message selectors use Message properties as criteria in conditional expressions. (Message selectors are also based on message headers, which are outside the scope of this chapter.) These conditional expressions use Boolean logic to declare which messages should be delivered to a client. Message properties, upon which message selectors are based, are additional headers that can be assigned to a message. They give the application developer or JMS vendor the ability to attach more information to a message. The Message interface provides several accessor and mutator methods for reading and writing properties. Properties can have a String value or one of several primitive values (boolean, byte, short, int, long, float, double). The naming of properties, together with their values and conversion rules, is strictly defined by JMS. The ReservationProcessor EJB uses a message selector filter to select messages of a specific format. In this case the format is "Version 3.4"; this is a string Titan uses to identify messages of type MapMessage that contain the name values CustomerID, CruiseID, CabinID, CreditCard, and Price. In other words, by specifying a MessageFormat on every reservation message, we can write MDBs that are designed to process different kinds of reservation messages. If a new business partner needs to use a different type of Message object, Titan would use a new message version and an MDB to process it. This is how a JMS producer would go about setting a MessageFormat property on a Message: Message message = session.createMapMessage(); message.setStringPropery("MessageFormat","Version 3.4"); // set the reservation named values sender.send(message); The message selectors are based on a subset of the SQL-92 conditional expression syntax that is used in the WHERE clauses of SQL statements. They can become fairly complex, including the use of literal values, Boolean expressions, unary operators, and so on. Message selector examples Here are three complex selectors used in hypothetical environments. Although you will have to use your imagination a little, the purpose of these examples is to convey the power of the message selectors. When a selector is declared, the identifier always refers to a property name or JMS header name. For example, the selector UserName !='William' assumes that there is a property in the message named UserName, which can be compared to the value 'William'.
© Trendz Information Technologies Ltd. Page No. 199 of 220

J2EE

Managing claims in an HMO Due to some fraudulent claims, an automatic process is implemented using MDBs that will audit all claims submitted by patients who are employees of the ACME manufacturing company for visits to chiropractors, psychologists, and dermatologists: <message-selector> <![CDATA[ PhysicianType IN ('Chiropractic','Psychologists','Dermatologist') AND PatientGroupID LIKE 'ACME%' ]]> </message-selector> TIP: MDB <message-selector> statements are declared in XML deployment descriptors. XML assigns special meaning to a variety of characters, such as the greater than (>) and less than (<) symbols, so using these symbols in the <message-selector> statements will cause parsing errors unless CDATA sections are used. This is the same reason CDATA sections were needed in EJB QL <ejb-ql> statements, as explained in Chapter 8. Notification of certain bids on inventory A supplier wants notification of requests for bids on specific inventory items at specific quantities: <message-selector> <![CDATA[ InventoryID ='S93740283-02' AND Quantity BETWEEN 1000 AND 13000 ]]> </message-selector> Selecting recipients for a catalog mailing An online retailer wants to deliver a special catalog to any customer that orders more than $500.00 worth of merchandise where the average price per item ordered is greater than $75.00 and the customer resides in one several states. The retailer creates an MBD that subscribes to the order-processing topic and processes catalog deliveries for only those customers that meet the defined criteria: <message-selector> <![CDATA[ TotalCharge >500.00 AND ((TotalCharge /ItemCount)>=75.00) AND State IN ('MN','WI','MI','OH') ]]> </message-selector> <acknowledge-mode> JMS has the concept of acknowledgment, which means that the JMS client notifies the JMS provider (message router) when a message is received. In EJB, it's the MDB container's responsibility to send an acknowledgment to the JMS provider when it receives a message. Acknowledging a message tells the JMS provider that MDB container has received the message and processed it using an MDB instance. Without an acknowledgment, the JMS provider will not know whether the MDB container has
© Trendz Information Technologies Ltd. Page No. 200 of 220

J2EE received the message, so it will try to redeliver it. This can cause problems. For example, once we have processed a reservation message using the ReservationProcessor EJB, we don't want to receive the same message again. When transactions are involved, the acknowledgment mode set by the bean provider is ignored. In this case, the acknowledgment is performed within the context of the transaction. If the transaction succeeds, the message is acknowledged. If the transaction fails, the message is not acknowledged. If the MDB is using containermanaged transactions, as it will in most cases, the acknowledgment mode is ignored by the MDB container. When using container-managed transactions with a Required transaction attribute, the <acknowledge-mode> is usually not specified; however, we included it in the deployment descriptor for the sake of discussion: <acknowledge-mode>Auto-acknowledge</acknowledge-mode> When the MDB executes with bean-managed transactions, or with the containermanaged transaction attribute NotSupported (see Chapter 14), the value of <acknowledge-mode> becomes important. Two values can be specified for <acknowledge-mode>: Auto-acknowledge and Dupsok-acknowledge. Auto-acknowledge tells the container that it should send an acknowledgment to the JMS provider soon after the message is given to an MDB instance to process. Dups-ok-acknowledge tells the container that it doesn't have to send the acknowledgment immediately; any time after the message is given to the MDB instance will be fine. With Dups-ok-acknowledge, it's possible for the MDB container to delay acknowledgment so long that the JMS provider assumes that the message was not received and sends a "duplicate" message. Obviously, with Dupsok-acknowledge, your MDBs must be able to handle duplicate messages correctly. Auto-acknowledge avoids duplicate messages because the acknowledgment is sent immediately. Therefore, the JMS provider won't send a duplicate. Most MDBs use Auto-acknowledge, to avoid processing the same message twice. Dups-okacknowledge exists because it may allow a JMS provider to optimize its use of the network. In practice, though, the overhead of an acknowledgment is so small, and the frequency of communication between the MDB container and JMS provider is so high, that Dups-ok-acknowledge doesn't have a big impact on performance. <message-driven-destination> The <message-driven-destination> element designates the type of destination from which the MDB receives messages. The allowed values for this element are javax.jms.Queue and javax.jms.Topic. In the ReservationProcessor EJB this value is set to javax.jms.Queue, indicating that the MDB is getting its messages via the p2p messaging model from a queue: <message-driven-destination> <destination-type>javax.jms.Queue</destination-type> </message-driven-destination> When the MDB is deployed, the deployer will map the MDB so that it listens to a real queue on the network. When the <destination-type> is a javax.jms.Topic, the <subscription-durability> element must be declared with either Durable or NonDurable as its value:
© Trendz Information Technologies Ltd. Page No. 201 of 220

J2EE

<message-driven-destination> <destination-type>javax.jms.Topic</destination-type> <subscription-durability>Durable</subscription-durability> </message-driven-destination> The <subscription-durability> element determines whether or not the MDB's subscription to the topic is Durable. A Durable subscription outlasts an MDB container's connection to the JMS provider, so if the EJB server suffers a partial failure, is shut down, or is otherwise disconnected from the JMS provider, the messages that it would have received will not be lost. While a Durable MDB container is disconnected from the JMS provider, it is the responsibility of the JMS provider to store any messages the subscriber misses. When the Durable MDB container reconnects to the JMS provider, the JMS provider sends it all the unexpired messages that accumulated while it was down. This behavior is commonly referred to as storeand-forward messaging. Durable MDBs are tolerant of disconnections, whether they are intentional or the result of a partial failure. If <subscription-durability> is NonDurable, any messages the bean would have received while it was disconnected will be lost. Developers use NonDurable subscriptions when it is not critical that all messages be processed. Using a NonDurable subscription improves the performance of the JMS provider but significantly reduces the reliability of the MDBs. When <destination-type> is javax.jms.Queue, as is the case in the ReservationProcessor EJB, durability is not a factor because of the nature of p2p or queue-based messaging systems. With a queue, messages may be consumed only once and remain in the queue until they are distributed to one of the queue's listeners. The rest of the elements in the deployment descriptor should already be familiar. The <ejb-ref> element provides JNDI ENC bindings for a remote EJB home object while the <ejb-local-ref> elements provide JNDI ENC bindings for local EJB home objects. Note that the <resource-ref> element that defined the JMS QueueConnectionFactory used by the ReservationProcessor EJB to send ticket messages is not accompanied by a <resource-env-ref> element. The queue to which the tickets are sent is obtained from the JMSReplyTo header of the MapMessage itself, and not from the JNDI ENC. The ReservationProcessor clients In order to test the ReservationProcessor EJB, we need to develop two new client applications: one to send reservation messages and the other to consume ticket messages produced by the ReservationProcessor EJB. The reservation message producer The JmsClient_ReservationProducer is designed to send 100 reservation requests very quickly. The speed with which it sends these messages will force many MDB containers to use multiple instances to process the reservation messages. The code for JmsClient_ReservationProducer looks like this: import import import import javax.jms.Message; javax.jms.MapMessage; javax.jms.QueueConnectionFactory; javax.jms.QueueConnection;
Page No. 202 of 220

© Trendz Information Technologies Ltd.

J2EE import import import import import import import javax.jms.QueueSession; javax.jms.Session; javax.jms.Queue; javax.jms.QueueSender; javax.jms.JMSException; javax.naming.InitalContext; java.util.Date;

import com.titan.processpayment.CreditCardDO; public class JmsClient_ReservationProducer { public static void main(String [] args) throws Exception { InitialContext jndiContext = getInitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) jndiContext.lookup("QueueFactoryNameGoesHere"); Queue reservationQueue = (Queue) jndiContext.lookup("QueueNameGoesHere"); QueueConnection connect = factory.createQueueConneciton(); QueueSession session = connect.createQueueSession(false,Session.AUTO_ACKNOWLEDGE); QueueSender sender = session.createSender(reservationQueue); Integer cruiseID = new Integer(1); for(int i = 0; i < 100; i++){ MapMessage message = session.createMapMessage(); message.setStringProperty("MessageFormat","Version 3.4"); message.setInt("CruiseID",1); message.setInt("CustomerID",i%10); message.setInt("CabinID",i); message.setDouble("Price", (double)1000+i); // the card expires in about 30 days Date expirationDate = new Date(System.currentTimeMillis()+43200000); message.setString("CreditCardNum", "923830283029"); message.setLong("CreditCardExpDate", expirationDate.getTime()); message.setString("CreditCardType", CreditCardDO.MASTER_CARD); sender.send(message); } } connect.close();

© Trendz Information Technologies Ltd.

Page No. 203 of 220

J2EE public static InitialContext getInitialContext() throws JMSException { // create vendor-specific JNDI context here } } You may have noticed that the JmsClient_ReservationProducer sets the CustomerID, CruiseID, and CabinID as primitive int values, but the ReservationProcessorBean reads these values as java.lang.Integer types. This is not a mistake. The MapMessage automatically converts any primitive to its proper wrapper if that primitive is read using MapMessage.getObject(). So, for example, a named value that is loaded into a MapMessage using setInt() can be read as an Integer using getObject(). For example, the following code sets a value as a primitive int and then accesses it as a java.long.Integer object: MapMessage mapMsg = session.createMapMessage(); mapMsg.setInt("TheValue",3); Integer myInteger = (Integer)mapMsg.getObject("TheValue"); if(myInteger.intValue() == 3 ) // this will always be true The ticket message consumer The JmsClient_TicketConsumer is designed to consume all the ticket messages delivered by ReservationProcessor EJB instances to the queue. It consumes the messages and prints out the descriptions: import import import import import import import import import import javax.jms.Message; javax.jms.ObjectMessage; javax.jms.QueueConnectionFactory; javax.jms.QueueConnection; javax.jms.QueueSession; javax.jms.Session; javax.jms.Queue; javax.jms.QueueReceiver; javax.jms.JMSException; javax.naming.InitalContext;

import com.titan.travelagent.TicketDO; public class JmsClient_TicketConsumer implements javax.jms.MessageListener { public static void main(String [] args) throws Exception { new JmsClient_TicketConsumer(); while(true){Thread.sleep(10000);} }

© Trendz Information Technologies Ltd.

Page No. 204 of 220

J2EE public JmsClient_TicketConsumer() throws Exception { InitialContext jndiContext = getInitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) jndiContext.lookup("QueueFactoryNameGoesHere"); Queue ticketQueue = (Queue)jndiContext.lookup("QueueNameGoesHere"); QueueConnection connect = factory.createQueueConneciton(); QueueSession session = connect.createQueueSession(false,Session.AUTO_ACKNOWLEDGE); QueueReceiver receiver = session.createReceiver(ticketQueue); receiver.setMessageListener(this); } connect.start();

public void onMessage(Message message) { try { ObjectMessage objMsg = (ObjectMessage)message; TicketDO ticket = (TicketDO)objMsg.getObject(); System.out.println("********************************"); System.out.println(ticket); System.out.println("********************************"); } catch(JMSException jmsE) { jmsE.printStackTrace(); }

} To make the ReservationProcessor EJB work with the two client applications, JmsClient_ReservationProducer and JmsClient_TicketConsumer, you must configure your EJB container's JMS provider so that it has two queues: one for reservation messages and another for ticket messages. The Life Cycle of a Message-Driven Bean Just as the entity and session beans have well-defined life cycles, so does the MDB bean. The MDB instance's life cycle has two states: Does Not Exist and Method-Ready Pool. The Method-Ready Pool is similar to the instance pool used for stateless session beans. Like stateless beans, MDBs define instance pooling in their life cycles. Figure 13-4 illustrates the states and transitions that an MDB instance goes through in its lifetime.

} public static InitialContext getInitialContext() throws JMSException { // create vendor-specific JNDI context here }

© Trendz Information Technologies Ltd.

Page No. 205 of 220

J2EE

Figure 13-4. MDB life cycle Does Not Exist When an MDB instance is in the Does Not Exist state, it is not an instance in the memory of the system. In other words, it has not been instantiated yet. The Method-Ready Pool MDB instances enter the Method-Ready Pool as the container needs them. When the EJB server is first started, it may create a number of MDB instances and enter them into the Method-Ready Pool. (The actual behavior of the server depends on the implementation.) When the number of MDB instances handling incoming messages is insufficient, more can be created and added to the pool. Transitioning to the Method-Ready Pool When an instance transitions from the Does Not Exist state to the Method-Ready Pool, three operations are performed on it. First, the bean instance is instantiated when the container invokes the Class.newInstance() method on the MDB class. Second, the setMessageDrivenContext() method is invoked by the container providing the MDB instance with a reference to its EJBContext. The MessageDrivenContext reference may be stored in an instance field of the MDB. Finally, the no-argument ejbCreate() method is invoked by the container on the bean instance. The MDB has only one ejbCreate() method, which takes no arguments. The ejbCreate() method is invoked only once in the life cycle of the MDB. MDBs are not subject to activation, so they can maintain open connections to resources for their entire life cycles. The ejbRemove() method should close any open resources before the MDB is evicted from memory at the end of its life cycle. Life in the Method-Ready Pool Once an instance is in the Method-Ready Pool, it is ready to handle incoming messages. When a message is delivered to an MDB, it is delegated to any available instance in the Method-Ready Pool. While the instance is executing the request, it is unavailable to process other messages. The MDB can handle many messages simultaneously, delegating the responsibility of handling each message to a different MDB instance. When a message is delegated to an instance by the container, the MDB instance's MessageDrivenContext changes to reflect the new transaction
© Trendz Information Technologies Ltd. Page No. 206 of 220

J2EE context. Once the instance has finished, it is immediately available to handle a new message. Transitioning out of the Method-Ready Pool: The death of an MDB instance Bean instances leave the Method-Ready Pool for the Does Not Exist state when the server no longer needs them. This occurs when the server decides to reduce the total size of the Method-Ready Pool by evicting one or more instances from memory. The process begins by invoking the ejbRemove() method on the instance. At this time, the bean instance should perform any cleanup operations, such as closing open resources. The ejbRemove() method is invoked only once in the life cycle of an MDB instance--when it is about to transition to the Does Not Exist state. During the ejbRemove() method, the MessageDrivenContext and access to the JNDI ENC are still available to the bean instance. Following the execution of the ejbRemove() method, the bean is dereferenced and eventually garbage collected. What's New in EJB 2.1? Only a few J2EE application servers are following the EJB 2.0 specification, and already the EJB 2.1 draft specification is out. For you busy folks who want to know about what the future has in store for EJBs but don't have the time to read a 636page document, here is a quick overview. Fair warning: the specification is a draft, so many parts are incomplete or will change. Quick List of New Features • • • • • Message-driven beans (MDBs): can now accept messages from sources other than JMS. EJB query language (EJB-QL): many new functions are added to this language: ORDER BY, AVG, MIN, MAX, SUM, COUNT, and MOD. Support for Web services: stateless session beans can be invoked over SOAP/HTTP. Also, an EJB can easily access a Web service using the new service reference. EJB timer service: a new event-based mechanism for invoking EJBs at specific times. Many small changes: support for the latest versions of Java specifications, XML schema, and message destinations.

Message-driven Bean Enhancements When the EJB 2.0 specification appeared, it introduced the idea of calling an EJB asynchronously, but you had to do it with JMS. JMS is not the only way to invoke an object asynchronously, however; other APIs exist, such as JAXM. How is this done with EJB 2.1? There are two things that differ. First, as you may know, in order to write an MDB class, it must implement some interfaces. These are javax.ejb.MessageDrivenBean and javax.jms.MessageListener. The latter is the interface that enables the EJB container to subscribe the bean to the JMS server. To make your EJB listen to another type of messaging server, the MDB must implement another interface. For example, in order to listen to JAXM messages, the MDB must implement javax.xml.messaging.OneWayListener or javax.xml.messaging.ReqRespListener. As for the second difference, obviously, the configuration side of a JMS-MDB will differ from a non-JMS one. The EJB container must know which destination or
© Trendz Information Technologies Ltd. Page No. 207 of 220

J2EE endpoint to which it must connect. The configuration of the MDB is done with a new <messaging-type> tag, and by specifying "configuration properties" with the tag <activation-config-propertyType>. This contains arbitrary name/value pairs that are specific to the messaging service being used. It is more versatile than being forced to use JMS-specific tags, like <message-selector>. The way non-JMS servers will plug into the EJB container is more or less overlooked in the current draft version of the specification. There is a mention of using the J2EECA, but no details are provided. This will probably be left to the EJB container to implement, just like persistence services. EJB-QL Enhancements When EJB-QL came out as a standard way to write queries, it was criticized for being a reinvention of the wheel. Don't we have already some querying languages, like SQL and XQuery? Plus, EJB-QL lacks several features that made it less than useful, in some cases. EJB 2.1 is trying to remedy these problems by extending the language to make it more SQL-like. Here are a few clauses and functions that are now added to this language.
ORDER BY

Ordering is something that's usually more optimized when it's done by the database than when it's done on the client side. This new clause simply works by specifying which fields to sort on, and if data needs to be sorted in ascending or descending order. For example: SELECT OBJECT(c) FROM ConsultantBean AS c ORDER BY c.city,c.startingDate DESC returns all consultants sorted by city, starting with the most senior.
MOD

This numeric function returns the rest of the division between an integer and another integer (modulo). For example: SELECT OBJECT(p) FROM PageBean AS p WHERE MOD(p.number,2) = 1 returns all odd-numbered pages.
AVG

AVG is an aggregate function that can be used for ejbSelect methods in the SELECT clause. It returns the average value of a specified field. For example: SELECT AVG(e.salary) FROM EmployeeBean AS e gets the average salary for all employees.
MIN

This aggregate function can be used for ejbSelect methods in the SELECT clause. It returns the minimum value of a specified field. For example: SELECT MIN(f.nextFlightDate) FROM FlightBean AS f WHERE f.departureAirport = ?1 AND f.arrivalAirport = ?2 gets the date when the next flight is scheduled between two cities.
MAX

This aggregate function can be used for ejbSelect methods in the SELECT clause. It returns the maximum value of a specified field. For example:
© Trendz Information Technologies Ltd. Page No. 208 of 220

J2EE

SELECT MAX(c.age) FROM ClientBean AS c returns the age of the oldest client.
SUM

This aggregate function can be used for ejbSelect methods in the SELECT clause. It adds up all values for a field. For example: SELECT SUM(q.sales) FROM QuarterBean AS q WHERE q.year = ?1 calculates the total of all sales for a certain year.
COUNT

This aggregate function counts the number of elements. It can only be used in ejbSelect methods and in the SELECT clause. For example: SELECT COUNT(s) FROM StoreBean AS s WHERE s.city = ?1 counts the number of stores in a certain city. About Aggregate Functions The aggregate functions (AVG, MIN, MAX, SUM, and COUNT) can be used with DISTINCT to eliminate duplicates before calculating. Personally, I don't see why all of these aggregate functions cannot be used in the WHERE clause, as well. The specification says these can be used in the SELECT clause only. It could be useful to test each record against a condition that uses an aggregate function. For example, getting all employees whose salary is above average: SELECT OBJECT(e) FROM EmployeeBean AS e WHERE e.salary > AVG(e.salary) One can work around this with an ejbSelect method, or in other ways. Web Services One of the best features of EJB 2.1 is the support for Web services. This applies to two different areas: accessing an EJB as if it were a Web service, and an EJB directly accessing a Web service. EJB As Web Service A stateless session EJB can now be accessed through a Web service. In order to do that, the client must use SOAP over HTTP or HTTPS, and use a WSDL descriptor. Furthermore, the stateless session bean must be invoked "RPC-style." To help with the development of Web-service-enabled beans, the specification was changed in these ways: • • • • SessionContext.getMessageContext() was added, to get a javax.xml.rpc.handler.MessageContext from within the bean implementation. The container is now required to provide a tool that can produce Web service facades in front of stateless session beans (called "Web Service endpoint interface implementation class"). The home interface is now optional, while the ejbCreate() method is still needed. The specification stipulates that for each stateless session bean, a WSDL file must be provided, and its interfaces must match the bean's methods. This WSDL file can be generated by the container.
Page No. 209 of 220

© Trendz Information Technologies Ltd.

J2EE • • • • • A new <service-endpoint> element has been added to ejb-jar.xml. The Mandatory transaction attribute is not accepted for stateless-sessionbean Web services. This is understandable, because transactions cannot be propagated from the client to the bean, as in RMI invocations. <method-intf> accepts ServiceEndPoint as a value. Exceptions are transformed into SOAP faults. Note that the server has no control over the client's transactions, so it cannot roll them back if a system exception happens. There doesn't seem to be any special note regarding security. But the credentials cannot be sent from the client to the bean the way RMI does, so I suspect that the usage of declarative security (using <method-permission>) will require the use of the <run-as> tag.

Forcing the use of HTTP is somewhat restrictive, since Web services are supposed to accept any protocol and technology, but this follows the general trend. By spelling out these restrictions, though, I think we will get into the same trap as JMS-only message-driven beans. The specification will later have to change to accommodate more standards. Many people have pointed out the disconnection between what exists in the Web service realm and what is available in EJBs. Here are a few examples: • • • How can the client's identity be propagated to the EJB? How can one set permissions? How can the client demarcate transactions? How can the client perform connection-based services (stateful session) or obtain data (entity)?

While these things are not addressed in the specification, they are not addressed in SOAP, either. There are programmatic solutions around those limitations, and it will be up to the container providers and/or bean developers to invent these solutions. EJB Accessing a Web Service An EJB can directly access a Web service, simply as a regular Web service client does. But this means the Web service's location has to be hard-coded in the bean implementation's code. This is not ideal, because if the Web service moves to a new location, the EJB must be modified and recompiled. To work around this problem, the new EJB 2.1 specification introduces the concept of a Web service reference. This is exactly the same concept as environment entries, EJB references, and resource references. Adding a Web service reference in ejb-jar.xml is done using the new tag <service-ref>. It is up to the container provider to map the reference to the actual Web service location. The reference can be looked up in the bean implementation, and the resulting factory object can be used to connect to the Web service. EJB Timer Service The new EJB 2.1 timer service is a mechanism to enable time-based business logic. For example, one could want to automatically: • • Run a certain query in five minutes. Delete the content of the "garbage can" database table one hour from now, and then every two hours.

© Trendz Information Technologies Ltd.

Page No. 210 of 220

J2EE • • Post an email saying "server shutdown in 1 hour" to all employees next Saturday at 11 pm. Send a usage report to the administrator every Monday at 8 am.

Note that this timer service is not meant to be used in real-time systems. Notifications will be sent at approximate times. To set up a timer object, use the method EJBContext.getTimerService(), returning a javax.ejb.TimerService object. This object is a factory for creating javax.ejb.Timer objects. Once such an object is created, the container will take care of calling the bean at the right time. Timer objects can later be retrieved using the TimerService object or with a TimerHandle (Serializable), and they can be cancelled and reconfigured. Only "stateless" objects (stateless session beans, pooled entity beans) can process timer events. Their bean implementations must implement the javax.ejb.TimedObject interface, which contains a single method: void ejbTimeout(Timer). Also, the security identity during the timer call can be specified using <run-as>; othrwise, permissions cannot be verified. Lastly, it is not clear how the EJB container provider will know which bean is linked to which timer. Timer creation methods do not have parameters to specify which bean would consume the ejbTimeout events. Plus it would be nice to have the choice of setting up timers declaratively in ejb-jar.xml (this would take effect at deployment time). Other New Features Here's a list of (smaller) new features: • EJB containers must now support the newest specifications: J2SE 1.4, JMS 1.1, JavaMain 1.3, JAF 1.0, JAXP 1.2, JAXR 1.0, and JAX-RPC 1.0. • The ejb-jar.xml standard deployment descriptor is now specified with XML schema, rather than DTD. • Message destinations (the same idea as EJB references, resource references, etc.) have been added.

J2EE DESIGN PATTERNS Model – View – Controller:
© Trendz Information Technologies Ltd. Page No. 211 of 220

J2EE Despite its relatively recent introduction, Java Server Pages (JSP) technology is well on its way to becoming the preeminent Java technology for building applications that serve dynamic Web content. Java developers love JSP for myriad reasons. Some like the fact that it brings the "write once, run anywhere" paradigm to interactive Web pages; others appreciate the fact that it is fairly simple to learn and lets them wield Java as a server-side scripting language. But most concur on one thing -- the biggest advantage of using JSP is that it helps effectively separate presentation from content. In this article, I provide an in-depth look at how you can gain optimal separation of presentation from content by using the JSP Model 2 architecture. This model can also be seen as a server-side implementation of the popular Model-ViewController (MVC) design pattern. Please note that you should be familiar with the basics of JSP and servlet programming before continuing on, as I do not address any syntax issues in this article.
So, what's wrong with servlets?

While JSP may be great for serving up dynamic Web content and separating content from presentation, some may still wonder why servlets should be cast aside for JSP. The utility of servlets is not in question. They are excellent for server-side processing, and, with their significant installed base, are here to stay. In fact, architecturally speaking, you can view JSP as a high-level abstraction of servlets that is implemented as an extension of the Servlet 2.1 API. Still, you shouldn't use servlets indiscriminately; they may not be appropriate for everyone. For instance, while page designers can easily write a JSP page using conventional HTML or XML tools, servlets are more suited for back-end developers because they are often written using an IDE -- a process that generally requires a higher level of programming expertise. When deploying servlets, even developers have to be careful and ensure that there is no tight coupling between presentation and content. You can usually do this by adding a third-party HTML wrapper package like htmlKona to the mix. But even this approach, though providing some flexibility with simple screen changes, still does not shield you from a change in the presentation format itself. For example, if your presentation changed from HTML to DHTML, you would still need to ensure that wrapper packages were compliant with the new format. In a worst-case scenario, if a wrapper package is not available, you may end up hardcoding the presentation within the dynamic content. So, what is the solution? As you shall soon see, one approach would be to use both JSP and servlet technologies for building application systems.
Differing philosophies

The early JSP specifications advocated two philosophical approaches for building applications using JSP technology. These approaches, termed the JSP Model 1 and Model 2 architectures, differ essentially in the location at which the bulk of the request processing was performed. In the Model 1 architecture, shown in Figure 1, the JSP page alone is responsible for processing the incoming request and replying back to the client. There is still separation of presentation from content, because all data access is performed using beans. Although the Model 1 architecture should be perfectly suitable for simple applications, it may not be desirable for complex implementations. Indiscriminate usage of this architecture usually leads to a significant amount of scriptlets or Java code embedded within the JSP page, especially if there is a significant amount of request processing to be performed. While this may not seem to be much of a problem for Java developers, it is certainly an issue if your JSP pages are created and maintained by designers -- which is usually the norm on large projects. Ultimately, it may even lead to an unclear

© Trendz Information Technologies Ltd.

Page No. 212 of 220

J2EE definition of roles and allocation of responsibilities, causing easily avoidable projectmanagement headaches.

Figure 1: JSP Model 1 architecture The Model 2 architecture, shown in Figure 2, is a hybrid approach for serving dynamic content, since it combines the use of both servlets and JSP. It takes advantage of the predominant strengths of both technologies, using JSP to generate the presentation layer and servlets to perform process-intensive tasks. Here, the servlet acts as the controller and is in charge of the request processing and the creation of any beans or objects used by the JSP, as well as deciding, depending on the user's actions, which JSP page to forward the request to. Note particularly that there is no processing logic within the JSP page itself; it is simply responsible for retrieving any objects or beans that may have been previously created by the servlet, and extracting the dynamic content from that servlet for insertion within static templates. In my opinion, this approach typically results in the cleanest separation of presentation from content, leading to clear delineation of the roles and responsibilities of the developers and page designers on your programming team. In fact, the more complex your application, the greater the benefits of using the Model 2 architecture should be.

Figure 2: JSP Model 2 architecture
© Trendz Information Technologies Ltd. Page No. 213 of 220

J2EE

Session Facade Context Enterprise beans encapsulate business logic and business data and expose their interfaces, and thus the complexity of the distributed services, to the client tier. Problem In a multitiered Java 2 Platform, Enterprise Edition (J2EE) application environment, the following problems arise:    Tight coupling, which leads to direct dependence between clients and business objects; Too many method invocations between client and server, leading to network performance problems; Lack of a uniform client access strategy, exposing business objects to misuse.

A multitiered J2EE application has numerous server-side objects that are implemented as enterprise beans. In addition, some other arbitrary objects may provide services, data, or both. These objects are collectively referred to as business objects, since they encapsulate business data and business logic. J2EE applications implement business objects that provide processing services as session beans. Coarse-grained business objects that represent an object view of persistent storage and are shared by multiple users are usually implemented as entity beans. Application clients need access to business objects to fulfill their responsibilities and to meet user requirements. Clients can directly interact with these business objects because they expose their interfaces. When you expose business objects to the client, the client must understand and be responsible for the business data object relationships, and must be able to handle business process flow. However, direct interaction between the client and the business objects leads to tight coupling between the two, and such tight coupling makes the client directly dependent on the implementation of the business objects. Direct dependence means that the client must represent and implement the complex interactions regarding business object lookups and creations, and must manage the relationships between the participating business objects as well as understand the responsibility of transaction demarcation. As client requirements increase, the complexity of interaction between various business objects increases. The client grows larger and more complex to fulfill these requirements. The client becomes very susceptible to changes in the business object layer; in addition, the client is unnecessarily exposed to the underlying complexity of the system. Tight coupling between objects also results when objects manage their relationship within themselves. Often, it is not clear where the relationship is managed. This leads to complex relationships between business objects and rigidity in the application. Such lack of flexibility makes the application less manageable when changes are required.

© Trendz Information Technologies Ltd.

Page No. 214 of 220

J2EE When accessing the enterprise beans, clients interact with remote objects. Network performance problems may result if the client directly interacts with all the participating business objects. When invoking enterprise beans, every client invocation is potentially a remote method call. Each access to the business object is relatively fine-grained. As the number of participants increases in a scenario, the number of such remote method calls increases. As the number of remote method calls increases, the chattiness between the client and the server-side business objects increases. This may result in network performance degradation for the application, because the high volume of remote method calls increases the amount of interaction across the network layer. A problem also arises when a client interacts directly with the business objects. Since the business objects are directly exposed to the clients, there is no unified strategy for accessing the business objects. Without such a uniform client access strategy, the business objects are exposed to clients and may reduce consistent usage. Forces    Provide a simpler interface to the clients by hiding all the complex interactions between business components. Reduce the number of business objects that are exposed to the client across the service layer over the network. Hide from the client the underlying interactions and interdependencies between business components. This provides better manageability, centralization of interactions (responsibility), greater flexibility, and greater ability to cope with changes. Provide a uniform coarse-grained service layer to separate business object implementation from business service abstraction. Avoid exposing the underlying business objects directly to the client to keep tight coupling between the two tiers to a minimum.

 

Solution Use a session bean as a facade to encapsulate the complexity of interactions between the business objects participating in a workflow. The Session Facade manages the business objects, and provides a uniform coarse-grained service access layer to clients. The Session Facade abstracts the underlying business object interactions and provides a service layer that exposes only the required interfaces. Thus, it hides from the client's view the complex interactions between the participants. The Session Facade manages the interactions between the business data and business service objects that participate in the workflow, and it encapsulates the business logic associated with the requirements. Thus, the session bean (representing the Session Facade) manages the relationships between business objects. The session bean also manages the life cycle of these participants by creating, locating (looking up), modifying, and deleting them as required by the workflow. In a complex application, the Session Facade may delegate this lifestyle management to a separate object. For example, to manage the lifestyle of participant session and entity beans, the Session Facade may delegate that work to a Service Locator object
© Trendz Information Technologies Ltd. Page No. 215 of 220

J2EE

It is important to examine the relationship between business objects. Some relationships between business objects are transient, which means that the relationship is applicable to only that interaction or scenario. Other relationships may be more permanent. Transient relationships are best modeled as workflow in a facade, where the facade manages the relationships between the business objects. Permanent relationships between two business objects should be studied to determine which business object (if not both objects) maintains the relationship. Other Patterns: The term J2EE is tossed around a lot because it is a generic term that covers many areas of enterprise and distributed development. The J2EE modules and environment continue to grow as a rapid pace, and as many of you have come to learn, in recent years J2EE development has had its trials and tribulations. For exactly this reason, it is important to take advantage of the most efficient and effective strategies for new development or the refactoring of existing projects. To keep up with the new developments, it is imperative that you aren't wasting time maintaining designs that have poor architecture or code that was poorly written. This article covers how to use and identify design patterns, specifically for the presentation tier, in J2EE applications. The interest in design patterns has been around for a number of years in the software industry. However, interest among mainstream software developers is a fairly recent development -- and one that's long overdue, in my opinion. There are a number of reasons for this: it takes a highly experienced engineer to recognize a pattern; it requires collaboration; and it requires ongoing refinements. It also requires a sense of fluidity. Design patterns are not absolutes -- they are more expressions of proven solutions. It is up to you, the engineer or architect, to apply a pattern appropriately to your given scenario. This, of course, is easier said than done. Patterns are not a magic pill. Just because a problem is observed and a pattern applied does not mean that you will have a perfect application -- or solution, for that matter. Patterns are a way of bringing clarity to a system architecture and they allow for the possibility of better systems being built. Building a system that meets the intended business requirements, performs well, is maintainable, and is delivered on time, is what keeps us engineers in business. Patterns have the distinct advantage of helping us do it all quicker. So, What is a Design Pattern Anyway? First of all, let's define what a design pattern is. There are a number of formal definitions, but I prefer a simple approach: a design pattern is simply a description of a recurring solution to a problem, given a context. Simple enough. The context is the environment, surroundings, situation, or interrelated conditions within which the problem exists. Design patterns have a number of advantages, among which are: • • • • They capture engineering experience. Once described, any level engineer can use the pattern. They allow for reuse without having to reinvent the wheel on a project-byproject basis. They allow for us, as engineers, to better define system structure.
Page No. 216 of 220

© Trendz Information Technologies Ltd.

J2EE • • They provide a design vocabulary. They also provide reusable artifacts.

It is a rare instance (although not an impossible one), that a design pattern is used in an isolated fashion. Typically, patterns have relationships and work together to form a weave, in that a pattern can be composed of, or rely on, other patterns. That is why you will see that the more familiar you are with different patterns, the better equipped you are to determine their interactions. Patterns can also form frameworks that can then be used for implementations. Enterprise systems are built crossing many tiers; this should not be news to anyone reading this article. This discussion is focused on the presentation tier, and primarily covers patterns that can be used with JSP and Servlet technology. Show Me Your Pattern There are a number of patterns that have been identified by the Sun Java Center for the presentation tier. These are certainly not the only patterns that can be applied, but they are a good starting point. The presentation patterns take into consideration the logic required to service clients that access the system. This includes client requests, single sign-on, session management, access to business services, as well as the creation, formatting, and delivery of responses to the client. These patterns include: • • • • • • Intercepting Filter: facilitates preprocessing and post-processing of a request. Front Controller: provides a centralized controller for managing the handling of requests. View Helper: encapsulates logic that is not related to presentation formatting into Helper components. Composite View: creates an aggregate View from atomic subcomponents. Service To Worker: combines a Dispatcher component with the Front Controller and View Helper patterns. Dispatch View: combines a Dispatcher component with the Front Controller and View Helper patterns, deferring many activities to View processing.

While the patterns listed above might not mean anything to you now, by the time you finish this article, you will understand how using patterns to describe solutions will give you a clear understanding of the problem being discussed, just by the use of the pattern name. Think of the time that will be saved in meetings by just saying, "I think the View Helper can be applied here," instead of droning on about a complete problem description that we've all faced many times. Helpful Hints A couple of words of advice if you are just starting on your pattern odyssey. If you haven't boned up on UML yet, the time is now. UML is quite commonly used to describe patterns in pattern catalogs, including class diagrams, sequence or interaction diagrams, and stereotypes. I'm not going to go into UML in this article, but I highly recommend getting up to speed on it. When using patterns, it is important to define a naming convention. It will be much easier to manage a project as it grows and identify exactly what role an object plays by using such naming conventions. For example, if you are using the View Helper or
© Trendz Information Technologies Ltd. Page No. 217 of 220

J2EE Composite View patterns, you might want to define the naming convention to be [action]Helper.java or [action].jsp, respectively; for instance, CreatePageHelper.java or CreatePage.jsp. Make a list of requirement statements that you will be addressing and then try to identify relevant patterns (once you are familiar with them) that might be applicable. By doing this, you will be amazed at how quickly you will start to recognize appropriate solutions to problems. For example: • • • •
Requirement: I need one place of control for handling all requests. Possible pattern: Front Controller Intercepting Filter. Requirement: I need a generic command interface for delegating processing

from

Possible pattern: Front Controller. Requirement: I want to make sure data related to my presentation formatting

a

controller

to

various

helper

components.

logic

is

encapsulated

correctly.

Possible pattern: View Helper. Requirement: I need to be able to create one View from a number of sub-

Views.

Possible pattern: Composite view.

Intercepting Filter The Intercepting Filter intercepts incoming requests and outgoing responses, and applies a filter. Filters may be added and removed in a declarative manner, allowing them to be applied in a variety of combinations. After pre- or post-processing is finished, the final filter in the group passes control to the original target object, typically a Front Controller. Front Controller A Front Controller is a container that holds common processing logic that occurs within the presentation tier and that may otherwise be misplaced in a View. A controller handles requests and manages content retrieval, security, view management, navigation, and delegation to a Dispatcher component, which further dispatches to a View. View Helper View Helper encourages the separation of formatting-related code from other business logic. It suggests using Helper components to encapsulate logic relating to initiating content retrieval and validation, as well as adapting and formatting the model. The View component is then left to encapsulate the presentation formatting. Helper components typically delegate to Business Services (a business-tier pattern which we won't be discussing further). Composite View The Composite View composes a View from numerous pieces. Multiple smaller views, which could be either static or dynamic, are pieced together to create a single template. Service to Worker and Dispatcher View The Service to Worker and Dispatcher View patterns are a combination of other patterns. They share a common structure with common components, consisting of a controller working with a Dispatcher, Views, and Helpers, but the division of labor is different. The Dispatcher View defers content retrieval and error handling to the time
© Trendz Information Technologies Ltd. Page No. 218 of 220

J2EE of View processing. This pattern also suggests that the Dispatcher plays a more limited role in the View management, as the choice of the View is typically already included in the request. You may already be using pattern-like strategies in your development process without even being aware of it. By identifying and becoming familiar with particular patterns, you will see that what might first appear as a problem that requires a rollyour-own solution might be better served by using a defined pattern. Let's explore a sample development scenario using the View Helper pattern and see how this might work. Sample Scenario Our scenario is a system that creates presentation content that requires processing of dynamic business data. This is a fairly common scenario to anyone doing J2EE development. The problem is that it is not uncommon for changes to occur in the presentation tier during the course of development. When business data logic and presentation-formatting logic are mingled together, the system becomes less flexible, harder to maintain, and provides a poor separation of tiers. Most of us -- even me -are guilty at one point or another of coding Java into our JSPs. We want to avoid this situation. Enter the View Helper pattern. The solution is to enforce this pattern so that the View contains formatting code, delegating its processing responsibilities to its helper classes. These classes might be implemented in a number of ways, including JavaBeans or custom tags. Helpers also store the View's intermediate data model and serve as business data adapters. It is important not to confuse a solution with its implementation strategy. For example, it's possible to implement this type of solution using a JSP View strategy, which uses a JSP as the View component. While this is a common strategy, it's also possible to take a Servlet View strategy, which uses a Servlet as a view instead. While we all know that a JSP actually becomes a Servlet, the strategy chosen becomes a matter of preference among the teams involved, as well as of the requirements of your project. We have identified that we will use the View Helper pattern in our project. The class diagram for this pattern is shown in Figure 1.

Figure 1. The class diagram tells us what components we will need to create in order to realize this pattern. Remember the naming conventions we spoke about earlier! (As a side note, if you are working with Rational Rose, there are a number of patterns included in v2002 that allow for the actual classes that need to be realized for a pattern to be
© Trendz Information Technologies Ltd. Page No. 219 of 220

J2EE generated for you. Depending on the pattern you select, the appropriate classes are created. It's quite convenient.) By using a sequence diagram that represents the View Helper pattern, we are quickly able to see the logic flow.

Figure 2. The View represents and displays information to the client. Dynamic data is required, and the display is retrieved from a model. The helpers are used to support the View by encapsulating and adapting the model for displaying. A Helper is called a ValueBean if it is storing intermediate data from the model needed by the View. How the helper is implemented doesn't really matter; it could be a JavaBean or a custom tag, as we previously discussed. It could also be an XSL transformer, if XSL is being used for converting the model into the appropriate output for a specific client device. The Business Service is the service the client is trying to access -- the Business Service would typically branch off into another pattern specific to handling control and protection of the business service. By using this pattern, we improve the tier partitioning and maintainability of our application by using helpers, as well as providing JavaBeans, custom tags, or XSL files that could very well be reused on other projects. The View Helper is also a good example of when a pattern is commonly used in conjunction with other patterns. Take note: this is just the beginning. While this simple sequence diagram is a starting point, you will have to learn how to adapt your system modelling to your own development. Transforming patterns and strategies into an implementation is nontrivial. The more familiar you become with patterns, their strategies, and their implementation, the quicker you will be able to determine what you need for a specific project.

© Trendz Information Technologies Ltd.

Page No. 220 of 220

Sign up to vote on this title
UsefulNot useful