Corporate Info | News | Solutions | Products | Partners | Services | Events | Download | How To Buy
Introduction to BEA WebLogic Server 5.1: Previous topic | Next topic | Contents

Servlets

A servlet is a server-side Java class that can be invoked and executed, usually on behalf of a client. Do not confuse servlets with applets; a servlet does its work on the server, but an applet does its work on the client. Several WebLogic Server services are implemented using servlets.

A servlet has input and output objects that represent a request and response, respectively. When a client requests a servlet, WebLogic Server loads the servlet, calls its init() method, and passes the request and response objects to a service method.

WebLogic Server supports the javax.servlet.GenericServlet and javax.servlet.http.HttpServlet interfaces. An HttpServlet extends the GenericServlet interface, adding support for the HTTP protocol.

The HTTP protocol concerns client requests and server responses. Clients are usually web browsers and servers are usually web servers, including servlet engines like WebLogic Server. Other web servers can be configured to redirect their servlet requests to WebLogic Server.

HTTP servlets (and JSP, which is based on HTTP servlets) are the components that represent the server-side presentation logic in e-commerce applications. This section concentrates on HTTP servlets.

HTTP servlets extend the javax.servlet.http.HttpServlet class, which allows them to run in any compliant servlet engine. The work performed by HTTP servlets can be compared to that of CGI scripts, but HTTP servlets are easier to write, faster than running an external script, and they have access to other WebLogic Server services.

The javax.servlet.http package provides the Java interfaces that allow your code to participate in the HTTP protocol. An HTTP servlet is called with an HttpServletRequest object, which contains data received by the server from the client, and an HttpServletResponse object, where the servlet can write data to return to the client.

A servlet can extract standard headers from the client request. When clients enter data in HTML forms, the data is transferred to the servlet as a set of parameters in the HTTP stream. The servlet can read the parameters by calling the HttpServletRequest object's getParameterValues() method.

To respond to an HTTP request, a servlet uses the HttpServletResponse object. The methods on this object let the servlet take such actions as setting headers in the HTTP response, adding a cookie to a response, or returning an error. The HttpServletResponse also provides a PrintWriter to the servlet, which the servlet uses to write HTML. Since the HTML is generated for each request to the servlet, it can be highly dynamic.

Many web applications require a coordinated series of requests and responses so they can get input from the client and return the correct response. To link HTTP requests and retain data over a series of calls, many web applications make use of URL parameters and browser cookies. With URL parameters, data is appended to the URL a client uses to make a request. Cookies allow a server to store an object in the client's web browser for later access, if the browser user permits it.

The javax.servlet.http.HttpSession interface provides a convenient method for managing a series of HTTP events in a servlet. This interface allows a servlet to create a session object in the servlet and store data in it. The session remains available to the servlet when the same client returns. WebLogic Server ties the session data it maintains to a particular browser session by setting a cookie in the browser. If the user has disallowed cookies, the servlet can still use sessions by coding the session ID in the URL. See Using WebLogic HTTP Servlets for information on URL rewriting.

WebLogic Server can be configured as a fully functional web server that delivers any arbitrary MIME type to HTTP clients. For more information on configuring WebLogic Server HTTP services, see Setting up WebLogic as an HTTP Server.

Creating an HTTP Servlet

A servlet class handles HTTP requests by overriding methods in javax.servlet.http.HttpServlet. A client can make an HTTP request to a servlet, specifying one of these service methods: GET, POST, PUT, DELETE, OPTIONS, or TRACE. The javax.servlet.http.HttpServlet class provides a default empty implementation for each of these methods. To create a servlet, you just override the methods you want to implement.

For example, when a user enters the servlet's URL into a browser, the browser sends a GET request to the servlet. The servlet engine sends the request to the servlet's service() method, which routes the GET request to the doGet() method. The default doGet() implementation returns an error 400, BAD_REQUEST, which is the correct response for a servlet that does not handle a GET request.

See the Javadocs for javax.servlet.HttpServlet on the Sun web site for a description of each of the service methods and their default implementations.

In HTTP servlets, it is common to override the doGet() and doPost() methods, less common to override the other methods. With generic servlets, all requests are passed to the service() method.

A servlet can override the init() method, which is called whenever the servlet is loaded or reloaded. It can perform any initialization work that needs to be done before it responds to client requests, but it must first call the init() method in the parent class. The init() method is commonly used to retrieve configuration parameters for the servlet which, in WebLogic Server, are set in the weblogic.properties file. You can override the destroy() method to perform any clean up required when the servlet exits.

