Linux Application Development For The Enterprise (Charles River Media Programming)
| < Day Day Up > |
|
Before the J2EE technology entered the Web development arena, the traditional CGI (common gateway interface)-based development was the major player, which supported several technologies including programming and scripting languages such as C++, Perl, PHP, and so on. However, the Web application development has undergone a revolutionary change over the years with support from several organizations. Undoubtedly, the CGI technology has brought about a kind of revolution by providing dynamic content to the static HTML pages. Many Web sites built over the past several years have derived their dynamic content from the CGI-based Web applications. The Kylix 3 platform discussed in Chapter 6, Desktop Application Development, is capable of supporting CGI-based applications for any Web server that supports CGI technology, and also supporting the Apache Web application modules. The advent of technologies that offered robust (and RAD) frameworks such as the J2EE (and Microsoft .NET) has revolutionized the Web development process. While the servlets and Java Server Pages (JSP) contribute to the presentation layer of the Web applications, the JavaBeans and Enterprise JavaBeans provide backend support. Technologies such as RMI, JDBC, and JNDI provide miscellaneous supporting services. Alhough the CGI-based systems will continue to exist in small and medium industries for a considerable period, J2EE technology will certainly form the basis for many large organizations due to the underlying robust, reliable, and secure architecture, as can be noticed from the trend in the industry over the past few years.
Servlets and Java Server Pages
Servlets are independent server-side objects that can process an incoming HTTP request from Web clients and send an appropriate HTTP response in return. Technically, servlets are Java classes that extend the javax.servlet.http.HttpServlet abstract class. In order for them to provide the server-side functionality of a Web application, a servlet engine (or a servlet container) operating within the context of a Java Virtual Machine is required. The servlet engine is an additional layer over a traditional Web server. It processes an incoming HTTP request and converts it to an object that implements the javax.servlet.http.HttpServletRequest interface. It also creates an object implementing the javax.servlet.http.HttpServletResponse interface for the servlet to fill its response to the client. Then it creates an instance of the servlet and invokes the service() method on the servlet object providing the request and response objects created earlier. In brief, this is what happens when a Web-based client sends in a request to execute a servlet; however, there are other tasks performed by the servlet engine that manage and control the lifetime of the servlets. The servlet object also implements other methods that are designed to process each of the HTTP request types. These methods are known as doXXX() methods, where the XXX suffix in the method name represents the type of HTTP request. For example, the doGet() and doPut() methods are designed to service the GET and PUT HTTP request types, among other doXXX() methods. Because the HttpServlet is an abstract class, it cannot be instantiated; the doXXX() methods on this class are all protected. There is only one public service() method and another protected service() method. Classes that extend this base class need not implement the service() method, while they have to implement (or override) one or more of the doXXX() methods, depending on the type of HTTP requests that the servlet supports. The public service() method of the parent HttpServlet class will eventually invoke the appropriate doXXX() method through the protected service() method. Figure 8.1 displays (without details) a servlet serving a client’s request through the servlet engine.
We will now walk through the process of creating a simple servlet, the HelloServlet, using JBuilder8 IDE. Borland’s JBuilder8 is a very popular IDE for Java development, as we saw in Chapter 6 during Java-based desktop system development. JBuilder8 is capable of building J2EE applications for a variety of servlet engines and application servers, including Tomcat 3.0 and Tomcat 4.0 servlet engines from the open source Jakarta Apache initiative, Borland Enterprise Server, IBM WebSphere, BEA Web Logic server, and so on. Rapid development and testing of servlets and JSPs using JBuilder8 is very easy. The following steps will describe this process.
-
Create a new project and save it with a name of your choice in a directory of your choice. A servlet project is very similar to any other project.
-
Invoke the Project Properties dialog by selecting the Project ® Project Properties menu item to make sure that an appropriate servlet engine is identified to run the servlet. The displayed window is similar to Figure 8.2. In the dialog, go the last tab page named ‘Server’. The default server name Tomcat 4.0 is selected, which is fine for this example because we are going to test a servlet. The default options selected in this page are enough for the example.
Figure 8.2: Project Properties dialog. -
Now invoke the Object Gallery dialog by selecting the File ® New menu item and go to the Web items page, as shown in Figure 8.3. This page contains icons representing several items relevant to Web application development. Select the Servlet icon and click the OK button to display the Servlet Wizard as shown in Figure 8.4, which contains five pages to configure the servlet while creating; each of the successive pages is displayed successively after providing input in the previous page. To conserve space, only the first page of the wizard is displayed here.
Figure 8.3: JBuilder8 Object Gallery—Web items page. Figure 8.4: Servlet Wizard. -
The servlet is created with the name HelloServlet, and therefore the source class file is named as
HelloServlet.java, whose source code is displayed in Listing 8.1. Most of the code in this servlet is written by the IDE automatically. The doGet method is implemented, as that is chosen (by default) in the Servlet Wizard. Only parts of the out.println statements are modified to display an appropriate message in the example. -
Compile the program and create a run configuration, as explained in earlier chapters. When the program is run, an instance of the Tomcat servlet engine also is automatically run, and the servlet is executed. The output of the servlet is displayed in the same window as the source program. As this window shows, a number of tab pages are displayed with the appropriate tab name at the bottom of the editor pane. The tab pages in this pane dynamically change, depending on the type of file we are working with and also on the type of operation performed on the file. In this case, because the results of execution of a servlet are displayed in a browser window, the ‘Web View’ tab page in the editor pane acts like a browser window, and also displays a Refresh button on the top of this page. Every time we recompile the servlet, this Refresh button may be clicked to reload the newly compiled servlet. Figure 8.5 displays a typical JBuilder8 window with all these features, and a closer examination of this figure will help the readers to correlate the discussion with the figure.
Figure 8.5: JBuilder8 editor pane with servlet in execution.
Listing 8.1 is available on the accompanying CD-ROM.
Listing 8.1: HelloServlet.java
package helloservlet; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; /** * <p>Title: </p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2003</p> * <p>Company: </p> * @author not attributable * @version 1.0 */ public class HelloServlet extends HttpServlet { private static final String CONTENT_TYPE = "text/html; charset=UTF-8"; //Initialize global variables public void init() throws ServletException { } //Process the HTTP Get request public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head><title>HelloServlet</title></head>"); out.println("<body bgcolor=\"#ffffff\">"); out.println("<p>The servlet has received a GET. This is the reply.</H2></p>"); out.println("<p><H4>Hello, how are you? </H4></p>"); out.println("</body></html>"); } //Clean up resources public void destroy() { } }
Servlet’s Life Cycle
The servlet’s life cycle begins when the servlet engine receives the first request for the servlet. At this point, an instance of the servlet is created and its init() method is executed. The init() method may be implemented to perform one-time initialization tasks on the servlet; it is not mandatory to implement this method if there is no need. This method is overloaded and has two forms. The first form of the method does not take any input arguments, and the second form of the method takes an input argument of type javax.servlet.ServletConfig interface. The servlet engine calls whichever method is implemented. The second form of the init() method is provided for convenience; however, the ServletConfig object is always available within a servlet by executing the getServletConfig() method. The ServletConfig provides information about initialization parameters created by the servlet engine at the time of instantiating the servlet. These values are usually set by the application deployer as servlet attributes through the deployment descriptor file in XML format. One of these attributes is the name of the servlet. Although an enumeration of the servlet’s attributes can be obtained by executing the getInitParameterNames() method on the ServletConfig object, each of the attribute values can be retrieved by executing the getInitParamter() method and passing the attribute name obtained from the enumeration of attribute names. More details on the deployment descriptor file will be discussed in the section named Jakarta Struts later in this chapter.
There is another object—the servlet context object—that implements the javax.servlet.ServletContext interface, which is also created by the servlet engine when the servlet is instantiated. This object is available to the servlet by executing the getServletContext() method either on the servlet object or on the servlet config object and is used by developers to communicate with the servlet engine. There is one servlet context object per Web application per one instance of Java Virtual Machine. A Web application is a collection of all the servlets and Java Server Pages (discussed in the following section) and other resources archived in a single file known as a Web application archive (or WAR) file. Thus, developers use the servlet context object to save local object references to be made available to other servlets in the application. In other words, the objects created by one servlet in the application may be stored in the servlet context in the form of (user defined) attributes using the setAttribute() method on the servlet context object, which takes two arguments: a user-defined name attribute as the first argument and a Java object reference as the second argument. The servlets that will access the object should execute the getAttribute() method on the servlet context object, which takes one argument—the name of the attribute. The getAttributeNames() method retrieves an enumeration of all the attribute names defined at that point of time. The purpose of an attribute name is to act as a bridge between servlets, and therefore servlets accessing objects created by other servlets may have their own local names to these object references when retrieving through the getAttribute() method. Another important point to remember is that the return value of the getAttribute() method is of java.lang.Object type, and therefore should be cast to the appropriate object in the servlet that retrieves the attribute. The removeAttribute() method on the servlet context object may be used to remove an attribute reference from the servlet context. This method only removes the object reference; it does not necessarily make the object a target for garbage collection. However, if there are no other references to this object, the garbage collector may eventually destroy the object the next time the collector runs. The servlet context interface supports other methods, which may be explored by the readers as and when required. Thus, the servlet context is also known as the application context and provides one of the four scopes (or levels of visibility) for the objects created in the servlets. More details on the scope will be provided in a subsection of this topic.
After the servlet object is initialized, the servlet engine executes the service() method, as mentioned earlier in this section, which in turn executes the appropriate doXXX() method based on the incoming request type. Typically, a servlet is developed to serve one type of HTTP request; however, the architecture does not prevent developers from implementing a servlet to serve more than one request type, in which case more than one doXXX() method is implemented. Multiple requests on the same servlet are executed by the container in multiple threads, with one instance of the servlet. This is the default behavior of the servlet engine, and it is the developers’ responsibility to protect the servlet data shared among multiple threads. However, a servlet may be implemented to execute in a single thread for concurrent access by multiple clients by implementing the javax.servlet.SingleThreadModel interface. This is a tagged interface with no methods and is only used to indicate to the servlet engine that the concurrent client requests should be processed sequentially in single thread model. Thus, it is the responsibility of the servlet engine to determine the lifetime of the servlet based on the threading model and other criteria. Once the servlet engine determines that the servlet may be taken out of service, it executes the destroy() method, which may therefore be used to release any acquired resources or perform any other finalization tasks.
Scope of Variables
Scope of variables is a very important feature that every application developer should understand thoroughly. Without proper understanding of this concept, developers are prone to commit mistakes that could raise exceptions or sometimes make the system behave unexpectedly or become unstable. The scope of variables and objects created in servlets is somewhat different from other types of applications, particularly as servlets are executed within the context of a Web application, and Web applications are stateless by nature. Throughout the industry, the main issue related to Web application development is that every request from a client to the server is unique and independent of the preceding requests. This is, in essence, the meaning of a stateless protocol. The disconnection (or lack of connection) between subsequent requests from the same client poses two challenges. The first challenge is to somehow implement a scheme that connects the independent client requests together to give the picture (or to create an illusion) of an application without sacrificing on security. (This challenge is addressed in a later section.) The second challenge is that the servlets (or any server-side components) should be able to preserve their data elements across client requests, as the processing of the previous request may be incomplete. For example, in the context of a shopping cart application, the client may be browsing through the list of items displayed in the browser, and the list is spanning across several pages. These pages may be scrolled back and forth (very similar to a traditional client-server application) using a couple of buttons with names like Next and Previous. If the client is choosing items from different pages and adding them to the shopping cart, the scenario is quite different between a traditional client server application and a Web application. In a traditional client server application, the server instance typically creates an object of the shopping cart and does not destroy it until the client stops adding items to it and closes the session. However, in the Web application, the server instance typically creates the shopping cart object when the client adds the first item to the cart. Because every subsequent button click on the client’s browser (whether it is to add an item or to scroll to another page of displayed items) initiates a new HTTP request that is distinct from the previous request, the server should be programmed to handle the two challenges described earlier. Assuming that the server somehow maintains a session consisting of multiple requests from the same client, the second problem is that the server should preserve the shopping cart object from being destroyed (or targeted for the garbage collector when it goes out of scope). This is done by extending the object’s scope or lifetime until further HTTP requests from the client are processed. It is therefore necessary to understand the different levels of scope supported by servlets.
The servlet context object discussed earlier provides the highest level of scope to the objects. Objects whose references are saved as attributes in the servlet context are visible to all the servlets in the application, and therefore it is also known as application level scope. The next level of scope is known as session scope. Java servlets implement sessions to make connections between distinct HTTP requests from the same client. When the first request from a client is received, a session is automatically created. Typically, a session may be implemented by one of two techniques: cookies or URL rewriting. Cookies are small pieces of data sent to the client with the response object to the first request from the client when the session object is created, which is stored on the client’s computer if it permits cookies. The next subsequent request from the client attaches this cookie as part of the HTTP header, and it is accessed by the servlet engine that matches it with the session created earlier. This match establishes the link between one of the session objects maintained by the servlet engine and the servlet. Due to security related issues, the browsers provide a feature to the clients to disable cookies. If the clients disable the cookies, the servlet engine cannot send the cookie and therefore resorts to the second method. In this method, a piece of information identifying the session is appended to the end of the URL and sent with the response object. The subsequent requests will pass this information as part of the URL, and the servlet engine can retrieve this information to identify the appropriate session object for client. The beauty of the session concept in servlets is that the servlet engine automatically handles the method to be used to create and manage session objects, and the servlet programmers do not have to do anything in this respect. They simply access the session objects created by the servlet engine on their behalf. The sessionobject is an instance of the javax.servlet.http.HttpSession interface. The servlet programmers use session-level scope to store objects related to the same client (or same user computer) between requests. Similar to the servlet context object, the session object also supports the setAttribute(), getAttributeNames(), getAttribute(), and removeAttribute() methods, among others. The signatures of these methods are the same as they are in the servlet context object and therefore they should be used in the same way. However, the objects stored in the session context are only visible to other servlets that can access this session object from the servlet engine. Thus, the session object not only provides an application-level scope but also preserves uniqueness of data maintained for a particular session, whereas objects stored in the servlet context are visible to all the servlets in the application—during any request from any client—and therefore should not be used to store data related to a particular client session. The session has a timeout period and will expire if subsequent requests from the client are not received by the server within this time. Use of session objects may also be disabled by the servlets.
The next lower level of scope is provided by the HTTP request object, which is passed as an argument to most of the servlet methods. This is an instance of the javax.servlet.http.HttpServletRequest interface and supports all the methods to set, get, and remove attributes—discussed earlier—with the same method signatures, and therefore should be used in the same manner. The only difference is the scope in which the objects are accessible. The attributes set at the request level are accessible to all the other methods (or objects) that have access to the request object and during the lifetime of the request object. Normally, a request object is live until a response object is sent to the client. This means that attributes set at the request level have their scope governed by the lifetime of the request object itself.
As far as servlets are concerned, these are the only three levels of scope, whereas Java Server Pages introduces another level of scope, known as page level, which will be discussed in the following section.
The Request and Response Objects
In this subsection, we are going to discuss the HTTP request and HTTP response objects, their properties, and their lifetimes. The request received from a Web client is wrapped by the servlet engine into an instance of javax.servlet.http.HttpServletRequest, known as the request object, which provides direct access to all the request-related information to the servlet through the methods implemented in this object. The information includes HTTP headers, cookies, request URL, path info, the request method (such as GET and POST), and so on. The session associated with the current request is obtained by executing the getSession() method. This is an overloaded method with two methods, one of which takes a Boolean argument indicating whether to create a session if one does not exist. The return value of this method is an object of javax.servlet.http.HttpSession interface, which may be used to set and get attributes. The request object also directly supports methods to get and set attributes as discussed in the previous section. Similar to the request object, the servlet engine also creates a response object that is an instance of the javax.servlet.http.HttpSessionResponse to facilitate the servlet sending an appropriate response to the client. The response object has methods through which the servlet can add cookies, set values to response headers, and write direct HTML code embedded with dynamic content. In a way, the page is directly built into the response object’s PrintWriter object, which is obtained by executing the getWriter() method. This can be noticed in the previous example code. An important feature of the request and response objects is that, once the response is sent, the request object is no longer accessible.
An IDE such as JBuilder8 is capable of creating most of the skeleton code for the servlet and all the necessary files for deploying the Web application, thus improving developers’ productivity. Other development environments such as IBM’s Web Sphere Application Developer and Oracle JDeveloper also provide similar features. Without an IDE, developers are required to use an editor such as vi or Emacs and compile the programs with the Java compiler included in the JDK. The developers also need to create the jarand warfiles manually (using tools supplied with the JDK and J2EE SDK) and deploy them to the appropriate servlet engine (or container). It is also a practice to deploy the servlet classes to a separate directory within the base directory serviced by the Web server. The users can access the servlets from this directory by appending this directory name to the server name followed by the specific servlet class name (without the .class extension), as shown in the example URL below.
http://www.myserver.com/servlets/HelloServlet
In this example, the string www.myserver.com identifies the host running the Web server listening to the default port 80. When the Web server (including the servlet engine) is installed, the base directory is specified in the server configuration file, which has a unique form to every server. By changing this base directory in the configuration file, the server is configured to read pages from a different location on the system. The port at which the server should listen may also be changed in the configuration file, as is usually necessary. This is because one port is attached to only one server at a time, and frequently, people run multiple Web servers on the same host computer. If the server is configured to listen to a different port (say 8080), then the port should be suffixed to the server name with a : character separating the server name and the port, as shown in the following URL.
http://www.myserver.com:8080/servlets/HelloServlet
The string servlets with prefixed / character indicates the subdirectory name under the server base directory from which the servlet class files are accessed by the server. The last part of the URL is the path info string, which identifies the specific request to be performed. In this case, the path info identifies the name of the servlet class file that has been built in the example before. The directory name (or names of one or more subdirectories) along with the path info string is known as the requested resource because a Web application is a group of resources (such as static and dynamic pages, images, and multimedia files) or links to resources. If there is a query string for the request (as is the case with the GET type HTTP request), it follows the path info string with associated parameters and values.
While the current section provided a brief introduction to the servlets, the following section is going to discuss Java Server Pages, which is a natural extension to the servlets.
Overview of JSP
The advent of Java Server Pages (JSP) as an extension to the servlets architecture has brought a revolutionary change to Java server-side development. The salient features of JSP technology are listed as an immediate reference to the reader, and may also help in alleviating some of the myths.
-
The JSP pages are simply server-side scripts using the core Java language and can be intermixed with HTML code. JSP is different from JavaScript; while the former is based on Java language and is used for server-side scripting, the latter has no relation to Java and is used for client-side scripting. Server-side scripts are executed by the server to produce response in the form of HTML text and sent to the browser, whereas the client-side scripts are not executed by the server are sent to the browser along with the HTML text, and the browser executes the client-side scripts.
-
A JSP page is an extension of the servlet and is hosted within a servlet container that translates it to a servlet before it starts servicing the clients. Typically, almost all the servlet containers in use today are capable of hosting JSP pages, and therefore the terms servlet engine and JSP engine may be considered synonymous.
-
In case of servlets, the HTML text is embedded with the dynamic content and both the static and dynamic content is sent to the PrintWriter output stream object of the response object through println statements. On the other hand, the JSP pages provide a more flexible and convenient way of mixing dynamic content in HTML pages. For example, the current HTML pages may be converted to JSP pages by embedding the JSP code within the HTML text and simply changing the file extension from .html to .jsp.
-
While only precompiled servlets can be deployed to the servlet engine, JSP pages are not precompiled by the developer; rather, they are translated to servlets by the servlet engine before servicing the client requests.
-
Although a servlet is accessed by the client by specifying the servlet name as part of the URL (path info), a JSP page is accessed by replacing the servlet name in the URL with the JSP name, including the .jsp file extension. The JSP pages may be deployed in the same subdirectory as servlets or in another subdirectory within the Web application, as desired.
-
Because the JSP scripts are executed by the server, these scripts can embed code that accesses database objects and other objects, thus making the full Java language available for Web application development. JSP pages may also include other resources containing static and dynamic content.
-
While building JSP pages, developers are not limited to implementing a few methods as in the case of a servlet. Rather, the program elements such as Java objects and the HTML entities interact with each other to produce complex Web pages. For this reason, JSP pages are considered the best choice for the presentation layer of a Web application.
-
JSP supports any scripting language that is capable of using Java objects in the scripts. However, the discussion in this book is targeted toward using Java as the scripting language for JSP pages, which is also the default scripting language.
Life Cycle of a JSP Page
The life of a JSP page begins when the servlet engine receives an HTTP request, with the requested resource matching the specific JSP page. Once the servlet engine identifies a JSP page for a request, it translates the page to a servlet class file and compiles it automatically. It also compiles included JSP files and caches them all together. (More detail on included files is provided later in this section.) If the current JSP file was not modified since the last time it was compiled, the cached servlet (of the page) is executed for the request. Any syntax errors in JSP pages will only be caught when the page is requested, as the page is not translated and compiled until that time. It should be noted that the syntax errors caught during compilation might refer to the resulting servlet, and therefore may not directly point to the code in the JSP page. Even the runtime errors typically point to the code in the servlet. There are several parameters that are specified through special JSP directives within the page, that are helpful to control the page execution process. The servlet engine takes care of these parameters while executing the resulting servlet.
A JSP page implements automatically from the javax.servlet.jsp.HttpJspPage interface when processed by the JSP container (or servlet engine). This interface extends the generic javax.servlet.jsp.JspPage interface and provides support to the HTTP protocol. It supports three methods one jspInit() method, one jspDestroy() method, and one _jspService() method. The first two methods may be implemented by the developer within a JSP page as a global JSP declaration (discussed in the following subsection). If the developer does not implement these methods, the JSP container automatically provides their default implementation for the page. The _jspService() method is automatically implemented by the JSP container based on the content of the JSP page and should not be implemented by the JSP developer. The jspInit() method is executed by the JSP container before executing the rest of the page and therefore is the ideal place to initialize global objects and variables. Similarly, the jspDestroy() method is executed by the JSP container when the page is about to be destroyed. For example, if an Enterprise JavaBean is created in the jspInit() method, it may be requested to be removed in the jspDestroy() method. More details on how the container creates, manages, and removes EJBs will be discussed in a later section in this chapter. Also, when EJBs are deployed, a simple JSP engine is not sufficient as the EJBs will need to be deployed within an EJB container.
JSP Programming Elements
Constructing JSP pages does not require one to know JavaScript; however, it does require that developers be familiar with the HTML tags and building static Web pages. JSP pages usually contain two main types of entities: the HTML text and elements, and the JSP elements such as declarations, expressions, scriptlets, directives, custom tags, and predefined and user-defined objects.
The JSP expressions are simply Java expressions embedded between the <%=and %>tags, as shown in the samples provided here.
<%= Java expression %> <%= java.util.Calendar.getInstance().toString() %>
While the first line shows the general syntax of a JSP expression, the second line shows how the expression on the right side of the equality is evaluated and embedded as text at the point where it is coded. In this example, the current date and time stored in the Calendar object are displayed as a string. Typically, JSP expressions are used to set attributes to HTML controls or display results from simple expressions, retrieving properties from JavaBeans and so on. However, complex logic cannot be incorporated through JSP expressions, and one should use the scriptlets for that purpose.
JSP scriptlets enable more flexible coding of complex logic, as any valid Java statements may be coded within a scriptlet, which is embedded by the <%and %>opening and closing tags. Typically, a scriptlet looks similar to the code sample given below.
<% Java code %> <% String name = (String)request.getAttribute("UserName"); out.println("User Name =" + name); %>
The first line shows the general format of a scriptlet, followed by the example. The sample code used a predefined object out, which is an instance of the PrintWriter object contained within the response object. Any text streamed out to this object through its println() method is sent as HTML text to be displayed in the browser. In the servlet example program discussed in the previous section, we obtained this object by executing the getWriter() method on the response object.
Within the context of a JSP page, the out object represents this PrintWriter instance and is automatically available. The other objects available in the JSP page include the request and response objects that represent the HTTP request and response, respectively; the session object to represent the current session; the application object that represents the servlet context; the config object that represents the servlet config object; and the PageContext object that provides a single point of access to many of the page-level attributes. This is the additional level of scope provided in JSP pages, that is not available in servlets. Attributes saved within the page context are accessible throughout the page. These predefined objects are also known as predefined variables.
Global variables and objects can be defined within the JSP declaration tags, <%!and %>, as shown in the code snippet here.
<%! String userName; userName = userBean.getName(); %>
In this example, the userName is declared as a global variable, and its value is set by retrieving an appropriate property value of a Java object, userBean. This Java object may represent a simple JavaBean, an Enterprise JavaBean, or any Java object. Declarations of global variables and objects make them available to the rest of the JSP page, and any Java code within that page can access them. The JSP container places these declarations outside of other functions in the resulting servlet code.
JSP pages can include comments to aid proper maintenance, using the <%--and --%>comment tags. Any text placed in between these tags is deemed by the JSP engine as comments and will not be compiled. Please note the two hyphens after the % sign in the first tag and before the % sign in the second tag.
A Simple JSP Application
Let us go through the process of creating a simple JSP application using JBuilder8, as described in the following steps: create a new project in JBuilder8 and save it with a name of your choice in a directory of your choice.
-
Add a new JSP source file using the Object Gallery Wizard shown in Figure 8.3. In this wizard, double-click the Java Server Page icon to start the JSP Wizard. This wizard runs in four pages and accepts all the necessary input from the developer. At this time, do not select the option to create a JavaBean, and do not select any of the listed frameworks. In the following examples, we will discuss how to use JavaBeans within a JSP page, and how to use the Jakarta Strutsframework in building Web applications.
-
The newly created source file is named as
SimpleJSP.jsp and contains the basic skeleton code necessary for a simple JSP, as per the information provided in the wizard. This JSP is modified slightly to contain a text field, where we enter some text, such as a name. There are two HTML buttons created automatically by the wizard—one is to submit the information to the Web server and the other is to reset the text field. The page’s title is changed to display that it is a user registration page. -
Create a second JSP page using the JSP Wizard, that should be displayed when the user clicks the Submitbutton on the first page. This source file is named
HelloUser.jsp. The default code is modified to contain only one button, the OK button. In the first page’s form tag, the wizard automatically adds the method="post" attribute. For the same form tag, add the action="HelloUser.jsp" attribute to indicate that when the form is posted, the action that the server should take is to display the second page. Similarly for the second page’s form tag, add the action="SimpleJSP.jsp" attribute, indicating that when the user clicks the OK button, the first page should be displayed. -
When the user enters a string in the text field in the first page, it is considered a name and a hello message is displayed in the second page. This is actually a very simple application. Still, it helps new developers to understand how to create JSP pages, how they are linked together, and so on.
Figure 8.6 and Figure 8.7 display the two pages in action within the JBuilder8 IDE, whereas Listing 8.2 and Listing 8.3 display the source code for these JSPs. These source files are saved within the .war file created by the IDE for the application. Listings 8.2, 8.3, and 8.4 are available on the accompanying CD-ROM.
Listing 8.2: SimpleJSP.jsp
<%@ page contentType="text/html; charset=UTF-8" %> <%@ page errorPage="SimpleJSP_error.jsp" %> <html> <head> <title> User Registration </title> </head> <body bgcolor="#ffffc0"> User Registration </h1> <form method="post" action="HelloUser.jsp"> <br>Enter user name :</h3> <input name="user"><br> <br><br> <input type="submit" name="Submit" value="Submit"> <input type="reset" value="Reset"> </form> </body> </html>
Listing 8.3: HelloUser.jsp
<%@ page contentType="text/html; charset=UTF-8" %> <html> <head> <title> HelloUser </title> </head> <body bgcolor="#ffffc0"> <% java.lang.String usrName = request.getParameter("user"); out.println("Hello "+ usrName); %> </h1> <% out.println("It's pleasure to have you in our system"); %> </h3> <form method="post" action="SimpleJSP.jsp"> <br><br> <input type="submit" name="OK" value="OK"> </form> </body> </html>
As mentioned in the previous section, the jspInit() method can be implemented by the developers to initialize values for objects and variables. In the current example, the
Listing 8.4: SimpleJSP_modified.jsp
<%@ page contentType="text/html; charset=UTF-8" %> <%@ page errorPage="SimpleJSP_error.jsp" %> <html> <head> <title> User Registration </title> </head> <body bgcolor="#ffffc0"> User Registration </h1> <%-- JSP declarations --%> <%! private String userName; public void jspInit() { userName = "Satya Sai Kolachina"; } %> <form method="post" action="HelloUser.jsp"> <br> Enter user name :</h3> <%-- User of JSP expression --%> <input name="user" value="<%=userName%>"> <br><br> <input type="submit" name="Submit" value="Submit"> <input type="reset" value="Reset"> </form> </body> </html>
JSP Directives
JSP page directives provide a way for the developers to control various execution parameters, which will be discussed in this subsection. The directives take one of the forms shown below.
<%@ directive attributes %> <jsp:directive.directiveType attributes />
The first line shows the standard JSP directive form, and the second line shows the XML style. A directive needs to be specified only through one form. There are three different types of directives supported by JSP: the page, include, and taglib directives. Through several page directives, the overall structure of the resulting servlet can be controlled; the include directive is used to include content from external sources, and the taglib directive is used to custom tag libraries within the page. Each of these directives supports one or more attributes. An attribute identifies a qualifying JSP parameter that is controlled through the directive. A value is specified to the attribute in the following form.
attribute="value"
More than one attribute can be set at the same time by separating these attributes with spaces, as shown here.
attribute1="value" attribute2="value" . . .
The import attribute is used to import specific Java classes in order to be used in the JSP, and the location of the jar file containing the imported classes should be specified in the CLASSPATH definition of the servlet engine (or JSP container). Every JSP container provides a way to add custom entries to its CLASSPATH variable, and usually it is done through a visual aid such as a wizard. An example of the import attribute is shown here.
<%@ page import="java.util.* "%>
In this example, all the classes in the java.util package are imported, very similar to any Java class. The import attribute can be specified multiple times (obviously because we need to be able to import more than one package several times) and should be specified before attempting to use the imported classes.
The content type being sent to the client through the response object may be set using the contentType attribute, as shown in the following examples.
<%@ page contentType="text/html" %> <%@ page contentType="text/plain" %> <%@ page contentType="image/gif" %>
This is also equivalent to setting the content type using the setContentType() method of the response object, which is predefined within the context of a page. This attribute must be specified at the beginning of the page. By default, the HTML format is used.
The buffer attribute is used to set the amount of buffer to be filled in the response object before sending the response to the client, as shown in the following example.
<%@ page buffer="16kb" %> <%@ page buffer="none" %>
The first line sets the buffer to 16 KB, and the second line turns off buffering. A larger buffer provides the JSP engine more time to fill the content before throwing the output to the client, and a smaller value will enable the client to receive content faster. Both methods have their own advantages and disadvantages. The JSP engine may ignore the specified value and use a default value if necessary.
The errorPage attribute is used to set an error page to be displayed in case an exception occurs while processing the current JSP page. The following example shows the syntax to define an error page. For this attribute to work properly, the error page should have been created before; the JSP engine does not create a page for you.
<%@ page errorPage="error page name" %>
The isErrorPage attribute is used to indicate whether the current page is playing the role of an error page for other JSP pages. The permissible values for this attribute are true or false, as it is a Boolean attribute.
<%@ page isErrorPage="true" %> <%@ page isErrorPage="false" %>
The isThreadSafe attribute is also Boolean, as shown below, and indicates to the JSP engine whether the page is going to be executed in multi-threaded mode (when the attribute value is true, which is default) or single-threaded mode (when the attribute value is false). Recall the earlier discussion about the servlets, which could also be implemented in either multi-threaded mode or single-threaded mode.
<%@ page isMultiThreaded="true" %> <%@ page isMultiThreaded="false" %>
When using the page in its default (multi-threaded) mode, the developer must ensure that the access to shared objects is synchronized in order to protect the object’s data from being modified concurrently by multiple threads.
Including External Files in JSP Pages
The include directive is used to include external resources such as an external JSP page within the current JSP page. The external file is specified with the file attribute. In this case, the external resource may contain JSP code, and the page is included before the current page is translated and compiled into a servlet. The include directive facilitates including the same external page to be reused in multiple JSP files, thus modularizing reusable code. However, the disadvantage of this directive is that if the external JSP file’s contents are changed, then each of the files that include the external file must acknowledge somehow that the file has changed, so that the JSP engine will retranslate and recompile these JSP files automatically. This involves manual efforts to at least change the last updated timestamp of these files. Another important feature to keep in mind while using this approach is that the included file may be cached by the container if caching is enabled, in order to achieve higher application performance. Disabling caching might make the container recompile the included files, at the cost of performance. The syntax of the include directive is given below.
<%@ include file="external.jsp" %>
Another way to include external resources is by using the jsp:include element (or tag) and specifying the included file name as value for the page attribute. In this approach, the inclusion happens when the JSP file is executed in response to a client’s request as opposed to during the page translation discussed earlier. If the included page contains dynamic content, then the included page is executed separately and the resulting static (HTML) content is placed in the page that includes the external file. On the other hand, if the included file contains only static content, it is directly included without having a need to interpret the file. Another feature of using this approach is that the included files are never cached, because the JSP engine accesses these files every time a request is received. The syntax of using the jsp:include element is given here.
<jsp:include page="external.jsp" />
Based on the discussion on both types of including external files, at times we may have to use a combination of both scenarios. Also, the syntactical difference should be noted between the two types of includes.
Using Applets in JSP Pages
Apart from the jsp:include tag, there are other useful tags that need to be discussed. The jsp:plugin element is used to use an applet or a bean in a JSP page. The syntax of this element is given in the following example.
<jsp:plugin type="applet" code="ShowChart.class" width="300" height="200" align="left" > </jsp:plugin>
Here, the type attribute specifies that the plugin is a Java applet, the code attribute specifies the class name that contains the applet code, width and height attributes specify the size of the applet with specific number of pixels, and the align attribute indicates how it should be aligned. Because the applet can accept parameters through the getParameter() method, these parameters can be specified through the jsp:params and jsp:param elements; the first element identifies the group of parameters enclosed within this element, while the second element identifies each of the individual parameters. When these elements are applied to the previous example, the code might look like the following. (There are other attributes that the jsp:plugin tag can accept and that are not discussed here, and the reader is encouraged to refer to the JSP documentation.)
<jsp:plugin type="applet" code="ShowChart.class" width="300" height="200" align="left" > <jsp:params> <jsp:param name="month" value="March" /> <jsp:param name="year" value="2003" /> </jsp:params> </jsp:plugin>
When the JSP page is compiled by the JSP engine, the above code converted to either the OBJECT tag or the EMBED tag according to whether the browser is Microsoft Internet Explorer or Netscape Navigator.
Using JavaBeans in JSP Pages
In a typical Web application, JSP pages play the role of presentation layer, and every application needs a source of data to provide the dynamic content. There is hardly any Enterprise-class application that does not use data read from a data source such as a database. If a JSP page does not use dynamic content, it is probably not necessary to code the page as JSP; rather, a static HTML page would serve the need. The data objects from the data source are represented by appropriately designed JavaBeans or Enterprise JavaBeans; therefore every JSP developer needs to know how to use JavaBeans and EJBs within the JSP pages. Any Java class can be used as a JavaBean if it adheres to certain specific rules: the class should have a constructor with no arguments, the class should not have any public instance variables, and the instance variables should be accessed through the get and set methods, followed by the name of the instance variable. Although the first character in the instance variable name is a lowercase letter, it should be in uppercase when suffixed to the get and set methods. For example, if the instance variable is named userName, the corresponding access methods are getUserName and setUserName. The instance variables are known as properties, and the get and set methods are known as access methods of the properties. A simple JavaBean class is presented in the following example, Listing 8.5, which is also available on the accompanying CD-ROM.
Listing 8.5: user.java JavaBean class
class user { private String firstName; private String lastName; public user() { } public user(String fName, String lName) { firstName = fName; lastName = lName; } public String getFirstName() { return firstName; } public void setFirstName(String fName) { firstName = fName; } public String getLastName() { return lastName; } public void setLastName() { lastName = lName; } }
This example provides a very simple JavaBean class without any methods to connect to a data source, retrieve data, and so on.
The jsp:useBean element is used to create objects of JavaBeans and work with their properties, as shown in the following example code:
<jsp:useBean scope="session" /> <jsp:setProperty name="aUser" property="firstName" value="<%=fName%>" /> <jsp:setProperty name="aUser" property="lastName" value="<%=lName%>" />
The jsp:useBean element is used to instantiate an object of the JavaBean class; the id attribute specifies the object name when creating the bean instance, the class name identifies the JavaBean class, and the scope attribute specifies the scope (or visibility) of the bean instance. In this example, the bean instance is visible at the session level. The jsp:setProperty element should be used to set the value of a property (or an instance variable), the name attribute identifies the bean instance name, the property attribute identifies the property to be set, and the value attribute identifies the value being set to the property. In this example, the property values are being retrieved from local (or global) variables fName and lName, respectively, using JSP expressions. The jsp:useBean element should be used only after the bean is instantiated with the jsp:useBean element; otherwise an exception is thrown. From the example, please note that even though the jsp:setProperty is used within the JSP code, internally it calls the property’s access method, setFirstName or setLastName accordingly. In JSP, we do not explicitly call the property’s access methods but, if the bean is used in another Java class, we do call the property’s access methods. Similar to the jsp:setProperty element, the jsp:getProperty element is used to retrieve the value of the specified property, as shown here.
<jsp:getProperty name="aUser" property="firstName" /> <jsp:getProperty name="aUser" property="lastName" />
In addition, the properties value may be retrieved through JSP expressions and scriptlets, depending on the purpose of retrieval and the context in which the bean is used, as shown in the examples below.
<%= aUser.getFirstName() %> <% String lName = aUser.getLastName(); %>
It should be noted that the bean instance name is used explicitly, as the bean is already instantiated with the jsp:useBean element. The JavaBean instances can also be created and used through the scriptlets. The scope of these bean instances can be extended by saving these object references at the required level, such as application context, session context, request context, and page context, as discussed earlier. However, using the jsp:useBean method is more straightforward and convenient.
Developing and Using Custom Tags
The final topic related to the JSPs is developing and using custom tags in JSP pages. By now, the readers should understand that the JSP pages (or any Web pages) are full of tags with embedded static and dynamic content. Although some of the tags (JSP tags) are recognized and interpreted by the JSP engine, some other tags (HTML tags) are recognized and interpreted by the browsers. However, all these tags are predefined by the appropriate interpreter architecture—either the JSP engine or the Web browser. Because the JSP engine provides a programmable environment to build (and embed) the dynamic content within the static HTML pages, it is also worthwhile to explore another very important feature of JSP that permits the developers to define custom tags with special features and implement them through custom Java classes. The steps involved in the process of building and using custom tags are described here, followed by a detailed explanation.
-
Create a tag handler class that performs the actual logic required when the tag is used in the JSP file. Typically, there is one tag handler class for every single custom tag.
-
Create a tag library descriptor file in XML format, defining the tag names and associating them with the appropriate tag handler classes.
-
In the JSP file, specify the tag library descriptor file to be used through the taglib directive.
-
Start using the tags in the JSP page, using the tag names specified in the tag library descriptor file.
The class that implements a tag handler should extend the javax.servlet.jsp.tagext.TagSupport base class, which provides the basic support needed for a tag handler. The derived class overrides one or more methods declared in the base class, thus providing necessary code for the tag it supports. The doStartTag() method is to be implemented with the code that should be executed when the starting tag is found in the JSP file. From within the tag class, the JSP page (where the tag is referenced) is accessed through the predefined pageContext field, which is an instance of the javax.servlet.jsp.PageContext class. This field is declared as protected in the base TagSupport class and is accessible to the extended classes. The pageContext field provides convenient methods to several implicit objects. The JspWriter object instance is available through the getOut() method and is used to write anything to the response object targeted to the client. The servlet config object is accessed through the getServletConfig() method, the servlet context object is accessed through the getServletContext() method, the session object is accessed through the getSession() method, and the request and response objects are accessible through the getRequest() and getResponse() objects, respectively.
When used in a JSP page, tags typically take the form <mytag>tag body</mytag>. Here, mytag represents the tag name and tag body represents the content enclosed within the beginning and ending tag marks of the tag. If the tag is used in standalone mode as in <mytag />without any body content, then it is known as a tag without associated body. In this case, it is sufficient to implement the doStartTag() method, and the method should return the static constant value SKIP_BODY. This static constant along with some others is defined in the base TagSupport class mentioned earlier. If the tag is going to support body (or is going to make use of the body content), then the method should return the static constant EVAL_BODY_INCLUDE. In this case, it may also be useful to implement the doEndTag() method, which is executed after processing the tag body, and any code that is necessary to conclude the work started in the tag may be implemented in this method. This method should return either SKIP_PAGE to indicate that the rest of the page should be skipped after completing the current tag or EVAL_PAGE to indicate that the processing should continue with the rest of the JSP page that follows the current end tag. The example provided in Listing 8.6 shows a simple custom tag implementation that displays the current timestamp. The tag handler is named
Listing 8.6: CurrTimeTag.java
package myTags; import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; import java.io.*; import java.util.*; // This is a simple tag handler class that prints // current timestamp to the output stream. class CurrTimeTag extends TagSupport { public int doStartTag() { try { Calendar currTime = Calendar.getInstance(); JspWriter out = pageContext.getOut(); out.println(currTime.getTime().toString()); } catch (Exception excp) { System.out.println("Error executing doStartTag method"); } return(SKIP_BODY); } }
Listing 8.7: CurrTimeTagLib.tld
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> <!-- This is a tag library descriptor file --> <taglib> <tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>mytags</shortname> <uri></uri> <info>My Example Tags</info> <tag> <name>ctime</name> <tagclass>myTags.currTimeTag</tagclass> <bodycontent>empty</bodycontent> <info>Current Time Display Tag</info> </tag> </taglib>
It may be noticed from the tag library descriptor file that the tag handler class currTimeTag is associated with a name to the tag—ctime—and the bodycontent attribute specifies that there is no body content. More tag definitions may be specified within the same tag library descriptor file, thus grouping tags together.
In the JSP file, the taglib directive is used to specify the tag library descriptor file before attempting to use the tag, as shown below.
<%@ taglib uri="CurrTimeTagLib.tld" prefix="mytags" %>
The prefix attribute in the taglib directive provides a prefix that should be prefixed to all the tags from this tag library when used in the JSP page. The tag is used in the page with syntax similar to the following.
<%= <mytags:ctime /> %>
Tags can be designed to accept attributes and make use of the body content. However, custom tag development is discussed here to introduce the concept to the readers, and more help may be obtained from the JSP documentation.
Jakarta Struts
Having provided sufficient input to the reader on developing servlets and JSP-based Web applications, it is now time to discuss a very useful third-party framework, known as Jakarta Struts, which is developed and maintained by the open source Apache Jakarta project team. The framework is completely developed in Java and is designed to work with servlets and Java Server Pages. Even though the framework is developed by an open source organization, it has become very popular in J2EE-based application development, and almost all the major vendors’ J2EE implementations have incorporated it. The Strutsframework is based on the Model 2 architecture, which is also known as the Model View Controller (MVC) architecture. Typically, a Web application consists of three main parts—the data model, the presentation layer, and the flow control. In the previous section, we discussed the process of using JavaBeans within JSP pages, thus the data model is separated in the form of JavaBeans from the rest of the Web application where the JSP pages contained both the presentation layer as well as the flow control logic. Essentially, this is the basic concept of the Model 1 architecture. The next architectural change is the Model 2 architecture, where the presentation layer and flow control layer are also separated, thus forming three independent layers—data model, presentation layer, and flow control. Hence the Model 2 architecture is also known as the Model, View, and Controller (MVC) architecture. This is a very robust (and hence popular) design pattern that formed the basis of the Struts framework.
In Struts, a servlet plays the main role of the controller (apart from other utility classes), while the JSP pages play the role of presentation layer (the View portion of MVC) and the JavaBeans (or EJBs) play the role of data model because they represent backend database objects. The framework efficiently divides the responsibilities among the three layers, and the connectivity between the layers is maintained through XML-based configuration files. There are two configuration files: the web.xml file is used by the application server and the Struts framework, and the struts-config.xml file is used by the Struts framework alone. An overview of a Web application running within the Struts framework and the application server is provided in Figure 8.8. The figure does not depict all the components that form part of the framework. The framework details, including the contents of the configuration files, will be discussed in this section.
From the figure, it may be noticed that the HTTP request is no longer directly received by the JSP pages. Rather, a controller servlet known as ActionServlet receives the HTTP request from the server and plays the role of controlling the entire process of servicing the request. The web.xml configuration file specifies the particular servlet that performs this task. When the application server first reads this file, it identifies the specific servlet that should be instantiated as the action controller and performs the necessary instantiation of this controller servlet. Although the controller part of the framework consists of more than a single component, it is still customary to call the ActionServlet as the controller servlet as it performs the role of the central controlling unit of the entire process. The functionality of this component is implemented in the org.apache.struts.action.ActionServlet class, which may be directly used in the application. Usually, it will not be necessary to extend this servlet, as it is complete in almost every aspect. The ActionServlet is derived from the base javax.servlet.http.HttpServlet class. Every request received by the server for this application has a few settings defined in the struts-config.xml file. When the ActionServlet receives the request, it attempts to map the request with the action elements pre-defined in the struts-config.xml file. For the purpose of understanding the framework, let us consider the requests as actions and the corresponding mappings as action mappings. At the minimum, an action mapping consists of an action object that can perform the action and one or more action-forward statements. An action object is a Java class that extends the org.apache.struts.action.Action class, and an action-forward statement typically identifies the specific JSP page that should be displayed for a specific status returned by the action object. For every action mapping, the ActionServlet creates an ActionMapping object of org.apache.struts.action.ActionMapping class, and for every action forward statement, it also creates an ActionForward object of org.apache.struts.action.ActionForward class. In addition, every JSP page can be associated with an ActionForm object type, which is used to perform validation of input data entered by the user into the JSP page. The ActionForm objects are also known as form beans, as their construction resembles that of JavaBeans. For every input field in the JSP file that needs to be validated, a property and associated access methods are defined in the form bean class. In a typical Struts-based implementation, every request is mapped to an action, and every JSP page might have an associated form bean for validation. While the former is required, the latter is optional. Every action class is derived from the org.apache.struts.action.Action class, and every form bean is derived from the org.apache.struts.action.ActionForm class. The form bean class implements the validate() method to start the data validation and the reset() method to reset the values of the input fields. Figure 8.9 displays a sample action mapping in a struts-config.xml file, with the associated struts objects.
The action element that is used in the figure is given in the following.
<action path="/order" type="com.mycompany.orderAction" name="orderForm" scope="request" validate="true" input="order.jsp" <forward name="success" path="/actions/billing" redirect="true" <forward name="failure" path="/actions/error" redirect="true" </action
This listing displays how an action element is described within the struts-config.xml file and is mapped with different Struts objects in the figure. The complete listing of the file contains several other elements and is displayed later. For the sake of simplifying the discussion, a portion of the file is extracted and displayed at appropriate locations in the chapter. From the listing, we can notice that the action element can have a number of associated attributes.
The path attribute identifies the path infostring in the context of a URL. For example, if the URL string is http://www.myserver.com/ordermgmt/actions/order, the /ordermgmt/ string may represent application’s base directory as configured with the application server. All the files related to a Web application are placed within the application’s base directory. This is normally the case when the Web application is developed using a technology other than J2EE. However, J2EE applications are organized differently, and all the files belonging to a Web application are typically archived into a Web application archive (WAR) file containing the .warfile extension, which is placed within the application base directory, which is /ordermgmt/ in the current example. When the Web application is developed using a commercial tool such as Borland JBuilder or IBM WebSphere Application Developer, they are capable of creating the WAR files using powerful wizards. Even Sun Microsystems’ J2EE reference implementation (a free download from http://java.sun.com Web site) provides necessary tools for development and testing purposes.
The subdirectories under the application base directory (such as /actions/ in this case) may be fictitious, or they may be real subdirectories (such as /jsp/, /html/, or /images/) where we place the JSP files or compiled Java classes, images, HTML files, and so on. However, with Java class files, the subdirectory tree should match the package names (and their hierarchy) specified in the Java class source files. The Web application configuration file, web.xml, is known as (and plays the role of) the deployment descriptor, where we identify the ActionServlet with a name and also specify a url-pattern to indicate the type of path info strings that the servlet is going to service, among other configuration details. Listing 8.8 displays a typical deployment descriptor file.
Listing 8.8: web.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet- class> <init-param> <param-name>debug</param-name> <param-value>2</param-value> </init-param> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <taglib> <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri> <taglib-location>/WEB-INF/struts-bean.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri> <taglib-location>/WEB-INF/struts-html.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri> <taglib-location>/WEB-INF/struts-logic.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-template.tld</taglib-uri> <taglib-location>/WEB-INF/struts-template.tld</taglib-location> </taglib> </web-app>
If we define the url-pattern as /actions/*, then every path info string that is specified after /actions/ is considered as an individual action to be serviced by the servlet, provided there is an associated action element in the struts-config.xml file. Because the action names specified as the path info string do not really represent any files in the Web application directory structure, the /actions/ subdirectory in this example (or any other similar subdirectory names) represents a fictitious directory as specified earlier. However, through the struts-config.xml file, we correlate the specific action names with the associated action classes and other attributes such that the ActionServlet will be able to use appropriate action objects (and other Struts objects) to service the requests. Again, this concept of fictitious subdirectories to represent actions corresponding to HTTP requests is only specific to the Struts framework. If an application is implemented without using Struts, then the discussion related to the struts-config.xml file and the concept of fictitious subdirectories may be ignored.
Let us now focus on the attributes and sub-elements specified with respect to the action elements. The type attribute identifies the fully qualified action class (which is derived from the org.apache.struts.action.Action class) name and should be placed in the CLASSPATH specified for the application. It should be noted that for every action, we need to create such an action class and implement the execute() method. In the example, it is named orderAction class in the package com.mycompany.
The name attribute identifies the name of the form bean and should be predefined within the form-beans element of the struts-config.xml file. As discussed earlier, the form beans are used to validate data entered through JSP file’s input forms. If a particular JSP page does not need validation, it is not necessary to create the form bean class and define it in the struts-config.xml file. Therefore, this attribute is optional. The scope attribute identifies the scope that governs the lifetime of the form bean and therefore should only be present if the name attribute is present. The default value for this attribute is session, while the permitted values are request and session. The validate attribute identifies a Boolean value true or false, and when set to true, it indicates that the validate() method of the form bean should be invoked before invoking the execute() method on the action class, and therefore should only be present if the form bean name is specified. In other words, this attribute functions like a switch to turn on or off the form validation—even though the form bean is implemented—and is a useful feature during development and debugging. The input attribute identifies the input JSP page that is associated with the form bean, so that in case the validation fails, the servlet returns this page to the browser for correcting input errors.
The forward element specifies a resource such as a JSP page (or an HTML page) and its URL is specified in the path attribute. This URL is specific to the application’s base directory or may even represent another action element. Every forward element has a name—such as “success” or “failure” in the example—that identifies the forward element logically and is useful for referencing in the programs with this name. In the current example, when the forward element “success” identifies another action, say billing, it means that if the order action is successful, then the servlet should initiate the next action, which is billing. Similarly if the order action fails, the next error action should performed. The redirect attribute is a Boolean value and indicates whether the servlet should redirect to the specified page (when true) or should forward (when false) to the specified page.
If there is no action mapping defined in the struts-config.xml file, then no action takes place. This is what happens when developers forget to define an action mapping after developing an action object and the associated JSP files. If there is an action mapping found for the specific request, then the ActionServlet identifies an action object that could perform this action and invokes the execute() method of this action object. If a form bean is defined for the input page of this action and the validate attribute is set to true, then the validate() method of the form bean is executed before the execute() method of the action class.
In addition to the configuration details discussed so far, the struts-config.xml file has other details, such as a data-sources element to provide one or more data-source details, a global-exceptions element, and a global-forwards element that permit us to define exceptions and forwards that are available for all the action objects in the application.
The Struts framework is evolving very fast and, at the time of writing this book, Release 1.1 is in final stages of beta. By the time the book is released to the market, Struts 1.1 should be available as a stable production release. This release features a number of enhancements to the earlier 1.0 release that aim at providing more flexibility to the framework without losing the power.
| < Day Day Up > |
|