Skip Headers

Oracle9iAS Containers for J2EE User's Guide
Release 2 (9.0.2)

Part Number A95880-01
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Go to previous page Go to next page

5
Servlet Primer

This chapter introduces Java servlets and the Oracle9iAS Containers for J2EE (OC4J). Read this chapter if you are not familiar with servlets or if you want to refresh your knowledge of servlets. For more extensive information about servlets, see the Oracle9iAS Containers for J2EE Servlet Developer's Guide.

This chapter covers the following topics:

What Is a Servlet?

A servlet is a Java program that runs in a J2EE application server, such as OC4J, and receives and responds to HTTP requests from clients. Think of a servlet as the server-side counterpart to a Java applet. A servlet is one of the four application component types of a J2EE application. Others are applets and application client programs on the client side, and EJBs on the server side. Servlets are managed by the OC4J servlet container; EJBs are managed by the OC4J EJB container. These containers, together with the JavaServer Pages container, form the core of OC4J.

JavaServer Pages (JSP) is another server-side component type. JSP pages also involve the servlet container, because the JSP container itself is a servlet and is therefore executed by the servlet container. The JSP container translates JSP pages into page implementation classes, which are executed by the JSP container but function similarly to servlets. See Chapter 6, "JSP Primer" and the Oracle9iAS Containers for J2EE Support for JavaServer Pages Reference for more information about JSP pages.

Most servlets generate HTML text, which is then sent back to the client for display by the Web browser, or sent on to other components in the application. Servlets can also generate XML, to encapsulate data and send the data to the client or to other components.

The Servlet Container

A servlet differs from a Java application client in that is has no static main() method. Therefore, a servlet must execute under the control of a servlet container, because it is the container that calls the methods of the servlet and provides services that the servlet might need when executing.

The servlet itself overrides the access methods (implemented in the GenericServlet or the HttpServlet classes) that it needs to process the request and return the response. For example, most servlets override the doGet() and doPost() methods (or both) of the HttpServlet to process HTTP GET and POST requests.

The servlet container provides the servlet easy access to properties of the HTTP request, such as its headers and parameters. In addition, a servlet can use other Java APIs such as JDBC to access a database, RMI to call remote objects, or JMS to perform asynchronous messaging, plus many other Java and J2EE services.

Servlet Performance

Because servlets are written in the Java programming language, they are supported on any platform that has a Java virtual machine and a Web server that supports servlets. You can use servlets on different platforms without recompiling and you can package servlets together with associated files such as graphics, sounds, and other data to make a complete Web application. This greatly simplifies application development.

It also means that your servlet-based application that was developed to run on another application server can be ported to OC4J with little effort. If your application was developed for an application server that complies with J2EE, then the porting effort is minimal.

Servlets outperform earlier ways of generating dynamic HTML, such as server-side includes or CGI scripts. Once a servlet is loaded into memory, it can run on a single lightweight thread; CGI scripts must be loaded in a different process for every request.

A servlet, along with optional servlet filters, relates to the servlet container and a client, such as a Web browser. When the Web listener is the Oracle HTTP Server, then the connection to the OC4J servlet container is through the mod_oc4j module. See the Oracle HTTP Server Administration Guide for details.

Two Servlet Examples

A good way to learn about servlets and how to code them is to view some simple servlet examples. This section displays the code for two servlets and annotates the code with comments. For simplicity, numbered callouts are located beside sections of code and the corresponding descriptions for each number section appears below the code example.

The Hello World Servlet

Here is another "Hello World" demo. But it does serve to show the basic framework you use to write a servlet. This servlet just prints "Hi There!" back to the client.