The HTTP service methods, such as service(), doGet() and doPost(), are each called with an HttpServletRequest and an HttpServletResponse. The servlet gets information about the client's request from the HttpServletRequest and writes the response into the HttpServletResponse.

SqlServlet example

The SqlServlet.java example is a servlet that gets an SQL statement from a browser form, executes the statement using a connection from a WebLogic Server connection pool, and constructs an HTML page containing the query results. Here is an example of the output from this servlet:

The SqlServlet example demonstrates the following:

- An init() method that retrieves an initArg that is set in the weblogic.properties file. The argument specifies the DataSource the servlet will use.

- A doGet() method that sends an HTML form to the browser.

- A doPost() method that retrieves the SQL statement entered in the form and calls some additional methods to process the query and format the results.

init() method

The init() method of a servlet does whatever initialization work is required when WebLogic Server loads the servlet. The default init() method does all of the initial work that WebLogic Server requires, so you do not need to override it unless you have special initialization requirements. If you do override init(), first call super.init() so that the default initialization actions are done first.

The SqlServlet init() method gets the name of the DataSource, which provides JNDI access to the JDBC connection pool it is to use. Setting the DataSource name as an argument makes it easy to redeploy the servlet with a different database.

Here is the beginning of the SqlServlet.java example, including the init() method:

Listing 4-1 SqlServlet.java

package examples.intro;
/*
* @author Copyright (c) 1999-2000. BEA Systems, Inc.
* All rights reserved.
*/
import java.io.*;
import java.sql.*;
import java.util.Hashtable;
import javax.naming.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.sql.DataSource;
import weblogic.common.*;
/**
* This example servlet takes an SQL query from a form and
* executes it using a connection borrowed from a connection
* pool in WebLogic Server.
*
* The name of the connection pool is specified in an initArg
* for the servlet in the <tt>weblogic.properties</tt> file.
*/
public class SqlServlet extends HttpServlet
{
String connPool;
/**
* The init method performs any tasks that need to be done when a
* servlet first starts up. For this servlet, there is one task,
* which is to look up the name of the DataSource to use for SQL
* queries. The DataSource is set in the servlet's initArgs
* property in the <tt>weblogic.properties</tt> file.
*/
public void init(ServletConfig config)
throws ServletException
{
super.init(config);
connPool = getInitParameter("dataSource");
if (connPool == null) {
System.err.println("This servlet requires a " +
" dataSource initArg." );
}
}

SqlServlet imports javax.servlet.* and javax.servlet.http.* and extends HttpServlet. The java.sql and weblogic.common packages are imported because this servlet uses JDBC and WebLogic JDBC connection pools. The java.io package is imported for the I/O methods of the PrintWriter, which is a stream object.

Our purpose in overriding the init() method is to retrieve the name of the connection pool. In the weblogic.properties file, this servlet is registered with properties similar to these:

    weblogic.http.register.SqlServlet=\
          examples.intro.SqlServlet

    weblogic.http.initArgs.SqlServlet=\
          dataSource=demoDataSource

The first property registers the servlet with the name SqlServlet. The second passes a single argument, dataSource, which is set to the name of the DataSource for the a JDBC connection pool configured in the WebLogic Server.

The init() method retrieves the argument by calling getInitParameter("dataSource").

doGet() method

The URL for a servlet in WebLogic Server is the URL of the WebLogic Server followed by the registered name of the servlet. The URL for the SqlServlet servlet is:

    http://host:port/SqlServlet

where host is the name of the computer running WebLogic Server and port is the port number where WebLogic Server is listening for connections. If a user requests this URL in a browser, WebLogic Server passes the request to the doGet() method of the SqlServlet servlet.

doGet(), and the putForm() method it calls, construct an HTML form to get an SQL query from the client:

Listing 4-2 SqlServlet.java doGet() method

      /**
       * The doGet() method is called when a Servlet is first
       * requested. This implement prints a query form to get
       * the query from the browser. Once a client has this
       * form, all of their subsequent calls to this servlet
       * should be through the doPost() method.
       */
      public void doGet(HttpServletRequest req,
                        HttpServletResponse res)
        throws ServletException, IOException
      {
        res.setContentType("text/html");
        PrintWriter pw = res.getWriter();
        pw.println("<html><head><title>SQL Query Servlet");
        pw.println("</title></head>");
        pw.println("<body bgcolor=#ffffff><font face=\"Helvetica\">");
        pw.println("<h1><font color=\"#FF0000\">");
        pw.println("SQL Query Servlet</font></h1>");
        pw.println("<hr><p>");
        putForm(req, pw, "");
        pw.println("</body></html>");
        pw.close();
      }

