Skip Headers
Oracle® Containers for J2EE Servlet Developer's Guide
10g Release 3 (10.1.3)
B14426-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

7 Using JDBC or Enterprise JavaBeans

Dynamic Web applications typically access a database to provide content. This chapter shows how servlets can use JDBC, the Java standard API for database connectivity. It also provides an overview of Enterprise JavaBeans, which you can call from servlets to perform server-side business logic or manage data persistence for an application. The following sections are included:

Using JDBC in Servlets

A servlet can access a database using a JDBC driver. The recommended way to use JDBC is to employ an OC4J data source for the database connection, and to use JNDI, the Java Naming and Directory Interface, to look up the data source. The following subsections describe the basic steps involved and supply an example of this functionality:

For information about JDBC, see the Oracle Database JDBC Developer's Guide and Reference.

Why Use JDBC?

Part of the power of servlets comes from their ability to retrieve data from a database to create dynamic output. A servlet can generate dynamic HTML by getting information from a database and sending it back to the client, or can update a database, based on information passed to the servlet in the HTTP request.

JDBC is the standard Java mechanism for accessing a database.


Notes:

  • The general assumption is that you will use an Oracle database and Oracle JDBC driver. For connection to a non-Oracle database, you can use a DataDirect JDBC driver, provided with Oracle Application Server.

  • Instead of using JDBC directly from a servlet, you can use EJBs to access data instead. Also see "Overview of Enterprise JavaBeans".


Configuring a Data Source and Resource Reference

Your database connection will presumably use a standard data source. This section describes steps to configure a data source that you can use through JNDI:

  1. Configure the Data Source

  2. Configure the Resource Reference

See the Oracle Containers for J2EE Services Guide for more information about data sources and their configuration in OC4J.

Configure the Data Source

To use a data source, you must add it to the central OC4J data source configuration. Typically perform this step through Oracle Enterprise Manager 10g Application Server Control.

In the Application Server Control Console:

  1. From the applicable Application Home page, or from the OC4J Home page, select the Administration tab.

  2. Go to the task "JDBC Resources".

  3. From the JDBC Resources page, you can create a data source. You can also edit a data source created previously. You can also create or edit connection pools from this page.

Configuring a data source results in new or updated entries in the j2ee/home/config/data-sources.xml file, following the form shown below (in this example, to use the Oracle JDBC Thin driver). Note the following:

  • The <connection-pool> element has settings for a JDBC connection pool and specifies the name of the pool. (Connection pooling improves performance by taking a connection from an existing pool of connection objects, rather than going through the overhead of creating a new connection object.)

  • The <connection-factory> subelement of <connection-pool> specifies the class to use as a factory for connections (in this case presumably a class representing a data source) and the database user name, password, and connection string.

  • The <managed-data-source> element specifies the name (name) and JNDI location (jndi-name) of the data source, and references the connection pool specified in the <connection-pool> element.

See "Configure the Data Source for the Query Servlet" for an example.

<data-sources ... >
    <connection-pool name="poolname">
        <connection-factory factory-class="package.Classname"
                            user="user"
                            password="password"
                            url="jdbc:oracle:thin:@host:port/service"/>
    </connection-pool>
    <managed-data-source connection-pool-name="poolname"
                         jndi-name="jndiname"
                         name="name"/>
</data-sources>

Note:

For the url entry, the host:port:sid form is also still supported, but deprecated.

Configure the Resource Reference

To use a data source and JNDI lookup, there must also be an appropriate resource reference entry in the web.xml file. Here is an example, which corresponds to the data source configuration example shown in the preceding section:

   <resource-ref>
      <res-auth>Container</res-auth>
      <res-ref-name>jdbc/OracleDS</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
   </resource-ref>

This establishes that the jdbc/OracleDS resource is of type DataSource, for use as a data source.


Note:

Always use the Container setting for the <res-auth> element, indicating that the container, as opposed to application component code, performs the sign-on to the resource.

Implementing JDBC Calls

