Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Java 2 Enterprise Edition Case Study CPSC550 Graduate Student Seminar Spring 2004 Jeffrey A. Brown March 15, 2004 History Sun Microsystems announced plans for the unveiling of its Java 2 Platform, Enterprise Edition (J2EE) in March 1999 with the details of the new platform to follow shortly. J2EE is built on the Java 2 Platform, Standard Edition (J2SE), and takes advantage of many of its built-in class libraries. The J2EE platform uses the concept of the J2EE container, which exists to service components instantiated within it. This allows the J2EE programmer to focus more on the business logic of the application and less on the underlying “plumbing”. The precursor of the J2EE container is the transaction processor. The transaction processor was created to solve the problem of handling many concurrent users in an efficient manner. It guarantees transactional integrity and manages the execution of programs and the sharing of resources. A transaction is when several statements are executed as a logical unit; either all of the statements execute successfully or none of them are executed. The primitives that are used to control a transaction are BEGIN, COMMIT, and ROLLBACK. In addition, the transaction manager can maintain a pool of running program instances with the size of the pool based on the current user load. This allows a system to support many more concurrent users than is possible if providing duplicate resources for each user. The J2EE platform is designed in a modular way and takes advantage of “best practices” devised over the course of the history of interactive computing. The interactive computing paradigm started with a mainframe computer containing all of the programs and related data and a vast array of dumb terminals. With the advent of the PC, the client machine could process both presentation and business logic, relieving some of the work of the server. This model came to be referred to as the client/server or two-tier model. The client would provide a request to the server, which would process the request and return a result back to the client. Unfortunately, this model required the redistribution of client code to each client machine when any of the business logic or presentation logic changed. Finally, the business logic was separated out into its own tier resulting in the three-tier model. The components of the J2EE platform reside in one of these three tiers. JavaServer Pages (JSP) and Servlets are presentation tier components and live in the web tier. Enterprise JavaBeans (EJB) are business logic components and live in the middle (or business) tier. The persistent data for the applications live in the enterprise integration (or data) tier and are often stored in relational databases (RDBMS) or legacy systems. Goal The development of enterprise applications is hard work and unfortunately, as a result, is easy to get wrong. There are many underlying services, sometimes referred to as “plumbing” or infrastructure that need to be considered including the following: 1. Security. 2. Transactional processing. 3. Data persistence. 4. Concurrency of users. 5. Multiple client types. 6. Interoperability with legacy systems. The goal of J2EE is to simplify the development of enterprise applications by taking advantage of the benefits of component technology. A component is a “managed” object. It lives within a container that provides its context and the underlying services that it needs to operate properly. In essence, we don’t need to “reinvent the wheel” for many of the underlying services that we need when creating an enterprise application. Therefore, we can build a more robust, scalable system faster and cheaper. This is a good thing! Definitions JavaServer Pages (JSP) Provides the ability to “put snippets of Java code directly into a text-based document. A JSP page is a text-based document that contains two types of text: static template data, which can be expressed in any text-based format such as HTML, WML, and XML, and JSP elements, which determine how the page constructs dynamic content.” Servlets Provides the ability to “define HTTP-specific servlet classes. A servlet class extends the capabilities of servers that host applications accessed by way of a request-response programming model.” Java Messaging Service (JMS) “A messaging standard that allows J2EE application components to create, send, receive, and read messages. It enables distributed communication that is loosely coupled, reliable, and asynchronous.” Enterprise JavaBeans (EJB) A component that is used to implement the business logic of an enterprise application. They execute within a “container” which provides numerous services that simplify their development. Java Naming and Directory Interface (JNDI) “Provides naming and directory functionality. It provides applications with methods for performing standard directory operations, such as associating attributes with objects and searching for objects using their attributes”. Remote Method Invocation (RMI) Provides the ability for “an object running in one Java Virtual Machine (JVM) to invoke methods on an object running in another JVM. RMI provides for remote communication between programs written in the Java programming language”. Java API for XML – Remote Procedure Call (JAX-RPC) “Uses the SOAP standard and HTTP so client programs can make XML-based remote procedure calls (RPCs) over the Internet. JAX-RPC also supports WSDL so you can import and export WSDL documents”. SOAP with Attachments API for Java (SAAJ) Provides “a low-level API upon which JAX-RPC depends. It enables the production and consumption of messages that conform to the SOAP 1.1 specification and SOAP with Attachments note”. Java API for XML - Registries (JAXR) Provides ability to “access business and general-purpose registries over the Web. JAXR supports the ebXML Registry/Repository standards and the emerging UDDI specifications. By using JAXR, developers can learn a single API and get access to both of these important registry technologies”. Java Management Extension (JMX) Provides the tools “for building distributed, Web-based, modular and dynamic solutions for managing and monitoring devices, applications, and service-driven networks”. Common Object Request Broker Architecture (CORBA) An open, vendor-independent architecture and infrastructure created by the Object Management Group (OMG) that allows a CORBA-based program from any vendor, on almost any computer, operating system, programming language, and network, can interoperate with another CORBA-based program from the same or another vendor, on almost any other computer, operating system, programming language, and network. Features There are a number of features that are supported in the J2EE platform including the following: 1. Distributed processing 2. Component life-cycle management 3. Transaction processing 4. Pooling of numerous resource types 5. Security management 6. Data persistence 7. Interoperability with legacy systems Although the J2EE platform can be used to create distributed applications. This is not always a good idea. This is further explored in the “Significant Points” section below. Component life-cycle management includes the instantiation, initialization, processing, and destruction of the component. In some cases, when pooling EJB components, which include session and entity beans, this list is augmented by passivation and activation as well. Passivation is the process of serializing a component so that it can be removed from the pool. Activation is the reverse process. The component is deserialized from storage and brought back into the pool for subsequent processing. Finally, when dealing with entity beans, store and load are included. Before each transaction, the J2EE container will call the appropriate entity bean(s) to load its current state from the persistent store. After the transaction has completed, the J2EE container will call the appropriate entity bean(s) to write out their current state to the persistent store. A transaction is when several statements are executed as a logical unit; either all of the statements execute successfully or none of them are executed. The primitives that are used to control a transaction are BEGIN, COMMIT, and ROLLBACK. The J2EE container can be configured using an external file, known as the deployment descriptor, so that it knows what methods are to be executed in a transaction. When a client invokes one of these designated methods, the J2EE container intercepts that call and makes sure that the appropriate transactional constraints are enforced. This eliminates the need to place transactional demarcation in the methods, which helps keep the method focused on the business logic at hand. In addition to using the deployment descriptor to configure the transactional aspects of the J2EE container for a particular application, the deployer can also use it to configure the necessary security constraints of the application. This includes setting up application users, groups, and roles and then designating which user/role combination(s) can execute which methods. Once again, this allows the J2EE developer to keep non-business-related concerns out of the component’s logic. Structure The overall architectural structure of the J2EE platform is illustrated in the following diagram: Notice how the J2EE components are built on top of the Java 2 Standard Edition (J2SE). Version 1.4 of the J2EE platform introduces both web services (i.e. JAX-RPC, SAAJ, and JAXR) and component management (i.e. JMX). The overall J2EE platform is composed of two parts: the web container and the EJB container. As a whole, these two parts are referred to as the J2EE container. How To Use This section of the case study introduces a simple example used to show how to create EJB session beans, entity beans, and a remote client that accesses them. The example illustrates how EJB technology can be used to implement the business logic necessary to make a reservation on a cruise line. Cabin Entity Bean Component We’ll start with the EJB entity bean component, which is made up of a remote interface, a home interface, a bean implementation class, and a primary key class. The remote interface is named Cabin and it extends javax.ejb.EJBObject. The code is given below: package com.titan.cabin; import java.rmi.RemoteException; public interface Cabin extends javax.ejb.EJBObject { public String getName() throws RemoteException; public void setName(String str) throws RemoteException; public int getDeckLevel() throws RemoteException; public void setDeckLevel(int level) throws RemoteException; public int getShip() throws RemoteException; public void setShip(int sp) throws RemoteException; public int getBedCount() throws RemoteException; public void setBedCount(int bc) throws RemoteException; } This interface defines the business method API for the entity bean component. In general, an entity bean’s business methods consist of simple getters and setters. We need to remember that the purpose of the entity bean component is to provide an object-oriented view of persistent data. The home interface is named CabinHome and it extends javax.ejb.EJBHome. The code is given below: package com.titan.cabin; import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.FinderException; public interface CabinHome extends javax.ejb.EJBHome { public Cabin create(int id) throws CreateException, RemoteException; public Cabin findByPrimaryKey(CabinPK pk) throws FinderException, RemoteException; } The methods in the home interface are mandated by the javax.ejb.EJBHome interface and must be included. If desired, the J2EE programmer can add additional finder methods. The bean implementation class is named CabinBean and it extends javax.ejb.EntityBean. The code is given below: package com.titan.cabin; import javax.ejb.EntityContext; public class CabinBean implements javax.ejb.EntityBean { public public public public public int id; String name; int deckLevel; int ship; int bedCount; public CabinPK ejbCreate(int id){ this.id = id; return null; } public void ejbPostCreate(int id){ // Do nothing. Required. } public String getName(){ return name; } public void setName(String str){ name = str; } public int getShip(){ return ship; } public void setShip(int sp) { ship = sp; } public int getBedCount(){ return bedCount; } public void setBedCount(int bc){ bedCount = bc; } public int getDeckLevel(){ return deckLevel; } public void setDeckLevel(int level ){ deckLevel = level; } public void setEntityContext(EntityContext ctx){ // Not implemented. } public void unsetEntityContext(){ // Not implemented. } public void ejbActivate(){ // Not implemented. } public void ejbPassivate(){ // Not implemented. } public void ejbLoad(){ // Not implemented. } public void ejbStore(){ // Not implemented. } public void ejbRemove(){ // Not implemented. } } The bean implementation class provides the actual business logic implementation. In addition, there are other methods included above, setEntityContext(), unsetEntityContext(), ejbActivate(), ejbPassivate(), ejbLoad(), and ejbStore() which are mandated by the javax.ejb.EntityBean interface and must be included. The method setEntityContext() is called by the J2EE container to provide the bean with its context information. If the J2EE container needs to make space in the pool, it calls ejbPassivate() to allow the bean to perform any logic necessary before it is serialized to secondary storage. When it’s time to bring the bean back into the pool for further processing, the J2EE container calls the ejbActivate() method. The ejbLoad() and ejbStore() method pair is used to allow the bean to synchronize its current state with the underlying persistent store. The primary key class is named CabinPK and it extends java.io.Serializable. The code is given below: package com.titan.cabin; public class CabinPK implements java.io.Serializable { public int id; public int hashCode( ){ return id; } public boolean equals(Object obj){ if(obj instanceof CabinPK) return (id == ((CabinPK)obj).id); return false; } public String toString(){ return String.valueOf(id); } } The J2EE container uses the primary key class to guarantee uniqueness among the EJB entity beans located in the underlying persistence store. TravelAgent Session Bean Component Next we’ll look at the EJB session bean component, which is made up of a remote interface, a home interface, a bean implementation class. Since session beans don’t represent persistent data, a primary class key in not needed. The remote interface is named TravelAgent and it extends javax.ejb.EJBObject. The code is given below: package com.titan.travelagent; import java.rmi.RemoteException; import javax.ejb.FinderException; public interface TravelAgent extends javax.ejb.EJBObject { // String elements follow the format "id, name, deck level" public String [] listCabins(int shipID, int bedCount) throws RemoteException; } In essence, we can think of the session bean as the real business logic component. Each of its methods relate to a use case as defined in the requirements of the associated application. In our case with this example, the use case deals with the requirement of the system to allow a client to get a list of cabins in the specified ship having the specified bed count. The home interface is named TravelAgentHome and it extends javax.ejb.EJBHome. The code is given below: package com.titan.travelagent; import java.rmi.RemoteException; import javax.ejb.CreateException; public interface TravelAgentHome extends javax.ejb.EJBHome { public TravelAgent create() throws RemoteException, CreateException; } The methods defined in the home interface are mandated by the javax.ejb.EJBHome interface and must be included. The bean implementation class is named TravelAgentBean and it extends javax.ejb.SessionBean. The code is given below: package com.titan.travelagent; import import import import import import import import import com.titan.cabin.Cabin; com.titan.cabin.CabinHome; com.titan.cabin.CabinPK; java.rmi.RemoteException; javax.naming.InitialContext; javax.naming.Context; java.util.Properties; java.util.Vector; javax.ejb.EJBException; public class TravelAgentBean implements javax.ejb.SessionBean { public void ejbCreate() { // Do nothing. } public String [] listCabins(int shipID, int bedCount) throws EJBException{ try { javax.naming.Context jndiContext = new InitialContext(); Object obj = jndiContext.lookup("ejb/CabinHome"); CabinHome home = (CabinHome) javax.rmi.PortableRemoteObject.narrow(obj, CabinHome.class); Vector vect = new Vector(); CabinPK pk = new CabinPK(); Cabin cabin; for(int i = 1; ; i++){ pk.id = i; try { cabin = home.findByPrimaryKey(pk); } catch(javax.ejb.FinderException fe){ break; } // Check for bed count and ship ID match. if (cabin.getShip() == shipID && cabin.getBedCount() == bedCount){ String details = i+","+cabin.getName()+","+cabin.getDeckLevel(); vect.addElement(details); } } String [] list = new String[vect.size()]; vect.copyInto(list); return list; } catch(javax.naming.NamingException ne){ throw new EJBException(ne); } catch(java.rmi.RemoteException re){ throw new EJBException(re); } } private javax.naming.Context getInitialContext() throws javax.naming.NamingException{ Properties p = new Properties(); // ... Specify the JNDI properties specific to the vendor. return new javax.naming.InitialContext(p); } public public public public void void void void ejbRemove(){} ejbActivate(){} ejbPassivate(){} setSessionContext(javax.ejb.SessionContext cntx){} } The bean implementation class provides the actual logic that implements the session bean’s business logic. The first step is to lookup the home interface of the appropriate entity bean. In this case, it is referred to as “ejb/CabinHome”. In order to do this, the class uses the Java Naming and Directory Interface (JNDI), which provides a common abstraction layer for retrieving components. Once we have a handle to the home interface, we can iterate through each of the Cabin entity bean components and determine which ones meet the specified criteria. When one is found, we call two of its getter methods, getName() and getDeckLevel(), in order to create a listing of cabins that we can return to the client. Remote Client Finally we’ll look at the remote client itself. The code is given below: package com.titan.travelagent; import import import import import import import import import com.titan.cabin.CabinHome; com.titan.cabin.Cabin; com.titan.cabin.CabinPK; javax.naming.InitialContext; javax.naming.Context; javax.naming.NamingException; javax.ejb.CreateException; java.rmi.RemoteException; java.util.Properties; public class Client { public static int SHIP_ID = 1; public static int BED_COUNT = 3; public static void main(String [] args){ try { Context jndiContext = getInitialContext(); Object obj = jndiContext.lookup("ejb/TravelAgentHome"); TravelAgentHome home = (TravelAgentHome) javax.rmi.PortableRemoteObject.narrow(obj, TravelAgentHome.class); TravelAgent reserve = home.create(); // Get a list of all cabins on ship 1 with a // bed count of 3. String list [] = reserve.listCabins(SHIP_ID,BED_COUNT); for(int i = 0; i < list.length; i++){ System.out.println(list[i]); } } catch(java.rmi.RemoteException re){ re.printStackTrace(); } catch(Throwable t){t.printStackTrace();} } static public Context getInitialContext() throws Exception { Properties p = new Properties(); // ... Specify JNDI properties specific to the vendor. return new InitialContext(); } } The remote client also uses JNDI. This time to lookup the home interface of the session bean named “ejb/TravelAgentHome”. It then uses the create() method to make a new TravelAgent session bean component. The J2EE container provides the appropriate stub object, which hides all of the distributed “plumbing” and allows the client to treat the remote bean as a local object. At this point, the client simply invokes the listCabins() method and then iterates through the returned list of cabin details printing it to the console for inspection. Applications There are two common applications for the J2EE platform. The first is the web application as illustrated in the diagram below. The components of the web application physically reside within the J2EE web container that is one part of the overall J2EE container. In general, this architecture consists of Servlet/JSP components, a business interface, and the implementation of the business interface using “plain old Java objects” (POJO). In order to maintain a separation of concerns, the Servlet components are used to provide the navigational logic while the JSP components provide the presentational logic (i.e. the view). There shouldn’t be any business logic in either the Servlet or JSP components. All business logic should be in the POJO layer. The strengths of this approach include: 1. 2. 3. 4. Simplicity Speed Easy to test Scales well The weaknesses of this approach include: 1. Only supports a web interface 2. Can’t use EJB transaction support 3. No built-in support for concurrent programming The second is the distributed application as illustrated in the diagram below. The components of the distributed application physically reside within both the J2EE web container and the EJB container. In general, this architecture consists of Servlet/JSP components, a business interface, and the implementation of the business interface using EJB components. The design of the Servlet and JSP components is the same as above. The major difference in this architectural approach is in the implementation of the business interface, which allows access to the business logic through either the web components or through remote components using Remote Method Invocation (RMI). When using RMI, the accessing component can either be implemented using Java or Common Object Request Broker Architecture (CORBA), providing numerous options to the J2EE developer. The introduction of the session bean component provides a distributive mechanism for accessing the business logic in a container-provided transactional manner. The web application approach above doesn’t get to take advantage of transactional services provided by the container. In this case, the J2EE developer is responsible for managing the transactions. In fact, this highlights one of the benefits of using EJB technology; the J2EE developer can rely on the container to manage transactional constraints without introducing it into the business logic itself. An optional component of this approach is the introduction of the entity bean component. Unfortunately, this may end up be more trouble than its worth. The strengths of this approach include: 1. Supports all J2EE client types 2. Provides a shared middle tier 3. Permits distribution of application components across different physical servers The weaknesses of this approach include: 1. Complex 2. Performance overhead 3. Hard to test and debug Significant Points J2EE simplifies enterprise development but it's still much harder than developing with “plain old Java objects” (POJO). Since JSPs, Servlets, and EJBs are all components, it is necessary to maintain not only the associated logic but the deployment descriptors as well. Fortunately, tools like XDoclet and EJBGen help lessen this burden. In addition, components are “managed” objects and therefore must reside and execute within a container. This makes the job of both testing and debugging much harder since the services supplied by the container must be factored in to the testing framework. Sometimes, in simple cases, these services can be stubbed out but this isn’t always possible. In these more difficult cases, the testing framework must support the ability to test within the container itself. The biggest question that a J2EE developer must face is whether to take a distributed or non-distributed approach for the design and implementation of the enterprise application. Although the J2EE platform can be used to create distributed applications, this isn’t always the best approach to take. We can develop an extremely scalable application by using the features of the web container alone. EJBs are not a requirement for developing scalable systems. When taking the non-distributed approach it is important to use EJB local interfaces. Unfortunately, the J2EE developer needs to make a conscience decision on whether to use an EJB local interface and/or an EJB remote interface. The original EJB specification only provided for EJB remote interfaces and therefore whenever an EJB component was used, even when residing within the same J2EE container, RMI was required for inter-component communication. The current version of the J2EE specification allows for local interfaces as well as remote interfaces, which then treat inter-component communication like a local in-process method call. This is obviously a real boon in terms of minimizing performance overhead. However, it would be even better if the EJB container could determine whether to use local or remote interfaces based on context! Another mantra of J2EE application development is to design for scalability from start to finish. It is important to keep state requirements for the application small to non-existent since stateless components are much more scalable! Sometimes this is impossible since HTTP is a stateless protocol and applications often require state to be maintained. In general, the rule of thumb is to keep state requirements as small as possible. Summary It is hard to create enterprise applications because of their complexity. J2EE helps simplify the development of enterprise applications. The J2EE platform consists of numerous components including JSP, Servlets, EJB, and JMS. JSP and Servlet components reside in the web tier. EJB components reside in the business tier. JMS is used as a messaging transport for communication between components. Finally, the J2EE platform provides a number of helpful underlying services including life-cycle management, transaction processing, resource pooling, security, and data persistence. References 1. Java 2 Platform Enterprise Edition Specification, v1.4 http://java.sun.com/j2ee/j2ee-1_4-fr-spec.pdf 2. The J2EE 1.4 Tutorial http://java.sun.com/j2ee/1.4/docs/tutorial/doc/index.html 3. Enterprise JavaBeans, 3rd Edition Richard Monson-Haefel O'Reilly & Associates ISBN 0596002262 4. Enterprise JavaBeans: Developing Component-Based Distributed Applications Thomas C. Valesky Addison-Wesley ISBN 0201604469 5. Expert One-on-One J2EE Design and Development Rod Johnson WROX Press ISBN 0764543857 6. Core J2EE Patterns: Best Practices and Design Strategies Deepak Alur, et. al. Prentice Hall ISBN 0130648841