      /**
        * putForm() writes an HTML form to the response to collect
       * the sqlStatement parameter.
       */
      public void putForm(HttpServletRequest req,
                          PrintWriter pw, String query)
        throws IOException
      {

        pw.println("<form action=\"" +
                   req.getRequestURI() +
                   "\" method=post>");
        pw.println("Enter an SQL query:");
        pw.println("<center><p>");
        pw.println("<textarea name=\"sqlStatement\" " +
                   "rows=\"8\" cols=\"64\" wrap=hard>" +
                   query + "</textarea>");
        pw.println("<p><input type=\"submit\" " +
                   "name=\"sendSql\" value=\"Send SQL\">");
        pw.println("</center>");
        pw.println("</form>");
      }

doGet() sets the MIME type of the page it is generating to "text/html", and then gets a PrintWriter from the HttpServletResponse. Then it writes out standard HTML through the PrintWriter. The HTML code for the form is in a separate method so that it can be reused by the doPost() method.

doGet() and putForm() have no dynamic HTML content. They could be implemented as static HTML pages. The <form> tag addresses the contents of the form to the SqlServlet servlet. The action attribute gives the URL of the servlet, and the method attribute specifies the HTTP POST method. The URL in the example code is relative to the servlet. If you want to send the data to another WebLogic Server or to another servlet, you can give the complete URL in the action attribute.

doPost() method

doPost() is called when a client clicks the "Send SQL" button on the form. The name attributes in the form element tags become the parameter names used to transport the form input in the HTTP request. In a doPost() method, parameters are retrieved by calling getParameterValues() on the HttpServletRequest. getParameterValues() returns an array of Strings, or null. The SqlServlet servlet is only interested in the first element of the array returned by the sqlStatement parameter, which contains the SQL statement the user entered:

Listing 4-3 SqlServlet.java doPost() method

      /**
       * This method handles a POST request from a client. It
       * gets the SqlStatement parameter from the HttpServletRequest
       * object, executes the SQL using a connection from the connection
       * pool, and generates an HTML page with the query results.
       */
      public void doPost(HttpServletRequest req,
                         HttpServletResponse res)
        throws ServletException, IOException
      {
        // first, set the "content type" header of the response
        res.setContentType("text/html");

        //Get the response's PrintWriter to return text to the client.
        PrintWriter pw = res.getWriter();
        pw.println("<html><head><title>" +
                   "SQL Query Results</title></head>");
        pw.println("<body bgcolor=#ffffff><font face=\"Helvetica\">");
        pw.println("<h1><font color=\"#FF0000\">");
        pw.println("SQL Query Results</font></h1>");
        pw.println("<hr><p>");

        try {
          String theQuery = req.getParameterValues("sqlStatement")[0];
          pw.println("<p><i>Query:</i> " + theQuery + "<p>");

          doQuery(theQuery, pw); // all the JDBC is in this method
          pw.println("<p><hr>");
          putForm(req, pw, theQuery); // ask for another SQL statement
          pw.println("<p><hr></body></html>");
        }
        catch (Exception e) {
          pw.println("<p><hr>A problem occurred:");
          pw.println("<pre>" + e.getMessage() + "</pre>");
        }
        finally {
          pw.close();
        }
      }

doPost() writes the HTML for the response, but it calls doQuery() to handle all of the JDBC and write out the HTML-formatted query results, and putForm() to add the query form following the results.

Support methods

doPost() calls doQuery() to handle all of the JDBC processing for the query. The query could be any text-doQuery() just sends it on to the JDBC driver. The result of the query could be a syntax error or some other exception, a row update count, or a set of rows. Some SQL commands, such as stored procedures, could return multiple result sets. The try block in doQuery() shows how to process an arbitrary ResultSet.

Listing 4-4 SqlServlet.java doQuery() method

    /**
       * This method executes the SQL query.
       */
      public void doQuery(String theQuery, PrintWriter pw)
        throws Exception
      {
        // set up the JDBC connection
        Context ctx = null;
        Hashtable ht = new Hashtable();
        Connection conn = null;
        ht.put(Context.INITIAL_CONTEXT_FACTORY,
               "weblogic.jndi.WLInitialContextFactory");
        try {
          ctx = new InitialContext(ht);
          javax.sql.DataSource ds =
            (javax.sql.DataSource) ctx.lookup("demoDataSource");
          conn = ds.getConnection();
          conn.setAutoCommit(true);
          Statement s = conn.createStatement();
          ResultSet rs = null;
          s.execute(theQuery);

          // loop through the result sets
          while (true) {
            rs = s.getResultSet();
            int rowcount = s.getUpdateCount();
            if (rowcount != -1) {
              pw.println("Update count = " + rowcount);
            }
            if (rs == null && rowcount == -1)
              break;
            if (rs != null)
              // call another method to construct a table
              // from the ResultSet
              printResults(pw, rs);
            s.getMoreResults();
          }
        }
        catch (NamingException ne) {
          pw.print("<p><hr>JNDI Exception: ");
          pw.print("<pre>" + ne.getMessage() + "</pre>");
        }
        catch (SQLException se) {
              pw.print("<p><hr>SQL Exception: ");
              pw.println("<pre>" + se.getMessage() + "</pre>");
        }
        finally {
          try { conn.close(); } catch (Exception e) {};
          try { ctx.close(); } catch (Exception e) {};
        }
      }

The printResults() method outputs a ResultSet in a formatted HTML table. It gets the metadata from the ResultSet, which provides access to the column names. It loops through the result rows, adding an HTML row for each.

Listing 4-5 SqlServlet.java printResults() method