This section shows typical steps to access a database through JDBC in servlet code. See "Write the Query Servlet" for a complete example.

  1. Import required packages. In addition to the servlet and java.io packages, there are packages that include classes for JDBC, data sources, and JNDI:

    import javax.servlet.*;
    import javax.servlet.http.*;
    import javax.naming.*;  // for JNDI
    import javax.sql.*;     // extended JDBC interfaces (such as data sources)
    import java.sql.*;      // standard JDBC interfaces
    import java.io.*;
    
    
  2. Implement the init() method to perform the JNDI lookup of the data source and to establish the database connection, inside a try...catch block. The lookup here corresponds to the examples shown in "Configuring a Data Source and Resource Reference".

      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
        }
        catch (SQLException se) {
          throw new ServletException(se);
        }
        catch (NamingException ne) {
          throw new ServletException(ne);
        }
      }
    
    
  3. Implement the appropriate servlet doXXX() method, such as doGet(), and use JDBC to perform the desired SQL operations. In this example, assume a SQL query string has been constructed in a string query. The code creates a JDBC statement object, performs the query, loops through the result set to print the data records (where out is a PrintWriter object), then closes the statement and result set objects. SQL operations are also performed inside a try...catch block.

        try {
          Statement stmt = conn.createStatement();
          ResultSet rs = stmt.executeQuery(query);
          while (rs.next()) {
             out.println(rs.getString(1) + rs.getInt(2));
          }
          rs.close();
          stmt.close();
        }
        catch (SQLException se) {
          se.printStackTrace(out);
        }
    
    
  4. Implement the destroy() method to close the database connection (also inside a try...catch block).

      public void destroy() {
        try {
          conn.close();
        }
        catch (SQLException se) {
          se.printStackTrace();
        }
      }
    

Database Query Servlet Example

This example has an HTML welcome page that prompts the user for the LIKE specification that completes the following query:

SELECT ename, empno FROM emp WHERE ename LIKE xxx

The welcome page then invokes a servlet to perform the query and output the results.

The following sections show how to implement and configure the example:

Configure the Data Source for the Query Servlet

Here is the data source configuration for this example, as reflected in the OC4J data-sources.xml file, configurable through the Application Server Control Console, as described in "Configure the Data Source". This example uses the Oracle JDBC Thin driver to access a database on host myhost through port 5521 using service name myservice, connecting as user scott. (This is a simplified example—there are ways to avoid exposing the password in data-sources.xml.) The example also uses connection pooling, and the class OracleDataSource to represent the data source from which connections are obtained. The jndi-name entry, jdbc/OracleDS, is used by the servlet for the JNDI lookup of the data source.

<data-sources>
       <connection-pool name="ConnectionPool1">
             <connection-factory factory-class="oracle.jdbc.pool.OracleDataSource"
                                 url="jdbc:oracle:thin:@myhost:5521/myservice" 
                                 user="scott" password="tiger"/>
       </connection-pool>
       <managed-data-source connection-pool-name="ConnectionPool1"
                            jndi-name="jdbc/OracleDS" name="OracleDS"/>
</data-sources>

Write the HTML Welcome Page

Here is the welcome page, empinfo.html, prompting the user to complete the query, then invoking the query servlet. For this example, the servlet is deployed to be invoked with the context path and servlet path of /myquery/getempinfo.

<html>
<head>
<title>Query the Employees Table</title>
</head>
<body>
<form method=GET ACTION="/myquery/getempinfo">
The query is<br>
SELECT ename, empno FROM emp WHERE ename LIKE xxx
 
<p>
Specify the WHERE clause xxx parameter.<br>
Enclose entry in single-quotes; use % for wildcard. Search is case-sensitive.<br>
Example: 'S%' (for all names starting with 'S').<br>
<input type=text name="queryVal">
<p>
<input type=submit>
</form>
</body>
</html>

Write the Query Servlet

Here is the query servlet, GetEmpInfo, implementing the steps described in "Implementing JDBC Calls". There is also formatting for an HTML table for the output, and a counter for the number of rows retrieved.

import javax.servlet.*;
import javax.servlet.http.*;
import javax.naming.*;  // for JNDI
import javax.sql.*;     // extended JDBC interfaces (such as data sources)
import java.sql.*;      // standard JDBC interfaces
import java.io.*;
 
public class GetEmpInfo extends HttpServlet {
 
  DataSource ds = null;
  Connection conn = null;
 
  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
    }
    catch (SQLException se) {
      throw new ServletException(se);
    }
    catch (NamingException ne) {
      throw new ServletException(ne);
    }
  }
 
  public void doGet (HttpServletRequest req, HttpServletResponse resp)
                     throws ServletException, IOException {
 
/* Get the LIKE specification for the WHERE clause from the user, through the */
/* HTTP request, then construct the SQL query.                                */
    String queryVal = req.getParameter("queryVal");
    String query =
      "select ename, empno from emp " +
      "where ename like " + queryVal;
 
    resp.setContentType("text/html");
 
    PrintWriter out = resp.getWriter();
    out.println("<html>");
    out.println("<head><title>GetEmpInfo Servlet</title></head>");
    out.println("<body>");
 
/* Create a JDBC statement object and execute the query.     */
    try {
      Statement stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery(query);
 
/* HTML table formatting for the output.                     */
      out.println("<table border=1 width=50%>");
      out.println("<tr><th width=75%>Last Name</th><th width=25%>Employee " +
                   "ID</th></tr>");
 
/* Loop through the results. Using ResultSet getString() and         */
/* getInt() methods to retrieve the individual data items.           */
      int count=0;
      while (rs.next()) {
         count++;
         out.println("<tr><td>" + rs.getString(1) + "</td><td>" +rs.getInt(2) +
                     "</td></tr>");
       
      }
      out.println("</table>"); 
      out.println("<h3>" + count + " rows retrieved</h3>");
         
      rs.close();
      stmt.close();
    }
    catch (SQLException se) {
      se.printStackTrace(out);
    }
 
    out.println("</body></html>");
  }
 
  public void destroy() {
    try {
      conn.close();
    }
    catch (SQLException se) {
      se.printStackTrace();
    }
  }
}

