12.2 Integrating with J2EE

Java Servlet Programming, 2nd Edition > 12. Enterprise Servlets and J2EE > 12.2 Integrating with J2EE

 
< BACKCONTINUE >

12.2 Integrating with J2EE

Throughout the rest of this book, servlets have been used as a standalone technology built upon the standard Java base. Servlets have another life, however, where they act as an integral piece of what's known as Java 2, Enterprise Edition , or J2EE for short.[2] J2EE 1.2 collects together several server-side APIs including Servlet API 2.2, JSP 1.1, EJB, JavaMail, the Java Messaging Service ( JMS), Java Transactions ( JTA), CORBA, JDBC, the Java API for XML Parsing ( JAXP), and the Java Naming and Directory Interface ( JNDI). J2EE makes the whole greater than the sum of its parts by defining how these technologies can interoperate and make use of one another, and providing certification that certain application servers are J2EE compliant, meaning they provide all the required services as well as the extra connection glue.

[2] Most pronounce J2EE as J-2-E-E but those who know it best at Sun just say "jah-too-ee."

12.2.1 J2EE Division of Labor

J2EE breaks enterprise application development into six distinct roles. Of course, an individual may participate in more than one role and multiple individuals may work together in a given role.

J2EE product provider

The operating system vendor, database system vendor, application server vendor, and/or web server vendor. The product provider provides an implementation of the J2EE APIs and tools for application deployment and management.

Application component provider

The author of the application's servlets, EJB, and other code as well as general content such as HTML. (In other words, you.)

Application assembler

Takes the application's components and (using tools from the product provider) places them in a form appropriate for deployment. As part of this the assembler describes the external dependencies of the application that may change from deployment to deployment, like database or user login information.

Deployer

Takes the output of the assembler and (using tools from the product provider) installs, configures, and executes the application. The configuration task requires satisfying the external dependencies outlined by the assembler.

System administrator

Configures and administers the network infrastructure to keep the application alive.

Tool provider

Creates tools to support J2EE development, beyond those provided by the product provider.

The division of labor between component provider, assembler, and deployer has an impact on how we (as servlet programmers in the content provider role) behave. Specifically, we should design our code to make external dependencies clear for the assembler, and furthermore we should use mechanisms that allow the deployer to satisfy these dependencies without modifying the files received from the assembler. That means no deployer edits to the web.xml file! Why not? Because J2EE applications are assembled into Enterprise Archive (.ear) files of which a contained web application's web.xml file is but one uneditable part.

This sounds more difficult than it actually is. J2EE provides a standard mechanism to achieve this abstraction using JNDI and a few special tags in the web.xml deployment descriptor. JNDI is an object lookup mechanism, a way to bind objects under certain paths and locate them later using that path. You can think of it like an RMI registry, except it's more general with support for accessing a range of services including LDAP and NIS (and even, in fact, the RMI registry!). An assembler declares external dependencies within the web.xml using special tags, a deployer satisfies these dependencies using server-specific tools, and at runtime our Java code uses the JNDI API to access the external resources kindly placed there by the J2EE-compliant server. All goals are satisfied: our Java code remains portable between J2EE-compliant servers, and the deployer can satisfy the code's external dependencies without modifying the files received from the assembler. There's even enough flexibility left over for server vendors to compete on implementations of the standard.

12.2.2 Environment Entries

Context init parameters serve a useful purpose with servlets, but there's a problem with context init parameters in the J2EE model: any change to a parameter value requires a modification to the web.xml file. For parameter values that may need to change during deployment, it's better to use environment entries instead, as indicated by the <env-entry> tag. The <env-entry> tag may contain a <description>, <env-entry-name>, <env-entry-value>, and <env-entry-type>. The following <env-entry> specifies whether the application should enable sending of PIN codes by mail:

  <env-entry>     <description>Send pincode by mail</description>     <env-entry-name>mailPincode</env-entry-name>     <env-entry-value>false</env-entry-value>     <env-entry-type>java.lang.Boolean</env-entry-type> <!-- FQCN -->   </env-entry>