      /** This method is called from doPost to format the
       * query results as an HTML table.
       */
      static void printResults(PrintWriter pw, ResultSet rs)
        throws IOException, SQLException
      {
        int columns = 0;
        ResultSetMetaData md = null;

        pw.println("<table border=1 bgcolor=\"#FFFFCC\" " +
                   "width=\"100%\">");
        md = rs.getMetaData();
        columns = md.getColumnCount();
        pw.println("<tr>");
        for (int i = 0 ; i < columns; i++ ) {
          pw.print("  <th align=left>");
          String label = md.getColumnLabel(i+1);
          pw.print( label == null?"<br>" : label ) ;
          pw.println("</th>");
        }
        pw.println("</tr>");
        while (rs.next()) {
          pw.println("<tr>");
          for (int i = 0; i < columns; i++) {
            Object val = rs.getObject(i+1);
            if (val == null)
              pw.println("  <td><br></td>");
            else
              pw.println("  <td>" + val.toString().trim()
                         + "</td>");
          }
          pw.println("</tr>");
        }
        pw.println("</table>");
        rs.close();
      }

Running the SqlServlet example

1. Set your development environment as described in Setting your Development Environment.

2. In your weblogic.properties file, if you have not set up a JDBC connection pool, uncomment the weblogic.jdbc.connectionPool.demoPool property to use the Cloudscape evaluation database.

3. Make sure there is an ACL (Access Control List) for the connection pool that includes either "guest" or "everyone". If you are using the Cloudscape demoPool connection pool, for example, uncomment the property:

       weblogic.allow.reserve.weblogic.jdbc.connectionPool.demoPool=\
         everyone

   This property is needed because SqlServlet does not specify a username and password when it gets the connection from the pool. Whenever an unauthenticated client attempts to use a WebLogic service, WebLogic Server assigns the client the "guest" user identity. If the connection pool does not have an ACL that allows "guest" to use the pool, the servlet will get an exception with a message such as: Pool connect failed: User "guest" does not have Permission "reserve" based on ACL "weblogic.jdbc.connectionPool.demoPool".

4. Create a DataSource entry for the "demoPool" connection pool by adding this property:

       weblogic.jdbc.TXDataSource.demoDataSource=demoPool

5. Register the servlet by adding these properties:

       weblogic.httpd.register.SqlServlet=\
             examples.intro.SqlServlet

       weblogic.httpd.initArgs.SqlServlet=\
             dataSource=demoDataSource

6. In your development shell, change to the directory where you copied the examples, and compile SqlServlet.java into the SERVLET_CLASSES directory:

   Windows NT:

       javac -d %SERVLET_CLASSES% SqlServlet.java

   UNIX:

       javac -d $SERVLET_CLASSES SqlServlet.java

7. Start WebLogic Server.

8. In a web browser, enter the URL for the servlet. For example, if WebLogic Server and your browser are on the same computer, enter http://localhost:7001/SqlServlet. Otherwise, change localhost to the name of the computer running WebLogic Server.

9. Enter a SQL query in the browser form and click the "Send SQL" button.

   You can enter any SQL DDL or DML statement that is valid for the target database. Since SqlServlet uses a JDBC Statement to execute the SQL, it can only handle results that can come from a Statement. For example, it does not handle procedure parameters.

More about Servlets

Learn more about writing HTTP Servlets in the developers guide, Using WebLogic HTTP Servlets.

You can find javadocs for the javax.servlet.http.HttpServlet package on the Sun website .

To configure WebLogic Server as an HTTP server, see the administration document Setting up WebLogic as an HTTP Server.

Copyright © 2000 BEA Systems, Inc. All rights reserved. Required browser: Netscape 4.0 or higher, or Microsoft Internet Explorer 4.0 or higher.