Configure the Servlet and JNDI Resource Reference

The web.xml file, in addition to configuration for the servlet, must include a resource reference entry for the data source. There is also configuration to declare empinfo.html as a welcome file. Here is the file for this example:

<?xml version="1.0" ?> 
<!DOCTYPE web-app (doctype...)> 
<web-app> 
   <servlet> 
      <servlet-name>empinfoquery</servlet-name> 
      <servlet-class>GetEmpInfo</servlet-class> 
   </servlet> 
   <servlet-mapping> 
      <servlet-name>empinfoquery</servlet-name> 
      <url-pattern>getempinfo</url-pattern> 
   </servlet-mapping> 
   <resource-ref> 
      <res-auth>Container</res-auth> 
      <res-ref-name>jdbc/OracleDS</res-ref-name> 
      <res-type>javax.sql.DataSource</res-type> 
   </resource-ref> 
   <welcome-file-list>
      <welcome-file>empinfo.html</welcome-file>
   </welcome-file-list>
</web-app>

Package the Query Example

The WAR file for this example, which we name empinfo.war, has the following contents and structure:

empinfo.html
META-INF/Manifest.mf
WEB-INF/web.xml
WEB-INF/classes/GetEmpInfo.class
WEB-INF/classes/GetEmpInfo.java

And the EAR file is as follows:

empinfo.war
META-INF/Manifest.mf
META-INF/application.xml

(The Manifest.mf files are created automatically by the JAR utility.)

Invoke the Query Example

For this example, assume that application.xml maps the context path /myquery to empinfo.war. In this case, after deployment, you can invoke the welcome page empinfo.html as follows (given the declaration of empinfo.html as a welcome page in web.xml):

http://host:port/myquery

In a test run, we specify 'S%' to look for any names starting with "S":

Description of queryin.gif follows
Description of the illustration queryin.gif

For a database used for the test run, this returned two entries:

Description of queryout.gif follows
Description of the illustration queryout.gif

Overview of Enterprise JavaBeans

A servlet can call Enterprise JavaBeans to access a database or perform additional business logic. The following sections offer an overview of EJBs and their use from servlets:

For detailed information about EJB features, and for servlet-EJB examples in an Oracle Application Server environment, refer to the Oracle Containers for J2EE Enterprise JavaBeans Developer's Guide.


Note:

OC4J provides an EJB tag library to make accessing EJBs from JSP pages more convenient. See the Oracle Containers for J2EE JSP Tag Libraries and Utilities Reference for information.

Why Use Enterprise JavaBeans?

EJBs have many uses in business applications, including the use of session beans for server-side business logic and entity beans to manage data persistence. EJB technology provides a more robust infrastructure than JSP or servlet technology, for use in secure, transactional, server-side processing.

A typical application design often uses a servlet as a front-end controller to process HTTP requests, with EJBs being called to access or update a database, and finally another servlet or JSP page being used to display data for the requester.

There are three categories of EJBs: session beans, entity beans, and message-driven beans. Container Managed Persistence entity beans, in particular, are well-suited to manage persistent data, because they make it unnecessary to use the JDBC API directly when accessing a database. Instead, you can let the EJB container handle database operations for you transparently.

Session beans are useful to model business logic and may be either stateless or stateful, with stateful beans typically being used where transaction state must be maintained across method calls or servlet requests. Stateless beans contain individual business logic methods that are independent of application state.

EJB Support in OC4J and Oracle Application Server

OC4J provides full support for session beans, entity beans, and message driven beans. The entity bean implementation provides Bean Managed Persistence (BMP), Container Managed Persistence (CMP), local interfaces, container-managed relationships, and the ability to perform queries using the EJB query language.

Within the entity bean implementation, a basic persistence manager supports both simple mapping and complex mapping, supporting one-to-one, one-to-many, many-to-one, and many-to-many object-relational mappings. It also automatically maps fields of an entity bean to a corresponding database table.

To facilitate application maintenance and deployment, Oracle Application Server provides a number of enhancements, including dynamic EJB stub generation. CORBA interoperability provides the capability to build EJBs and access them as CORBA services from CORBA clients.

Servlet-EJB Lookup Scenarios