import java.io.*;                                      // 1. (first comment)
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWorldServlet extends HttpServlet {   // 2.

  public void doGet (HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {             // 3.
    resp.setContentType("text/html");                  // 4.

    ServletOutputStream out = resp.getOutputStream();  // 5.
    out.println("<html>");                             // 6.
    out.println("<head><title>Hello World</title></head>");
    out.println("<body>");
    out.println("<h1>Hi There!</h1>");
    out.println("</body></html>");                     // 7.
  }
}

Comments on HelloWorldServlet

  1. You must import at least these packages for any servlet you write. Other packages are needed for SQL operations or to support Oracle JDBC drivers.

  2. Your servlet class extends the HttpServlet class, which implements the methods that a servlet uses. You override the methods you need for your particular servlet implementation.

  3. The doGet() method here overrides the one in the HttpServlet class, which services HTTP GET requests. Like almost all HttpServlet methods, doGet() takes request and response objects as parameters. In this example, no methods are called on the request object (req), because this example requires no input (that is, request) data.

  4. Call the setContentType() method on the response object to set the response content MIME type in the header. Here, it is text/html, because that is what this servlet generates.

  5. You use the response object (resp) to get a writer that sends the output of the server back to the client. You could also get a PrintWriter from the response object.

  6. The remainder of the code generates the HTML that the client Web browser will print when it gets the response. This is the identical HTML that you would code to write a simple Web page to display "Hi There!" in a heading one (<h1>) format.

  7. Do not forget to close off the page you are generating by closing the body and html tags.

Save this servlet in a file called HelloWorldServlet.java. Compile the servlet, using a Java 1.3.x compliant compiler:

% javac HelloWorldServlet.java

If you would like to try out this servlet in OC4J, just configure a web.xml and archive these in a WAR file. Deploy the WAR file using the Deploy WAR File button on the OC4J Home Page. In the wizard, provide the URL servlet context as /j2ee/hello. Thus, the WAR is deployed into the /j2ee/hello servlet context. Having made sure that OC4J is up and running, you can invoke this servlet and see its output from a Web browser. Just enter the URL:

http://<apache_host>:<port>/j2ee/hello/servlet/HelloWorldServlet

The /servlet part of the URI is an OC4J feature that starts up any servlet indicated, which in this case is the HelloWorldServlet. Alternatively, you could have configured a context for the servlet in the application web.xml. For example, the HelloWorldServlet could be mapped to a URL, such as "world", as follows:

<servlet-mapping>
    <servlet-name>HelloWorldServlet</servlet-name>
    <url-pattern>/world</url-pattern>
</servlet-mapping>

Thus, you would invoke the servlet as follows:

http://<apache_host>:<port>/j2ee/hello/world

The <apache_host> represents the name of the host that the OC4J server is running on. By default in Oracle9iAS, specify port 7777 for access through the Oracle HTTP Server with Oracle9iAS Web Cache enabled.

If your servlet exists within a package (or packages), you would include the packages in the <servlet-name> definition. The following shows the <servlet-name> definition for the HelloWorldServlet that is included in the "my" package. If this servlet is included in a nested group of packages, they are separated by a period.

<servlet-mapping>
    <servlet-name>my.HelloWorldServlet</servlet-name>
    <url-pattern>/world</url-pattern>
</servlet-mapping>

Request and Response Objects

The HttpServlet methods, such as doGet() and doPost(), take two parameters: an HttpServletRequest object and an HttpServletResponse object. The servlet container passes these objects to the servlet and receives the response to pass on to the client, to the next servlet in a filter chain, or to another server object such as an EJB.

The request and response objects support methods that enable you to write efficient servlet code. In the preceding example, you saw that you can get a stream writer object from the response and use it to write statements to the response stream.

The GetEmpInfo Servlet

The HelloWorldServlet example shows a minimal servlet--it really does not do very much. But the power of servlets comes from their ability to retrieve data from a database. A servlet can generate dynamic HTML: the servlet can get information from a database and send it back to the client.

Of course, a servlet can also update a database, based upon information passed to it in the HTTP request.

In the next example, a servlet gets some information from the client (the Web browser) and queries a database to get information based on the request data.

Although there are many ways that a servlet can get information from its client, this example uses a very common method: reading a query string from the HTTP request.


Note:

This example works only if the HR schema has been installed in the Oracle database. This schema is part of the example Common Schemas set.


The HTML Form

The Web browser accesses a form in a page that is served through the OC4J Web listener. First, enter the following text into a file. Next, name the file EmpInfo.html.

<html>

<head>
<title>Query the Employees Table</title>
</head>

<body>
<form method=GET ACTION="/servlet/GetEmpInfo">
The query is<br>
SELECT LAST_NAME, EMPLOYEE_ID FROM EMPLOYEES WHERE LAST NAME LIKE ?.<p>

Enter the WHERE clause ? parameter (use % for wildcards).<br>
Example: 'S%':<br>
<input type=text name="queryVal">
<p>
<input type=submit>
</form>

</body>
</html>

The Servlet

The servlet that the preceding HTML page calls takes the input from a query string. The input is the completion of the WHERE clause in the SELECT statement. The servlet then appends this input to complete the database query. Most of the complexity of this servlet comes from the JDBC code required to connect to the data server and retrieve the query rows. If you are not familiar with JDBC, see the Oracle9i JDBC Developer's Guide and Reference.

Here is the code for the servlet:

import javax.servlet.*;
import javax.servlet.http.*;
import javax.naming.*;                                 //1. (see comments below)
import javax.sql.*;                                                        // 2.
import oracle.jdbc.*;


public class GetEmpInfo extends HttpServlet {

  DataSource ds = null;
  Connection conn = null;

  public void init() throws ServletException {                             // 3.
    try {
      InitialContext ic = new InitialContext();                            // 4.
      ds = (DataSource) ic.lookup("java:comp/env/jdbc/OracleDS");          // 5.
      conn = ds.getConnection();                                           // 6.
    }
    catch (SQLException se) {                                              // 7.
      throw new ServletException(se);
    }
    catch (NamingException ne) {                                           // 8.
      throw new ServletException(ne);
    }
  }

  public void doGet (HttpServletRequest req, HttpServletResponse resp)
                     throws ServletException, IOException {

    String queryVal = req.getParameter("queryVal");                        // 9.
    String query =                                                         //10.
      "select last_name, employee_id from employees " +
      "where last_name like " + queryVal;

    resp.setContentType("text/html");

    PrintWriter out = resp.getWriter();
    out.println("<html>");
    out.println("<head><title>GetEmpInfo</title></head>");
    out.println("<body>");

    try {
      Statement stmt = conn.createStatement();                             //11.
      ResultSet rs = stmt.executeQuery(query);                             //12.

      for (int count = 0; ; count++ ) {                                    //13.
        if (rs.next()) {
          out.println(rs.getString(1) +  "&nbsp;&nbsp;&nbsp;" +
             rs.getInt(2) + "<br>");
        }
        else {
          out.println("<h3>" + count + " rows retrieved</h3>");
          break;
        }
      }
      rs.close();                                                          //14.
      stmt.close();
}
    catch (SQLException se) {                                              //15.
      se.printStackTrace(out);
    }

    out.println("</body></html>");
  }

  public void destroy() {                                                  //16.
    try {
      conn.close();
    }
    catch (SWLException ignored) {
    }
  }    

}

Comments on GetEmpInfo

  1. Import these packages to support the JNDI API.

  2. These packages support SQL and the Oracle JDBC drivers.

  3. This example overrides the HttpServlet init() method to look up a data source and get a database connection using the data source.

  4. Get an initial JNDI context. For more information about using JNDI with the OC4J server, see the Oracle9iAS Containers for J2EE Services Guide.

  5. Look up a data source with the JNDI name OracleDS. This assumes it has been configured in Enterprise Manager using the following element definitions:

    <data-source
       class="com.evermind.sql.DriverManagerDataSource"
       name="OracleDS"
       location="jdbc/OracleCoreDS"
       xa-location="jdbc/xa/OracleXADS"
       ejb-location="jdbc/OracleDS"
       connection-driver="oracle.jdbc.driver.OracleDriver"
       username="scott"
       password="tiger"
       url="jdbc:oracle:thin:@localhost:5521:oracle"
       inactivity-timeout="30" 
    />
    
    

    You can configure this data source either using the Advanced Properties or the Data Source links in the Administration section of either the OC4J Home Page or the application page.

    In Oracle9iAS 9.0.2, it is advisable to use only the ejb-location JNDI name in the JNDI lookup for a data source. See the Oracle9iAS Containers for J2EE Services Guide for more information about data sources.

  6. Use the data source to get a connection to the database.

  7. These look up and SQL operations are performed in a try...catch sequence, to catch JNDI naming or SQL errors.

  8. Catch a JNDI naming exception, and throw it as a ServletException.

  9. Get the parameter passed in the request header from the HTML form.

  10. Construct a SQL query using the parameter in the WHERE clause.

  11. Open a statement object.

  12. Open a JDBC ResultSet object. This causes the statement to execute the query, and returns a result set, which may be empty, or else contains all the rows that satisfy the query.

  13. Loop through the rows of the result set. The for loop exits after the last row retrieved, at the break statement. Print the results, using the getString() and getInt() methods of the result set instance. See the Oracle9i JDBC Developer's Guide and Reference for more information about the result set's getXXX() methods.

  14. Close the result set, the statement, and the connection.

  15. Catch any SQL exceptions, such as connection errors or table-not-found errors.

  16. The destroy() method closes the database connection.

How GetEmpInfo Runs

When your browser invokes EmpInfo.html, you should see a browser window that looks something like this:

Text description of gsimg1.gif follows.

Text description of the illustration gsimg1.gif

Entering 'S%' in the form, and pressing Submit Query calls the GetEmpInfo servlet, and the results look like this:

Text description of servpri2.gif follows

Text description of the illustration servpri2.gif

Better Output

The output from the GetEmpInfo servlet is not very well formatted. But since the servlet generates HTML, there's no reason why you can't make the output a bit prettier. Just add an HTML table statement before the Java for statement, and replace the out.println() code in the for with some out.println() calls that generate HTML table rows. Here is one way to do this:

out.println("<table border=1 width=50%>");
out.println("<tr><th width=75%>Last Name</th><th width=25%>Employee " +
ID</th></tr>"); for (int count = 0; ; count++ ) { if (rs.next()) { out.println ("<tr><td>" + rs.getString(1) + "</td><td>" + rs.getInt(2) + "</td></tr>"); } else { out.println("</table><h3>" + count + " rows retrieved.</h3>"); break; } }

This simple modification generates better-looking output in a browser window, as shown here:

Text description of servpri3.gif follows

Text description of the illustration servpri3.gif

Session Tracking

Servlets, and their JSP relatives, have come into widespread use for applications like shopping carts. For example, clients search for an item on a web site, then go to a page that describes the item more fully, and then might decide to buy the item, putting in their shopping basket. Finally, they check out, giving credit card details and a shipping address. To implement such a site, the server must be able to track the identity of clients as they migrate from page to page of the Web site.

Several mechanisms have been developed to do this, but the most widely-used is undoubtedly the cookie. A cookie is just a small piece of information, that includes the server session ID, that the server sends back to the client. The client (the Web browser, for example) then returns the cookie to the server on each new HTTP request. So a cookie provides a means to let a client synchronize with a server session to maintain stateful information while still using the stateless HTTP protocol.

In addition to cookies, for client to server communication, the OC4J servlet container supports the HttpSession object, as described in the servlet specifications. An HTTP session object is scoped over the Web application only. This means that you cannot use session objects to share data between applications, or between different clients. To do these things, you should persist the data in a database or some other location.

Session Tracking Example

The SessionServlet code below implements a servlet that establishes an HttpSession object, and uses that object to maintain a counter that records the number of times the session has been accessed. The servlet also prints a lot of information obtained both from the request and the session objects, to illustrate some of the capabilities of the HttpServletRequest and the HttpSession classes.

import java.io.*;
import java.util.Enumeration;

import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Date;

public class SessionServlet extends HttpServlet { 

  public void doGet (HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {

    HttpSession session = req.getSession(true);                     // 1.

    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    out.println("<head><title> " + "SessionServlet Output " +
                "</title></head><body>");
    out.println("<h1> SessionServlet Output </h1>");
    Integer ival = 
      (Integer) session.getAttribute("sessionservlet.counter");    // 2.
    if (ival==null) {
      ival = new Integer(1);
    }
    else {
      ival = new Integer(ival.intValue() + 1);
    }

    session.setAttribute("sessionservlet.counter", ival);           // 3.

    out.println(" You have hit this page <b>" + 
                ival + "</b> times.<p>");                           // 4.
    out.println("Click <a href=" + 
                res.encodeURL(HttpUtils.getRequestURL(req).toString()) + 
                ">here</a>");                                       // 5.
    out.println(" to ensure that session tracking is working even " +
                "if cookies aren't supported.<br>");
    out.println("Note that by default URL rewriting is not enabled" +
                " due to its large overhead.");

    out.println("<h3>Request and Session Data</h3>");               // 6.
    out.println("Session ID in Request: " +
                req.getRequestedSessionId());
    out.println("<br>Session ID in Request is from a Cookie: " +
                req.isRequestedSessionIdFromCookie());
    out.println("<br>Session ID in Request is from the URL: " +
                req.isRequestedSessionIdFromURL());
    out.println("<br>Valid Session ID: " +
                req.isRequestedSessionIdValid());

    out.println("<h3>Session Data</h3>");                           // 7.
    out.println("New Session: " + session.isNew());
    out.println("<br> Session ID: " + session.getId());
    out.println("<br> Creation Time: " + new Date(session.getCreationTime()));
    out.println("<br>Last Accessed Time: " +
                new Date(session.getLastAccessedTime()));

    out.println("</body>");
    out.close();
  }

  public String getServletInfo() {                                  //8.
    return "A simple session servlet";
  }
}

SessionServlet Comments

  1. This line gets the session object. The getSession(true) method creates a new session if one hasn't already been created.

  2. The number of hits is retrieved from the session object. Note that this counter must be an object--it cannot be a primitive int value. The name sessionservlet.counter is an arbitrary key name for the attribute that is assigned by this servlet.

  3. Set the new, incremented hit count.

  4. Print the result.

  5. The place to go to have the servlet do URL rewriting.

  6. Get information from the request headers, and print it.

  7. Get and print some data about the session.

  8. getServletInfo() is a method that the container can call when it needs to supply information about what the servlet does. A servlet can override this GenericServlet method to provide meaningful information for the container.

When you invoke the SessionServlet from a web browser, you will see something like the following:

Text description of servpri4.gif follows

Text description of the illustration servpri4.gif

Servlet Filters

You can use filters to process the requests that servlets receive, process the responses, or do both. For example, an application might need to provide special logging of certain kinds of requests for one or more servlets, or might need to encrypt the output (response objects) of a whole class of servlets.

Unlike servlets, filters do not generally create a response. You use filters to modify the requests or responses, or to perform some other action based on the requests or responses. These actions could include:

The javax.servlet.Filter interface was added to the Servlet 2.3 specification to allow an application to perform these kinds of tasks. Several filters can be chained together to perform a series of tasks on requests or responses.

A Logging Filter

This example implements a simple filter that logs the amount of time (in milliseconds) required to process a servlet request. In this example, the filter is deployed to the default Web application, and a time log of each servlet or JSP invocation is written to the global-application.log file in the j2ee/home/log directory. To see the results of the filter, just examine this file in a separate window as servlet requests are being processed. On a UNIX-type system, you can use the command:

% tail -f j2ee/home/log/global-application.log

LogFilter Code

The log filter implementation is commented, just like the previous examples.

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;


public
class LogFilter implements Filter {                                     //1.
  FilterConfig config;
  ServletContext context;

  public
  void init(FilterConfig config) {                                      //2.
    this.config = config;
    context = config.getServletContext();                               //3.
  }

  public
    void destroy() {                                                        //4.
    context.log("Log Filter terminating.");
  }

  public                                                                    //5.
  void doFilter(ServletRequest req,
                ServletResponse res,
                FilterChain chain) throws IOException, ServletException {
    long bef = System.currentTimeMillis();
    chain.doFilter(req, res);                                       //6.
    long aft = System.currentTimeMillis();
    HttpServletRequest nreq = (HttpServletRequest) req;
    context.log("Request from " + nreq.getRequestURI() + ": " + (aft-bef));
  }
}

Comments on the LogFilter Example

  1. This filter implements the three methods specified in the javax.servlet.Filter interface: doFilter(), init(), and destroy().

  2. A filter saves its configuration parameters when the container calls the init() method at startup.

  3. This example gets a ServletContext object from the configuration, to use writing the to the log file.

  4. The destroy() method must be implemented. The container calls destroy() before terminating the filter, so put any clean-up code, such as closing file handles, here.

  5. doFilter() takes request and response objects as parameters, and a FilterChain object that lets the filter pass on the request and response objects (perhaps wrapped) to the next filter in the chain, or at the end of the chain, to the servlet or back to the container. The container calls filters before and after processing the target servlet.

  6. The servlet's context is obtained from the filter config object.

This filter is solitary (there is no chain), so the FilterChain parameter is not used in the doFilter() invocation.

After the servlet has finished, the filter computes the time required to process the servlet (in milliseconds), and writes the value out to the log file, along with the URI that invoked the servlet for which the filter applies.

Configuring Filters

Filters are configured in the deployment descriptor of a web application. Create a <filter> tag in the web.xml file, indicating a name for the filter and the name of the class that implements the filter. The filter in this example is intended to monitor all servlet requests for the application, so there must be a mapping to indicate that and to have it filter all requests: '/*'.

Therefore, to deploy this filter in the default Web application, enter the following lines in web.xml:

<web-app>
  ...
  <filter>
    <filter-name>log</filter-name>
    <filter-class>LogFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>log</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  ...
</web-app>

Example Output

This sample shows the output that this filter generates. The PrimeSearcher servlet was initialized by the container, and called a few times, then the server was shut down, but first the container called the filter destroy() method. The lines that begin "Request from..." are the filter output.


8/1/01 8:50 AM defaultWebApp: 1.0.2.2 Stopped
8/1/01 8:50 AM defaultWebApp: PrimeSearcher: init
8/1/01 8:50 AM defaultWebApp: 1.0.2.2 Started
8/1/01 8:50 AM defaultWebApp: PrimeSearcher: init
8/1/01 8:50 AM defaultWebApp: Request from /servlet/PrimeSearcher: 1
8/1/01 10:10 AM defaultWebApp: Request from /servlet/PrimeSearcher: 1
8/2/01 5:56 AM defaultWebApp: Request from /servlet/PrimeSearcher: 2
8/2/01 2:12 PM defaultWebApp: Log Filter done.
8/2/01 2:12 PM defaultWebApp: 1.0.2.2 Stopped
8/2/01 2:12 PM Stopped (Shutdown executed by admin from 130.35.172.234 
(dlsun1497))

For more information about filters, filter chains, and filter deployment, see the Oracle9iAS Containers for J2EE Servlet Developer's Guide.

Learning More About Servlets

Your first step in learning more about servlets should be to read the Oracle9iAS Containers for J2EE Servlet Developer's Guide. This guide tells you what you need to know to develop servlets and web-tier applications in the OC4J environment.

To get complete documentation on the servlet APIs, visit the Sun Microsystems Web site at:

http://java.sun.com/j2ee/docs.html

You can also find a great deal of tutorial information on servlets as well as other aspects of J2EE application development at this site.

Finally, there are several trade press books that will teach you how to develop servlets, and deploy them in J2EE-compatible applications. In particular, the books from O'Reilly & Associates (http://www.oreilly.com) and Wrox (http://www.wrox.com) are very useful.


Go to previous page Go to next page
Oracle
Copyright © 2002 Oracle Corporation.

All Rights Reserved.
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index