The <description> explains to the deployer the purpose of this entry. It's optional but a good idea to provide. The <env-entry-name> is used by Java code as part of the JNDI lookup. The <env-entry-value> defines the default value to be presented to the deployer. It's optional, but not specifying a value requires the deployer to provide one. The <env-entry-type> represents the fully qualified class name (FQCN) of the entry. The type may be a String, Byte, Short, Integer, Long, Boolean, Double, or Float (all with their full java.lang qualification). The type helps the deployer know what's expected. If you're familiar with the EJB deployment descriptor, these tags may look familiar; they have the same names and semantics in EJB as well.

Java code can retrieve the <env-entry> values using JNDI:

Context initCtx = new InitialContext(); Boolean mailPincode = (Boolean) initCtx.lookup("java:comp/env/mailPincode");

All entries are placed by the server into the java:comp/env context. If you're new to JNDI, you can think of this as a URL base or filesystem directory. The java:comp/env context is read-only and unique per web application, so if two different web applications define the same environment entry, the entries do not collide. The context abbreviations, by the way, stand for component environment.

Example 12-1 shows a servlet that displays all its environment entries, using the JNDI API to browse the java:comp/env context.

Example 12-1. Snooping the java:comp/env Context
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import javax.naming.*; public class EnvEntrySnoop extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/plain");     PrintWriter out = res.getWriter();     try {       Context initCtx = new InitialContext();       NamingEnumeration enum = initCtx.listBindings("java:comp/env");       // We're using JDK 1.2 methods; that's OK since J2EE requires JDK 1.2       while (enum.hasMore()) {         Binding binding = (Binding) enum.next();         out.println("Name: " + binding.getName());         out.println("Type: " + binding.getClassName());         out.println("Value: " + binding.getObject());         out.println();       }     }     catch (NamingException e) {       e.printStackTrace(out);     }   } }

Assuming the previous web.xml entry, the servlet would generate:

Name: mailPincode Type: java.lang.Boolean Value: false

Remember, a server that does not support J2EE is not required to support these tags or any of the tags we talk about in this section.

12.2.3 References to EJB Components

When the environment entry object is an EJB component, there's a special <ejb-ref> tag that must be used. It provides a way for servlets to get a handle to an EJB using an abstract name. The deployer ensures the availability of an appropriate bean at runtime based on the constraints given by the <ejb-ref> tag. The tag may contain a <description>, <ejb-ref-name>, <ejb-ref-type>, <home>, <remote>, and <ejb-link>. Here's a typical <ejb-ref>:

<ejb-ref>   <description>Cruise ship cabin</description>   <ejb-ref-name>ejb/CabinHome</ejb-ref-name>   <ejb-ref-type>Entity</ejb-ref-type>   <home>com.titan.cabin.CabinHome</home>   <remote>com.titan.cabin.Cabin</remote> </ejb-ref>