There are three scenarios in calling an EJB from a servlet:

  • Local lookup: The servlet calls an EJB that is co-located, meaning it is in the same application and on the same host, running in the same JVM. The servlet and EJB would have been deployed in the same EAR file, or in EAR files with a parent/child relationship. For this, use EJB local interfaces.

  • Remote lookup within the same application: The servlet calls an EJB that is in the same application, but on a different host, where the application is deployed to both hosts. This requires EJB remote interfaces. This would be the case for a multitier application where the servlet and EJB are in the same application, but on different tiers.

  • Remote lookup outside the application: The servlet calls an EJB that is not in the same application. This requires EJB remote interfaces. The EJB may be on a different host or on the same host, but is not running in the same JVM.

Servlet-EJB communications use JNDI for local and remote EJB calls. When a remote lookup is performed, JNDI uses either ORMI (the Oracle implementation of RMI) or IIOP (the standard and interoperable Internet Inter-Orb Protocol). In versions of EJB before 3.0, only home interfaces require JNDI lookup. They are then used to create EJBs for use by the application. J2EE components can use the default no-args constructor to look up objects within the same application. The RMIInitialContextFactory or IIOPInitialContextFactory class can be used for remote lookups. See the Oracle Containers for J2EE Services Guide for more information about JNDI in OC4J.

A remote lookup requires a JNDI environment to be set up, including the URL and a user name and password. This setup is typically in the servlet code, but for a lookup in the same application it can be in the rmi.xml file instead.

Remote lookup within the same application on different hosts also requires proper configuration of the OC4J EJB remote flag for your application, on each host. See "Using the Remote Flag for Remote Lookup within the Same Application".

As in any application where EJBs are used, there must be an entry for each EJB in the ejb-jar.xml file.

EJB Local Interfaces Versus Remote Interfaces

In initial versions of the EJB specification, an EJB always had a remote interface extending the javax.ejb.EJBObject interface, and a home interface extending the javax.ejb.EJBHome interface. In this model, all EJBs are defined as remote objects, adding unnecessary overhead to EJB calls in situations where the servlet or other calling module is co-located with the EJB.


Note:

The OC4J copy-by-value parameter, which maps to an attribute of the <session-deployment> element of the orion-ejb-jar.xml file, is also related to avoiding unnecessary overhead, specifying whether to copy all incoming and outgoing parameters in EJB calls. See the Oracle Containers for J2EE Enterprise JavaBeans Developer's Guide for information. Note that this parameter is configurable as copyByValue in the Application Server Control deployment plan editor, as discussed in the Oracle Containers for J2EE Deployment Guide.

In more recent versions, the EJB specification supports local interfaces for co-located EJB calls. In this case, the EJB has a local interface that extends the javax.ejb.EJBLocalObject interface, in contrast to having a remote interface. In addition, a local home interface that extends the javax.ejb.EJBLocalHome interface is specified, in contrast to having a home interface.

Any lookup involving EJB remote interfaces uses RMI and has additional overhead such as for security. RMI and other overhead are eliminated when you use local interfaces.


Notes:

  • An EJB can have both local and remote interfaces.

  • The term local lookup in this document refers to a co-located lookup, in the same JVM. Do not confuse "local lookup" with "local interfaces". Although local interfaces are typically used in any local lookup, there may be situations in which remote interfaces are used instead.


Using the Remote Flag for Remote Lookup within the Same Application

In OC4J, to perform a remote EJB lookup within the same application but on different tiers (where the same application has been deployed to both tiers), you must set the OC4J EJB remote flag appropriately on each tier. When this flag is set to "true" on a server, beans will be looked up on a remote server instead of the EJB service being used on the local server.

The remote flag maps to an attribute in the <ejb-module> subelement of an <orion-application> element in the orion-application.xml file. The default setting is remote="false". Update the file to set this flag to "true", as follows:

<orion-application ... >
   ...
   <ejb-module remote="true" ... />
   ...
</orion-application>

(You cannot set this flag through Oracle Enterprise Manager 10g Application Server Control.)

You can deploy the application EAR file to both servers with a remote flag value of "false", then set it to "true" on server 1, the servlet tier. This is illustrated in Figure 7-1.

Figure 7-1 Setup for Remote Lookup within Application

Description of ejbremot.gif follows
Description of the illustration ejbremot.gif

You must properly configure server 2 as a remote host to instruct OC4J to look for EJBs there. Specify host, port, username, and password settings in the <server> subelement of the applicable <rmi-server> element in the rmi.xml file on server 1, as follows:

<rmi-server ... >
...
   <server host="remote_host" port="remote_port" username="user_name"
           password="password" />
...
</rmi-server>

See the Oracle Containers for J2EE Enterprise JavaBeans Developer's Guide for details about using remote hosts and the remote flag.


Note:

Use the default administrative user name for the remote host, and the administrative password set up on the remote host. This avoids possible JAZN configuration issues. See the Oracle Containers for J2EE Security Guide for information about JAZN.