Oracle® Containers for J2EE Servlet Developer's Guide 10g (10.1.3.1.0) Part Number B28959-01 |
|
|
View PDF |
This chapter, consisting of the following sections, provides basic information for developing servlets for OC4J and the Oracle Application Server:
For more general OC4J development information, refer to the Oracle Containers for J2EE Developer's Guide.
Note: For use during development, there is a convenience flag to direct automatic recompilation of servlet source files in a specified directory. If a source file has changed since the last request, then OC4J will, upon the next request, recompile the servlet, redeploy the Web application, and reload the servlet and any dependency classes. See the description of thedevelopment flag under "<orion-web-app>". |
HTTP servlets follow a standard form. They are written as public classes that extend the javax.servlet.http.HttpServlet
class. Most servlets override either the doGet()
method or the doPost()
method of HttpServlet
, to handle HTTP GET
or POST
requests, respectively. It may also be appropriate to override the init()
and destroy()
methods if special processing is required for initialization work at the time the servlet is loaded by the container, or for finalization work when the container shuts down the servlet.
The following subsections cover basic scenarios for implementing these methods, show how to set up the response, and go step-by-step through the code of a Hello World servlet:
Here is a basic code template for servlet development:
package ...; import ...; public class MyServlet extends HttpServlet { public void init(ServletConfig config) { } public void doGet(HttpServletRequest request, HttpServletResponse) throws ServletException, IOException { } public void doPost(HttpServletRequest request, HttpServletResponse) throws ServletException, IOException { } public void doPut(HttpServletRequest request, HttpServletResponse) throws ServletException, IOException { } public void doDelete(HttpServletRequest request, HttpServletResponse) throws ServletException, IOException { } public String getServletInfo() { return "Some information about the servlet."; } public void destroy() { } }
The subsections that follow discuss the scenarios for overriding any of these methods.
You can override the init()
method to perform special actions that are required only once in the servlet lifetime, such as the following:
Establish database connections.
Get initialization parameters from the servlet configuration object and store the values.
Recover persistent data that the servlet requires.
Create expensive session objects, such as hashtables.
For example, to establish a database connection through a data source:
public void init() throws ServletException { try { InitialContext ic = new InitialContext(); // JNDI initial context ds = (DataSource) ic.lookup("jdbc/OracleDS"); // JNDI lookup conn = ds.getConnection(); // database connection through data source } ... }
Almost any servlet will override the doGet()
method, to handle an HTTP GET
request, or the doPost()
method, to handle an HTTP POST
request, for the bulk of its processing. GET
and POST
are the two HTTP methods for passing form data to the server. A detailed discussion of when to use one versus the other is beyond the scope of this manual, but the doPost()
method may be more appropriate if security is a particular concern, given that the GET
method places form parameters directly in the URL string, or for large sequences of data, allowing the client to send data of unlimited length to the server.
In implementing doGet()
or doPost()
, in addition to writing the code that generates the data to pass to the client, you will typically write code to read data from the HTTP request, set up the HTTP response, and write the response. For additional information, see "Setting Up the Response", which follows shortly, and "Using HTML Forms and Request Parameters".
"Step-by-Step Through a Simple Servlet" shows the steps for an elementary doGet()
implementation.
Use this method to execute an HTTP PUT
request, which allows a file to be written from the client to the server. The doPut()
method must be able to handle a content header (or issue an error message if it cannot), and must leave any content headers it encounters intact.
Use this method to execute an HTTP DELETE
request, which allows a file or Web page to be removed from the server.
Use this method to retrieve information from the servlet, such as author and version. By default, this method returns an empty string, so you must override it to provide any meaningful information.
This method is called by the servlet container when the servlet is about to be shut down. You can override it for any cleanup prior to shutdown that is appropriate for your servlet, such as the following:
Update any persistent data to make sure it is current.
Clean up any resources, such as database connections or file handles.
For example, to close the database connection that was opened in "When to Override the init() Method":
public void destroy() { try { conn.close(); } ... }
To send a response from your servlet, use the HttpServletResponse
instance that is passed in to the servlet method you are using, typically doGet()
or doPost()
. The key steps are as follows:
Set a content type, and optionally a character encoding (MIME character set), for the response.
Note: The OC4J default content type, if any, is reflected in the<default-mime-type> element of the OC4J global-web-application.xml (global) or orion-web.xml (application-level) Web application configuration file. You can set it through the deployment plan editor in the Application Server Control Console, introduced in "A Brief Overview of OC4J Administration". |
Get a writer object (java.io.PrintWriter
), for character data, or an output stream (javax.servet.ServletOutputStream
), for binary data, from the response object.
Write the response data to the writer object or output stream.
Here is some code that shows these steps.
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html><body><h1>Hello World</h1></body></html>"); ... }
See "Key Methods of the HttpServletResponse Interface" for a summary of response methods.
This chapter shows a Hello World example that overrides the doGet()
method. This servlet is shown in its entirety in "Simple Servlet Example", but we also go through it step-by-step here.
Initial steps in the servlet example:
Declare a package, as appropriate. The servlet example declares mytest
:
package mytest;
Import required Java packages, particularly the servlet packages. The following are typically required:
import java.io.*; import javax.servlet.*; import javax.servlet.http.*;
Declare the servlet class, which always extends HttpServlet
for HTTP operations:
public class HelloWorld extends HttpServlet { ... }
Declare any servlet method that you want to override. The servlet methods for HTTP operations all take the same parameters (an HTTP request object and an HTTP response object) and throw the same exceptions. The servlet example overrides doGet()
:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { ... }
Steps in the servlet example doGet()
method:
Set the content type for the response object. This may not always be required, but is generally advisable:
response.setContentType("text/html");
Optionally, you can also specify a character encoding, such as UTF-8 in the following example:
response.setContentType("text/html; charset=UTF-8");
Get a writer object from the response object:
PrintWriter out = response.getWriter();
Write the data to the response object:
out.println("<html>"); out.println("<head>"); out.println("<title>Hello World!</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hi Amy!</h1>"); out.println("</body>"); out.println("</html>");
Close the output stream, which also commits the response.
out.close();
(In this simple example, manipulating request data is not required.)
This section shows the complete simple servlet example that is discussed, step-by-step, in the preceding section. This example is deployed and invoked in "Deploying and Invoking the Simple Servlet Example".
The following code writes "Hi Amy!" to the browser. Enter the code into a file called HelloWorld.java
. According to the package
statement, the HelloWorld
class will be in package mytest
.
package mytest; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloWorld extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Hello World!</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hi Amy!</h1>"); out.println("</body>"); out.println("</html>"); out.close(); } }
Compile the sample code. If you are using a JDK from Sun Microsystems, with their default compiler, accomplish this as follows, from the directory where the .java
file is located (assuming %
is the system prompt):
% javac HelloWorld.java
|
A typical servlet might ask the user to enter some information for the servlet to display or manipulate. The servlet can use HTML forms to take the information, store it in parameters of the HTTP request object, and send it to the server. You can also retrieve other information from the request object, such as the protocol, HTTP method, and request URI being used.
The following sections show some examples:
HTTP request parameters will not be available to servlet filters that are meant to be executed before dispatch of the request to a static resource (an .html
file, for example). Filters that execute before dynamic resources, such as a servlet or JSP page, will have access to the parameters.
See "Key Methods of the HttpServletRequest Interface" for a summary of request methods.
A servlet can use an HTML form to take input from the user, then submit these data to the server as parameters of the HTTP request object. Here is an example:
PrintWriter out = response.getWriter(); ... out.print("<form action=\""); out.print("RequestParamExample\" "); out.println("method=GET>"); out.println("Enter a new first name: "); out.println("<input type=text size=20 name=firstname>"); out.println("<br>"); out.println("Enter a new last name: "); out.println("<input type=text size=20 name=lastname>"); out.println("<br>" + "<br>"); out.println("<input type=submit>"); out.println("</form>");
This example prompts the user to enter his or her first name, stores it in a request parameter called firstname
, prompts for the last name, and stores it in a request parameter called lastname
. The request object is sent to the server, where the information is processed as desired (as shown in the next section).
A significant disadvantage to using the GET
method for this operation, however, is that the parameter names and values are appended to the servlet URL string. To prevent this, you can use the POST
method instead, as shown in "Using the POST Method for URL Security".
This section shows sample code that displays request parameter data that were specified by the user through an HTML form (shown in the preceding section).
PrintWriter out = response.getWriter(); ... String firstName = request.getParameter("firstname"); String lastName = request.getParameter("lastname"); out.println("First and last name from request:" + "<br>" + "<br>"); if (firstName != null || lastName != null) { out.println("First name "); out.println(" = " + firstName + "<br>"); out.println("Last name "); out.println(" = " + lastName + "<br>"); } else { out.println("(No names entered. Please enter first and last name.)"); }
The values of the request parameters firstname
and lastname
are stored in the strings firstName
and lastName
, then output to the user.
Here is the complete servlet with the code from the preceding sections. It prompts the user for first name and last name, with the information being written to the request object, then it retrieves the names from the request object and outputs them to the user. (The output code comes first, indicating "No names entered" until the user first enters some names.)
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class RequestParamExample extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<body>"); out.println("<h3>" + "My Request Parameter Example" + "</h3>"); String firstName = request.getParameter("firstname"); String lastName = request.getParameter("lastname"); out.println("First and last name from request:" + "<br>" + "<br>"); if (firstName != null || lastName != null) { out.println("First name "); out.println(" = " + firstName + "<br>"); out.println("Last name "); out.println(" = " + lastName + "<br>"); } else { out.println("(No names entered. Please enter first and last name.)"); } out.println("<P>"); out.print("<form action=\""); out.print("RequestParamExample\" "); out.println("method=GET>"); out.println("Enter a new first name: "); out.println("<input type=text size=20 name=firstname>"); out.println("<br>"); out.println("Enter a new last name: "); out.println("<input type=text size=20 name=lastname>"); out.println("<br>" + "<br>"); out.println("<input type=submit>"); out.println("</form>"); out.println("</body>"); out.println("</html>"); } }
When the servlet first starts, it shows the following:
If you enter "Jimmy" and "Geek" and then click Submit Query, it shows the following:
This servlet uses the HTTP GET method, resulting in the request parameter names and values being appended to the servlet URL. In this example, the string "?firstname=Jimmy&lastname=Geek " is appended. See the next section, "Using the POST Method for URL Security", for how to avoid this. |
The preceding example used the HTTP GET
method, which results in request parameter names and values being appended to the servlet URL. To avoid this (typically for security considerations), you can use the POST
method instead. In the following code, the preceding example has been modified to use the POST
method in the form, and to use a doPost()
method to call the doGet()
method. Changes are highlighted in bold.
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class RequestParamExample extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<body>"); out.println("<h3>" + "My Request Parameter Example" + "</h3>"); String firstName = request.getParameter("firstname"); String lastName = request.getParameter("lastname"); out.println("First and last name from request:" + "<br>" + "<br>"); if (firstName != null || lastName != null) { out.println("First name "); out.println(" = " + firstName + "<br>"); out.println("Last name "); out.println(" = " + lastName + "<br>"); } else { out.println("(No names entered. Please enter first and last name.)"); } out.println("<P>"); out.print("<form action=\""); out.print("RequestParamExample\" "); out.println("method=POST>"); out.println("Enter a new first name: "); out.println("<input type=text size=20 name=firstname>"); out.println("<br>"); out.println("Enter a new last name: "); out.println("<input type=text size=20 name=lastname>"); out.println("<br>" + "<br>"); out.println("<input type=submit>"); out.println("</form>"); out.println("</body>"); out.println("</html>"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { doGet(request, response); } }
Development Tip: There is still adoGet() method in this example, rather than using doPost() directly, because browsers use GET requests. |
"Key Methods of the HttpServletRequest Interface" lists some methods of the request object that you can use to retrieve information about the HTTP request. Here is a code sample that calls some of the information methods of a request object and outputs the information:
PrintWriter out = response.getWriter(); ... out.println("Method:"); out.println(request.getMethod()); out.println("Request URI:"); out.println(request.getRequestURI()); out.println("Protocol:"); out.println(request.getProtocol());
This example retrieves and displays the HTTP method (such as GET
or POST
), the request URI (consisting of the context path and servlet path in this example), and the protocol (such as HTTP). The next section shows a complete example.
Here is a complete servlet that retrieves the HTTP method, request URI, and protocol, and outputs them in an HTML table.
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class RequestInfoExample extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<body>"); out.println("<h3>" + "My Request Info Example" + "</h3>"); out.println("<table border=0><tr><td>"); out.println("Method:"); out.println("</td><td>"); out.println(request.getMethod()); out.println("</td></tr><tr><td>"); out.println("Request URI:"); out.println("</td><td>"); out.println(request.getRequestURI()); out.println("</td></tr><tr><td>"); out.println("Protocol:"); out.println("</td><td>"); out.println(request.getProtocol()); out.println("</td></tr>"); out.println("</table>"); out.println("</body>"); out.println("</html>"); } }
This results in output such as the following:
Many servlets use other servlets in the course of their processing, either by including the response of another servlet or by forwarding the request to another servlet. The following subsections discuss these features and show examples:
Note: The target of an include or forward can be a JSP page as well as a servlet. Wherever target servlets are discussed in the following text, you can assume the same applies to target JSP pages. |
In servlet terminology, a servlet include is the process by which a servlet includes the response from another servlet within its own response. Processing and response are initially handled by the originating servlet, then are turned over to the included servlet, then revert back to the originating servlet once the included servlet is finished.
With a servlet forward, processing is handled by the originating servlet up to the point of the forward call, at which point the response is reset and the target servlet takes over processing of the request. When a response is reset, any HTTP header settings and any information in the output stream are cleared from the response. After a forward, the originating servlet must not attempt to set headers or write to the response. Also note that if the response has already been committed, then a servlet cannot forward to or include another servlet.
To forward to or include another servlet, you must obtain a request dispatcher for that servlet—this is the mechanism for dispatching an HTTP request to an alternative servlet. Use either of the following servlet context methods:
RequestDispatcher getRequestDispatcher(String path)
RequestDispatcher getNamedDispatcher(String name)
For getRequestDispatcher()
, input the URI path of the target servlet. For getNamedDispatcher()
, input the name of the target servlet, according to the <servlet-name>
element for that servlet in the web.xml
file.
In either case, the returned object is an instance of a class that implements the javax.servlet.RequestDispatcher
interface. (Such a class is provided by the servlet container.) The request dispatcher is a wrapper for the target servlet. In general, the duty of a request dispatcher is to serve as an intermediary in routing requests to the resource that it wraps.
A request dispatcher has the following methods to execute any includes or forwards:
void include(ServletRequest request, ServletResponse response)
void forward(ServletRequest request, ServletResponse response)
As you can see, you pass in the servlet request and response objects when you call these methods.
A servlet include is a convenient way to do any of the following:
Reuse existing code without having to rewrite it.
Include the same processing or output in multiple servlets, without having to implement the code in each individual servlet.
Include content from a static file.
You are including the output of the target servlet in addition to the output of the originating servlet.
These points are similarly true for servlet forwards, but remember that with a forward, the output of the target servlet is instead of the output of the originating servlet, not in addition to it.
Here are basic steps to implement an include or forward:
Use the getServletConfig()
method of the servlet (specified in the javax.servlet.Servlet
interface) to retrieve a servlet configuration object.
ServletConfig config = getServletConfig();
Use the getServletContext()
method of the servlet configuration object to retrieve the servlet context object for the servlet.
ServletContext context = config.getServletContext();
Use the getRequestDispatcher()
or getNamedDispatcher()
method of the servlet context object to retrieve a RequestDispatcher
object. For getRequestDispatcher()
, specify the URI path of the target servlet; for getNamedDispatcher()
, specify the name of the target servlet, according to the relevant <servlet-name>
element in the web.xml
file.
RequestDispatcher rd = context.getRequestDispatcher("path"); RequestDispatcher rd = context.getNamedDispatcher("name");
Use the include()
or forward()
method of the request dispatcher, as appropriate, to execute the include or forward, respectively. Pass the servlet request and response objects.
rd.include(request, response); rd.forward(request, response);
You can combine all four steps into a single statement, as in the following example:
getServletConfig().getServletContext().getRequestDispatcher
("path").include(request, response);
Note: Alternatively, you can retrieve a request dispatcher through thegetRequestDispatcher() method of the request object (HttpServletRequest instance). |
The next section shows a complete example for a servlet include.
This section provides a complete example of a servlet including the output of another servlet. The RequestInfoExample
class, shown in "Complete Example Retrieving Request Information", is updated to include output from a slightly modified version of the HelloWorld
class shown in "Simple Servlet Example".
Here is the slightly modified Hello World example whose output will be included. The class is now called HelloIncluded
and is not in a package:
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloIncluded extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Hello World!</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hi Amy!</h1>"); out.println("</body>"); out.println("</html>"); } }
Here is the updated request information example class, now called RequestInfoWithInclude
, that includes the output from HelloIncluded
. Key code is highlighted in bold:
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class RequestInfoWithInclude extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<body>"); out.println("<h3>" + "My Request Info Example" + "</h3>"); out.println("<table border=0><tr><td>"); out.println("Method:"); out.println("</td><td>"); out.println(request.getMethod()); out.println("</td></tr><tr><td>"); out.println("Request URI:"); out.println("</td><td>"); out.println(request.getRequestURI()); out.println("</td></tr><tr><td>"); out.println("Protocol:"); out.println("</td><td>"); out.println(request.getProtocol()); out.println("</td></tr>"); out.println("</table>"); out.println("</body>"); out.println("</html>"); getServletConfig().getServletContext().getRequestDispatcher ("/mypath/helloincluded").include(request, response); } }
The path /mypath/helloincluded
is a URI consisting of the context path and servlet path. The assumption is that the application has been configured so that HelloIncluded
can also be requested directly, as follows:
http://host:port/mypath/helloincluded
See Chapter 2, "Deploying and Invoking Servlets" for related information.
You could similarly include a JSP page instead of a servlet, such as in the following example:
getServletConfig().getServletContext().getRequestDispatcher ("/mypath/hello.jsp").include(request, response);
Invoking RequestInfoWithInclude
results in output such as the following:
Request objects and response objects are typically passed directly between the servlet container and a servlet. The servlet specification, however, allows servlet filters, which are Java programs that execute on the server and can be interposed between servlets and the servlet container to wrap and preprocess requests or to wrap and postprocess responses. A filter is invoked when there is a request for a resource that the filter has been mapped to in the servlet configuration.
Filters can effectively transform requests and responses. Use filters if you want to apply preprocessing or postprocessing for a group of servlets. (If you want to modify the request or response for just one servlet, there is no need to create a filter. You can just do what is required directly in the servlet itself.)
You can use filters in scenarios such as accessing a resource, or processing a request to that resource, prior to the request being invoked; or wrapping a request or response in a customized request object or response object, respectively. You can act on a servlet with a chain of filters in a specified order.
One example is an encryption filter. Servlets in an application may generate response data that is sensitive and should not go out over the network in clear-text form, especially when the connection has been made using a nonsecure protocol such as HTTP. A filter can encrypt the responses. (Of course, in this case the client must be able to decrypt the responses.) Other examples are filters for authentication, logging, auditing, data compression, and caching.
See Chapter 4, "Understanding and Using Servlet Filters" for details.
The servlet specification adds the capability to track key events in your Web applications through event listeners. You can implement listeners to notify your application of application events, session events, or request events. This functionality allows more efficient resource management and automated processing based on event status.
Use event listeners if there is reason for your application to be notified of any of the following.
For the servlet context:
The servlet context is newly created or is about to be shut down.
Servlet context attributes are added, removed, or replaced.
For a session:
A session is newly created or is newly invalidated or timed out.
Session attributes are added, removed, or replaced.
A session is newly active or passive.
An object is newly bound to or unbound from a session.
For a request:
A request is being newly processed.
Request attributes are added, removed, or replaced.
As an example, consider a Web application comprising servlets that access a database. You can create a servlet context lifecycle event listener to manage the database connection. This event listener may function as follows:
The event listener is notified of application startup.
The application logs in to the database and stores the connection object in the servlet context.
Servlets use the database connection to perform SQL operations.
The event listener is notified of imminent application shutdown (shutdown of the Web server or removal of the application from the Web server).
Prior to application shutdown, the event listener closes the database connection.
An event listener class is declared in the web.xml
deployment descriptor and invoked and registered upon application startup. When an event occurs, the servlet container calls the appropriate event listener method.
See Chapter 5, "Understanding and Using Event Listeners" for details.
The following changes have been made to the error messages that are presented when an exception occurs and there is no error page to handle it.
The following error message appears for security-sensitive exceptions:
Servlet error: An exception occurred. For security reasons, it may not be included in this response. Please consult the application log for details.
For other exceptions, the following error message appears:
Servlet error: An exception occurred. The current application deployment descriptors does not allow for including it in this response. Please consult the application log for details.
If you have tests that rely on the display of an exception or stack trace, you can cause the stack trace to be displayed by running the application in developer mode.
To run an application in development mode, set the development
attribute of the <orion-web-app>
element to "true"
in the orion-web.xml
file.
Here is an example:
<?xml version="1.0"?>
<orion-web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://xmlns.oracle.com/oracleas/schema/orion-web-10_0.xsd"
deployment-version="null"
deployment-time="1152223108413"
jsp-cache-directory="./persistence"
jsp-cache-tlds="standard"
temporary-directory="./temp"
context-root="/DevelopmentThrowException"
schema-major-version="10"
schema-minor-version="0"
development="true">
<!-- Uncomment this element to control web application class loader behavior.
<web-app-class-loader search-local-classes-first="true" include-war-manifest-class-path="true" />
-->
<web-app>
</web-app>
</orion-web-app>}}
This section provides information about migrating a Web application that includes servlets, JSP modules, or both from Apache Tomcat to OC4J. The following topics are discussed:
This section provides pointers about migrating Java servlets from Tomcat to Oracle Application Server. This section contains the following topics:
Migrating Java servlets from Tomcat to OC4J is straightforward, requiring little or no code changes to the servlets migrated, depending on some of the choices made in the Tomcat environment.
Oracle Application Server 10g Release 3 (10.1.3.x) is fully compliant with Sun Microsystem's J2EE Servlet specification, version 2.4. Tomcat 5.5 is also compatible with version 2.4.
In addition, Oracle Application Server 10g Release 3 (10.1.3.x) is backward compatible to Servlet 2.3. Hence, servlets written to the standard 2.3 specification should work correctly in OC4J and require minimal migration effort.
The primary tasks involved in migrating servlets to a new environment are configuration and deployment.
The tasks involved in migrating servlets also depend on how the servlets have been packaged and deployed. Servlets can be deployed as a simple servlet, as a Web application packaged with other resources in a standard directory structure, or as a Web archive (WAR) file.
The typical steps for migrating servlets to OC4J are as follows:
Configuration: Create or modify the Oracle Application Server deployment descriptors for the servlets.
Packaging:
Simple servlets can be deployed individually.
Servlets can be packaged as part of a Web application in a WAR file.
Deployment: Application Server Control Console can be used to deploy servlets in a WAR file. Individual servlets and servlets in exploded Web applications can be deployed automatically by copying them to the appropriate directories.
Oracle JDeveloper provides tools and wizards to automate these steps.
Simple servlets are easily configured and deployed in OC4J. The manual process used to deploy a servlet is the same in both Tomcat and OC4J.
Note: The recommended and preferred way to deploy a servlet is by packaging it in a WAR or EAR file and using Oracle Enterprise Manager 10g Application Server Control Console.Alternatively, you can deploy manually using the |
A servlet must be registered and configured as part of a Web application. To register and configure a servlet, several entries must be added to the Web application deployment descriptor.
The typical steps to deploy a simple servlet are as follows:
Update the Web application deployment descriptor (web.xml
) with the name of the servlet class and the URL pattern used to resolve requests for the servlet.
Copy the servlet class file to the WEB-INF/classes/
directory. If the servlet class file contains a package statement, create additional subdirectories for each level of the package statement. The servlet class file must then be placed in the lowest subdirectory created for that package.
Extract and copy the supporting utility class file and any other supporting files required by the servlet to the appropriate directory in the Oracle Application Server installation.
Start or restart the home OC4J "home" instance.
Invoke the servlet from your browser by entering its URL.
A Web application can be configured and deployed as a WAR file. This is most easily accomplished in OC4J by using the Application Server Control Console administration GUI. Alternatively, you can manually copy the WAR file to the appropriate directory. This is also true for Tomcat.
Note: Manually copying a WAR file to the appropriate directory to deploy it should only be done in a development environment where OC4J is in standalone mode (not a component of an Oracle Application Server instance). |
Production Web applications are typically deployed using WAR or EAR files through Application Server Control Console or the utility. During the development of a Web application, it may be faster to deploy and test edited code using an exploded directory format.
See the Oracle Containers for J2EE Deployment Guide for more information on deployment.
The typical steps for migrating a WAR file from Tomcat to OC4J are as follows:
Create the WAR file for the sample application.
Deploy the sample application to OC4J.
Test the deployed application.
Web applications can also be configured and deployed as a collection of files stored in a standard directory structure or exploded directory format. This can be accomplished in OC4J by manually copying the contents of the standard directory structure to the appropriate directory in the OC4J installation. The same method can also be used for Tomcat.
Deploying a Web application in exploded directory format is used primarily during the development of a Web application. It provides a fast and easy way to deploy and test changes. When deploying a production Web application, package the Web application in a WAR file and deploy the WAR file using Application Server Control Console.
The typical steps for manually deploying an exploded Web application in OC4J are as follows:
Copy the top-level directory containing the exploded Web application into the following directory of your OC4J installation: <ORACLE_HOME>/j2ee/home/applications
Then, modify the application deployment descriptor <ORACLE_HOME>/config/application.xml
to include the Web application, as follows:
<web-module id="migratedHR" path="../applications/hrapp" />
Bind the Web application to your Web site by adding an entry in the descriptor file <ORACLE_HOME>/config/default-web-site.xml
, as follows:
<web-app application="default" name="migratedHR " root="/hr" />
Finally, register the new application by adding a new <application>
tag entry in the following file: <ORACLE_HOME>/config/server.xml
When you modify server.xml
and save it, OC4J detects the timestamp change of this file and deploys the application automatically. OC4J need not be restarted.
Here are some issues to watch out for when porting from Tomcat to OC4J.
Tomcat is not entirely compliant with the Servlet specification with respect to the following methods of the ServletContext
class:
ServletContext.getResource()
ServletContext.getResourceAsStream()
The methods getResource()
and getResourceAsStream()
take a path parameter. This path allows you to access files in your web application directory structure such as WEB-INF/config.xml
.
The J2EE API documentation and specifications state the following:
"The path must begin with a "/" and is interpreted as relative to the current context root."
Tomcat, contrary to the Servlet specification, allows path names without the initial slash (/).
OC4J, in full compliance with the Servlet specification, requires the initial slash (/).
Don't forget the initial slash (/) on path names to access files with the ServletContext
class.
In OC4J, you can use several different JNDI context factories, each of which creates an InitialContext
and comes with different functionalities.
The most commonly used context factories are the following:
The internal context factory - You get the internal context factory when you are within the OC4J container and you call the default constructor of InitialContext
without jndi.properties
in the class path.
RMIInitialContextFactory
- This context factory is commonly used to connect to the OC4J container. It ignores every configuration and does not require the java:comp/env/
prefix.
ApplicationClientContextFactory
- This context factory takes care of your JNDI environment (especially in META-INF/application-client.xml
) and honors the java:comp/env/
environment prefix.
If the code relies on Xerces/Xalan, then additional steps must be taken.
Metalink has additional information about this topic.
Tomcat enables you to look up resources using java:
comp
/
env
/
ResourceName
without defining a <resource-ref>
element in web.xml
.
OC4J requires the <resource-ref>
element in web.xml
or the lookup is just as ResourceName
.
OC4J can do this by default for a Data Source defined on the server:
initialContext.lookup("jdbc/ScottDS")
Whereas Tomcat can do it like this:
initialContext.lookup("java:comp/env/jdbc/ScottDS")
If you do not want make code changes and you need to use the Tomcat option, then you must modify web.xml
to include the <resource-ref>
entry for the resource, as follows:
<resource-ref> <res-auth>Container</res-auth> <res-ref-name>jdbc/ScottDS</res-ref-name> <res-type>javax.sql.DataSource</res-type> </resource-ref>
In general, OC4J interprets the J2EE specifications more strictly than Tomcat.
You can avoid compilation issues by replacing custom Tomcat JSP tags with standard JSP tags before you deploy a JSP page on OC4J.
Be careful when the words "should" and "may" appears in the specification. Treat these cases with caution because they allow choice, which results in differing behavior.
Here is an example. The JSP specification says:
A scripting language variable of the specified type (if given) or class (if type is not given) is defined with the given id in the current lexical scope of the scripting language. The type attribute should be used to specify a Java type that cannot be instantiated as a JavaBean (i.e. a Java type that is an abstract class, an interface, or a class with no public no-args constructor). If the class attribute is used for a Java type that cannot be instantiated as a JavaBean, the container may consider the page invalid, and is recommended to (but not required to) produce a fatal translation error at translation time, or a java.lang.Instantiation-Exception at request time. |
In this case, OC4J implements the recommendation that the type
attribute should be used instead of the class
attribute when the JavaBean does not have a zero-args
constructor. Tomcat does not insist on the type
attribute but will accept the class
attribute as well. This difference results in the following problem when migrating the application from Tomcat to OC4J:
If you use the type
attribute in your index.jsp
and the JavaBean (my.MyClass
) does not have a public no-args
constructor, then your page works properly both in Tomcat and in OC4J, which is the desirable behavior.
The following example shows this preferred usage:
<jsp:useBean id="codeDesc" scope="session" type="my.MyClass"/>
If, on the other hand, you use the class="my.MyClass"
attribute in this situation, Tomcat may accept this usage and behave correctly. But OC4J will throw a JSPCompilationException
because OC4J uses the more strict interpretation of the specification.
The following example shows the less-strict usage:
<jsp:useBean id="codeDesc" scope="session" class="my.MyClass"/>
This section provides an overview of how clustering in OC4J and Tomcat relate to one another. The following topics are discussed:
Note: The commentary in this section is based on the behavior of Tomcat 5. |
In OC4J, clustering is defined on an application-by-application basis when it is deployed.
For information about clustering in OC4J, including how to configure, see Chapter 9 "Application Clustering in OC4J" of the Oracle Containers for J2EE Configuration and Administration Guide.
For information about load balancing, see Appendix D of the Oracle® HTTP Server Administrator's Guide.
In Tomcat, clustering is configured using the <cluster> element and its subelements in the server.xml file. Clustering is enabled on a container basis.
In OC4J, clustering is defined on an application-by-application basis using the <cluster> element in the orion-application.xml file of a deployed application.
This enables applications with and without clustering enabled to co-exist within the same OC4J instance. Clustering in OC4J is configured using the orion-application.xml file of the application in question. To enable container-level clustering, enable clustering for the default application and all deployed applications will inherit this setting. Also, since the clustering is configured on a per-application basis in OC4J, different applications can be configured to enable clustering, using different protocols and different options.
Tomcat uses both IP multicast and IP sockets to facilitate clustering. In terms of terminology, Tomcat has a single in-memory replication option, where it combines the two network models.
IP multicast is used to perform group membership operations - such as when Tomcat instances are discovering and checking the availability of one another.
IP sockets are used to perform the actual replication of the session state from one Tomcat instance to another Tomcat instance. Presumably this is for the in-memory state persistence mechanism.
OC4J differs in its use and terminology for in-memory session-state replication. OC4J has two different ways to replicate session state in-memory - it can use either IP multicast OR IP sockets. In either case, the Group membership activities occur using the same network model.
IP Multicast
If you configure OC4J to use IP Multicast as the replication protocol, then OC4J uses IP Multicast as the medium to participate in the Group membership protocol as well as for distributing session state to the other members of the Group. The multicast network address is defaulted to a known value. It can be configured as desired using the <multicast> subelement of the <cluster> element. In OC4J, the multicast replication protocol has the added value of guaranteed delivery - so, even though the actual network model used has no reliability guarantees, the way in which is it used by OC4J guarantees that all the packets are delivered and no loss of session state will occur.
IP Sockets
If you configure OC4J to use Peer-Peer as the replication protocol, then OC4J uses IP sockets as the medium to participate in the Group membership protocol as well as for distributing session state to its selected peers. In the case of OC4J used on its own (standalone), then the list of peers must be statically defined in a configuration file. The TCP socket address defaults to a well-known value. It can be configured using the peer subelement of the cluster protocol, tag.
In the case of OC4J used in the Oracle Application Server environment (clustered), the initial list of peers is provided by the OPMN server. OPMN also allocates the port numbers used by the Peer replication protocol so that there are no port conflicts on a server where multiple OC4J instances are started.
Tomcat supports the following mechanisms to handle the distribution of session state to other Tomcat instances:
In-memory
Database
File-based
OC4J supports the following session persistence mechanisms:
In-memory
Database
There is potential confusion here because OC4J supports two methods of in-memory-based replication (multicast and peer) whereas Tomcat uses a combination of both to support in-memory replication.
OC4J does not support a file-based state replication protocol.
OC4J uses the term "replication protocol" instead of "state persistence".
In Tomcat, the "state persistence" mechanism is defined by specifying the name of the class used to implement the persistence mechanism.
In OC4J, the analogous concept, "replication protocol", is configured as a value in the orion-application.xml
file using the <protocol>
tag and specifying one of the <multicast>
, <peer>
or <database>
subtags to indicate which protocol should be used.
The database replication protocol requires the JNDI location of a Data Source, which points to the database instance in which the state replicas will be stored.
In Tomcat, the type of state replicated can be configured to be either the full session or just the change set. This is configured by specifying the class that is used to perform the replication task.
OC4J supports the same concept of sending either the full session or just the deltas. This is configurable using the <replication-policy>
element and the scope
attribute. The options are modifiedAttributes
or allAttributes
.
In Tomcat, the transmission of the state replications can be configured to be synchronous, asynchronous, or pooled.
OC4J by default uses an asynchronous replication model for replication transmissions. This can be changed to a synchronous model using the synchronous-replication option, whereupon the OC4J instance sending the replica will wait for an acknowledgment from the receiving OC4J before proceeding.
OC4J and Tomcat share the same application design requirements for applications that will run in a clustered environment.
Tomcat provides a built-in HTTP server. However, it is possible to scale up using a generic Apache HTTP Server with mod_proxy
or mod_rewrite
or the AJP-based mod_jk
connector to route between multiple instances of Tomcat.
OC4J also provides a built-in HTTP server. However, to scale up and benefit from the automatic load balancing capabilities it provides, Oracle recommends using the Oracle HTTP server. Using OC4J HTTP requires a third-party load balancing component.
In an Oracle Application Server environment, the Oracle HTTP Server is used to route requests to applications running on OC4J instances. The Oracle HTTP Server is configured to discover the OC4J instances running in the same Cluster Topology. As applications are deployed to the OC4J instances, Oracle HTTP Server automatically receives updates about the new deployment and automatically adds the application context root to its list of routable URLs.
Oracle HTTP Server provides automatic failover for clustered applications with sticky session support so that session-based requests are always routed to the same OC4J instance until a failover occurs.
Oracle HTTP Server uses a round-robin load balancing algorithm by default. The load balancing model can be changed to several different options.
For further discussion, see Appendix D, "Load Balancing Using mod_oc4j" in the Oracle HTTP Server Administrator's Guide.