|
|
J2EE servlets | jsps | ejbs | tools | j2ee patterns
Last updated: February 2005
Despite strong early efforts, Java did not catch on either
as as a means of giving an OS level of interactivity to the
browser or as a successor to C++ in developing
client (esp. Windows) applications. Since 1997 its primary
application has been on the server-side, especially in developing
the back-end systems that power web sites.
From the start Java offered strong networking support, with
libraries that enabled a developer to open sockets or download
web pages with very few lines of code. Around 1997 Sun developed
the servlet API as a way to connect
web links to server-side processing. The next year a refinement
called JSP became popular: JSP pages are
mixtures of HTML and Java which are compiled to servlets.
Third parties soon adopted servlets as a standard in their application servers,
but they also bundled in other services to do such things as facilitate
communication with databases, deal with high load, and ensure the integrity
of transactions. Furthermore some application servers provided a coding
framework to insulate the application developer from lower-level intricacies.
In response Sun quickly developed its own all-inclusive standard for the
enterprise: J2EE (Java 2 Enterprise Edition). The task-oriented servlets
and JSPs were embraced by the J2EE framework
but backed up by a new object-based system called EJB: EJB
objects are a way of implementing all the server-side support systems and
database communication that a developer could need. The JNDI standard was
also included in J2EE as a way for objects to find each other.
|
|
|
servlets When the Web was new, developers who wanted to connect hyperlinks to server-side processing used a primitive technology called CGI scripts. Shortly after Java was introduced, the Servlet Extension API was developed as a more efficient alternative. The idea is that a servlet engine runs constantly on the server machine and waits for requests to be passed on to it from the web server; then when it gets one it executes the appropriate piece of code, i.e. the servlet itself, which might do something like query a database for a catalog of products, format the information as HTML, and send this dynamically-produced document back to the user. To create a servlet, the developer writes a normal Java class which makes use of the Servlet API, and registers it with the servlet engine being used. The root class in the Servlet API is GenericServlet; this is subclassed by HttpServlet which deals specifically with the HTTP protocol and provides the methods doGet (for GET requests) and doPost (for PUT requests). When writing a servlet, you typically create a subclass of HttpServlet and fill in code for the callbacks doGet and/or doPost. Several implicit objects are provided for use by your code, the most important ones being request, for doing things like accessing arguments sent along with a requested URL, and response, for writing out the actual HTML document. To illustrate here is a tiny servlet which just creates a web page showing the query string padded on to a URL in a GET request:
public class ShowQueryStringServlet
extends HttpServlet
{
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<HTML><BODY><br> "
+ "The arguments sent were "
+ request.getQueryString()
+ " <br></BODY></HTML>");
}
}
One thing that is not immediately obvious about servlets is that all requests to a servlet are processed by a single servlet instance. Simultaneous requests are handled by different threads started up by the single instance. This means extreme caution must be exercised with instance variables as well as with any other resources which are shared between all requests. One solution is to have the the servlet implement SingleThreadModel, which causes a separate instance to be created for each request, but this is generally not recommended as it hits performance and scalability. The servlet framework has grown more mature and standardized over the years. Modern implementations typically have servlets registered in a web.xml file, which allows you to set initializing arguments for each servlet and create filters on them. Servlets can be chained using either filters or the RequestDispatcher.forward() call.
|
|
|
jsps As discussed above, a servlet is a Java program which (usually) outputs a HTML page. What if, at some late stage, a copywriter or graphics designer wishes to make some simple change to the page which has nothing to do with the dynamic functionality? It's necessary to ask the programmer to go into the Java code, implement the modification, and retest the code using the servlet engine. JSP technology gives us a more flexible model. A JSP page is like a HTML page except it has a .jsp filename extension, a few extra lines of code at the top of the page, and some embedded snippets of Java wherever it needs to be dynamic. Like this line:
<br>The arguments sent were <%= request.getQueryString() %><br> At a later stage (either when the servlet engine is restarted or when the JSP page is first requested) the JSP page is automatically compiled into a servlet. The above JSP line would be translated into something like this Java:
out.println("<br>The arguments sent were\n"
+ request.getQueryString()
+ "<br>");
The developer would not even need to see this code. It is created behind the scenes. We now have a model where non-programmers are able to make changes to the HTML (i.e. non-dynamic) portions of the JSP page. However, this does not always work in practice. One thing that tends to happen is that too much Java code gets put in the JSP page, either when it is first created or with successive feature additions. The division between presentation and functionality becomes compromised, and the JSP pages become confusing. A common solution to this and other problems is to use the MVC (Model-View-Controller) framework, an architectural pattern borrowed from GUI design. With MVC, JSPs are reserved strictly for presentation (the View), servlets contain action logic to process requests (Controller), and JavaBeans or EJBs represent the Model. In this kind of system all servlet requests are typically channelled through a "Front Controller" servlet which determines what servlet(s) and/or JSP(s) to send on the request to. The controller servlet also serves as a useful central point for your web application, and can do things which would be common to all servlets such as logging and authorizing the user. Rather than write all the extra MVC logic, some developers prefer to go with a prepackaged implementation called Struts. This includes a controller servlet called ActionServlet which needs to be declared in the web.xml file for your application. In place of servlets, you now create Java classes which extend Struts's Action class and are called by ActionServlet according to logic in a Struts configuration file which you modify. Another step to separate off presentation logic, and one which is embraced by the latest JSP specifications, is to use tags instead of Java code within your JSP page wherever possible. Tags look a bit like HTML but can represent processing logic, e.g. <iterate>. In the JSP-to-servlet compilation process, the tag is simply converted to Java code using a Java class definition of the tag. Tags come included with servlet engines, packages like Struts, from Sun (the JSTL), and can also be created by the application developer. |
|
|
ejbs An Enterprise JavaBean is a special type of server-side component operating within an environment (technically called an EJB container). Typically a number of EJBs cooperate to perform the middle-layer business logic for a serious application. Apart from being a component technology, EJBs have little to do with JavaBeans, a technology Sun introduced earlier for the client side. Communication between EJBs is based on two key networking APIs which Sun had earlier introduced: RMI (Remote Method Invocation) for interprocess and over-the-network calls between objects, and JNDI (Java Naming and Directory Interface), an interface to directory services, which is used to locate EJBs. The EJB container is provided by a server such as WebLogic, WebSphere, JBoss, or Sun's own ONE Application Server. Such a server, implementing the EJB specification, is the basic tool a developer must have to deploy and test the EJBs he creates. The EJB 1.0 specification established two main types of EJB: entity beans and session beans. Entity beans model concepts that be expressed as nouns, and have persistent state which generally needs to be stored in a database: e.g. CustomerEJB or InventoryItemEJB. Session beans are process-oriented and represent business tasks, e.g. AddSalesTaxEJB. Session beans are further subdivided as being either stateless or stateful: stateless session beans contain methods which contain only local data like static methods; stateful session beans maintain a conversational state with the client, meaning that data particular to the client's session can be saved in memory across method calls (while the client has not released the EJB). EJB 2.0 introduced a third type of EJB called message-driven beans: MDBs are stateless task-oriented beans like session beans but do not respond to direct (RMI) method calls; instead they wait for messages sent asynchronously. These messages are sent using the Java Message Service (JMS), another key API within the J2EE framework. In ordinary client-side Java, an entity or task can often be represented by a single class. But on the server-side, the distributed nature of components — the fact that they are in different processes and machines — means that considerably more complexity is required to ensure that they interact in a robust, transaction-safe way. Consequently each EJB consists not of a single class but of several classes and interfaces, some of which can be considered as hooks for communication with other EJBs and the container. The structure is illustrated below:
|
|
|
|
After the developer has written all the classes and interfaces for an EJB, it's necessary to get the container to recognize and run them. Different servers will have different tools and steps for doing this, but the general process is:
Under pressure from the development community, Sun has steadily improved the functionality of EJBs in successive versions of the specification. One improvement in EJB 2.0 was the introduction of MDBs, mentioned above; another was CMR (Container Managed Relationships). The developer can now specify one-to-one, one-to-many, and many-to-many relationships between EJBs and navigate them using EJB-QL, a Query Language similar to SQL but object-based rather than table-based. Another 2.0 enhancement was local interfaces. The diagram above shows how EJBs are accessed by client code outside the container. But what if the client is another EJB? Most commonly it will be an EJB within the same container, i.e. within the same VM. In this case it is wasteful to use the same RMI semantics of serializing/deserializing method calls, and copying arguments rather than passing by reference. When EJBs were first released, it was necessary to do just that. Now, however, an EJB can access another EJB in the same container using its local home interface and local interface, which are analogs of the remote home interface and remote interface used by external client code. EJB 2.1 added support for web services, a nice way of exposing EJB functionality. EJB 3.0, being released as part of J2EE 1.5 in 2005, is intended to increase the usability of EJBs (often felt to be too heavy and complex) for developers by:
It is worth mentioning that while Sun has been trying to sort out EJB's teething problems many frustrated developers have turned to open-source lightweight frameworks, particularly for small to medium sized projects. For persistence (especially O/R mapping), a framework called Hibernate is popular. In the middle tier, Spring is widely used: it allows you to keep your business tier objects as POJOs (Plain Old Java Objects), while taking advantage of dependency injection. Much of the inspiration for EJB 3.0 has come from Hibernate and Spring. Lightweight frameworks are also popular at the presentation layer too of course: Struts has only recently begun to lose ground to Sun's JSF and JSTL, and other alternatives such as Tapestry and the Velocity template engine retain a lot of mind share. RESOURCES
|
|
|
tools An enterprise using J2EE may choose to use different server software for different types of components: for instance, static Web pages may be served from Apache, servlet and JSP calls may be dealt with by a servlet engine such as Tomcat, and EJB objects called by the servlets may be deployed on a JBoss server. These are free open-source servers. Some heavyweight commercial application servers such as WebLogic from BEA and WebSphere from IBM include all three functions, in addition to extra services. A key goal of the EJB specification is to define a container's responsibilities so tightly that an EJB that works in one server can work in another. To this end, application servers must pass a test suite from Sun before they can be certified as EJB compliant. The same applies to servlet engines implementing successive versions of the servlet specification. In practise there tends to be a lot of configuration work in moving J2EE components from one vendor's software to another even though the Java code stays the same. The build tool ant is often used to create compilation and deployment scripts. On the other hand, commercial application servers tend to have advanced proprietary GUI tools to do these things. The screenshots below illustrate the process of deploying a bean with WebLogic and running the server.
|
|
|
|
|
|
Download JBoss bundled with Tomcat
|
|
|
j2ee patterns The section Design Patterns showed how, in general OO programming, a set of idioms has become well known for addressing common problems. Similarly, within the J2EE framework, experience and understanding of good practices soon caused the emergence of J2EE patterns. In fact a flood of J2EE patterns have been suggested. One good reference for the core ones is the Java BluePrints Patterns Catalog from Sun. Examples of J2EE patterns have already been mentioned: the Front Controller pattern and the MVC pattern were described in the JSP section above. Note that the MVC pattern is of a different level of granularity than most patterns: MVC is an architectural pattern. J2EE patterns also differ according to whereabouts in the enterprise they are deployed: in the front-end such as Front Controller, in the middle such as Service Locator, or towards the back such as Data Access Object. The Service Locator pattern involves creating a module to simplify looking up enterprise resources. For instance, the code to look up an EJB using JNDI typically takes three or four lines (as opposed to using new for a normal Java object) and can get quite repetitious. A service locator can simplify this by caching home references. This also improves efficiency of course because it avoids redundant lookups. A service locator can cache other resources too such as database connections. The Data Object Access (DAO) pattern involves creating a layer of indirection between the enterprise's data source and the objects which access the data source. This should make it possible to change the data source (e.g. from Oracle to DB2) without having to rewrite business logic. It might be objected that entity beans already provide this layer of indirection, but entity beans have sometimes been found inefficient or not suitable for all purposes. A popular API used instead of or in tandem with entity beans is JDO (Java Data Objects). Unlike entity beans JDOs provide local-only access and are not transaction aware (transaction settings should be set by the callee, typically a session bean).
Java BluePrints Patterns
Catalog
New patterns suggested by members of TheServerSide.com (regularly updated).
|