These tags also have similar counterparts in EJB, and in fact this example is borrowed from the book Enterprise JavaBeans by Richard Monson-Haefel (O'Reilly). The <description> supports the deployer and is optional but recommended. The <ejb-ref-name> dictates the JNDI lookup name. It's recommended (but not required) that the name be placed within the ejb/ subcontext, making the full path to the bean java:comp/env/ejb/CabinHome. The <ejb-ref-type> must have a value of either Entity or Session, the two types of EJB components.[3] Finally, the <home> element specifies the fully qualified class name of the EJB's home interface, while the <remote> element specifies the FQCN of the EJB's remote interface.

[3] The Servlet API 2.2 Specification states, "The ejb-ref-type element contains the expected Java class type of the referenced EJB." This is a confirmed mistake. The actual purpose is as stated here.

A servlet would obtain a reference to the Cabin bean with the following code:

InitialContext initCtx = new InitialContext(); Object ref = initCtx.lookup("java:comp/env/ejb/CabinHome"); CabinHome home =   (CabinHome) PortableRemoteObject.narrow(ref, CabinHome.class);

If the assembler writing the web.xml file has a specific EJB component in mind for an EJB reference, that information can be conveyed to the deployer with the addition of the optional <ejb-link> element. The <ejb-link> element should refer to the <ejb-name> of an EJB component registered in an EJB deployment descriptor within the same J2EE application. The deployer has the option to use the suggestion or override it. Here's an updated web.xml entry:

<ejb-ref>   <description>Cruise ship cabin</description>   <ejb-ref-name>ejb/CabinHome</ejb-ref-name>   <ejb-ref-type>Entity</ejb-ref-type>   <home>com.titan.cabin.CabinHome</home>   <remote>com.titan.cabin.Cabin</remote>   <ejb-link>CabinBean</ejb-link> </ejb-ref>

12.2.4 References to External Resource Factories

Finally, for those times when the environment entry is a resource factory, there's a <resource-ref> tag to use. A factory is an object that creates other objects on demand. A resource factory creates resource objects, such as database connections or message queues.

The <resource-ref> tag may contain a <description>, <res-ref-name>, <res-type>, and <res-auth>. Here's a typical <resource-ref>:

<resource-ref>   <description>Primary database</description>   <res-ref-name>jdbc/primaryDB</res-ref-name>   <res-type>javax.sql.DataSource</res-type>   <res-auth>CONTAINER</res-auth> </resource-ref>

The <description> again supports the deployer and is optional but recommended. The <res-ref-name> dictates the JNDI lookup name. It's recommended but not required to place the resource factories under a subcontext that describes the resource type:

  • jdbc/ for a JDBC javax.sql.DataSource factory

  • jms/ for a JMS javax.jms.QueueConnectionFactory or javax.jms.TopicConnectionFactory

  • mail/ for a JavaMail javax.mail.Session factory

  • url/ for a java.net.URL factory

The <res-type> element specifies the FQCN of the resource factory (not the created resource). The factory types in the preceding list are the standard types. A server has the option to support additional types; user factories cannot be used. The upcoming J2EE 1.3 specification proposes a "connector" mechanism to extend this model for user-defined factories.

The <res-auth> tells the server who is responsible for authentication. It can have two values: CONTAINER or SERVLET. If CONTAINER is specified, the servlet container (the J2EE server) handles authentication before binding the factory to JNDI, using credentials provided by the deployer. If SERVLET is specified, the servlet must handle authentication duties programmatically. To demonstrate:

InitialContext initCtx = new InitialContext(); DataSource source =   (DataSource) initCtx.lookup("java:comp/env/jdbc/primaryDB"); // If "CONTAINER" Connection con1 = source.getConnection(); // If "SERVLET" Connection con2 = source.getConnection("user", "password");

These tags too have similar counterparts in the EJB deployment descriptor. The only difference is that in EJB the two possible values for <res-auth> are Container and Application (note the inexplicable case difference).

12.2.5 Servlet Distribution in a J2EE Environment

The final difference between servlets in a standalone environment and servlets in a J2EE environment involves a subtle change to the rules for session distribution. While a standard web server is required to support only java.io.Serializable objects in the session for a distributable application, a J2EE-compliant server that supports a distributed servlet container must also support several additional types of objects:

  • Any javax.ejb.EJBObject

  • Any javax.ejb.EJBHome

  • Any javax.transaction.UserTransaction

  • The javax.naming.Context for java:comp/env

All these are interfaces that do not implement Serializable. For transferring the objects the container may use its own custom mechanism, perhaps based on serialization or perhaps not. Additional class types may be supported at the server's discretion, but these are the only guaranteed types.


Last updated on 3/20/2003
Java Servlet Programming, 2nd Edition, © 2001 O'Reilly

< BACKCONTINUE >


Java servlet programming
Java Servlet Programming (Java Series)
ISBN: 0596000405
EAN: 2147483647
Year: 2000
Pages: 223

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net