[View INPRISE Home Page][View Product List][Search This Web Site][View Available Downloads][Join Inprise Membership][Enter Discussion Area][Send Email To Webmaster]
JBuilder Home Page

Building Java Servlets with JBuilder
Written by Live Software, Inc.

Part II

NOTE: The views and information expressed in this document represent those of its author(s) who is solely responsible for its content. Borland does not make or give any representation or warranty with respect such content.

Return to Part I
Part III

Example: Creating a JDBC Servlet as RMI server

The purpose of this topic is to help you become acquainted with using the Java Servlet API, and at the same time acquainting you with using JBuilderÆs built-in RMI support. This tutorial takes you through the steps of extending the capabilities of a servlet to provide RMI services for client agents. This will give servlet developers a wider option of distributing objectsÆ responsibilities. This example continues from Tutorial1a: creating a database servlet using Data Express. In this example you will learn how to:

  • Implement the Servlet interface
  • Add RMI functionality to a servlet
  • Use JBuilderÆs built-in RMI support to create stubs and skeletons

See also:
Distributed computing with Java RMI

A Simple Database RMI Servlet
Although this example is a continuation of Tutorial1a, we will be creating a new project. Creating a new project for each example will hopefully help you understand the transitions made from one example to another. Also, keeping these examples separate will prevent your projectÆs window from unnecessary clutter. Do the following steps to start this exampleÆs project.

  1. Follow the same steps as with Creating the SimpleServlet in JBuilder with the exception of part 1 and part 5. In part 1 we will be defining a new package, so select File|New Project. In the name field, append the directory path, /JBExamples/database/servlets/rmi/JDBCRmiServlet.jpr directly to the path to myproject. Click Finish. In part 5 name the servlet JDBCRmiServlet.

In order for an object to be used in the RMI system, it has to implement the Remote interface. The Remote interface does not introduce any new methods it just acts as a marker for RMI objects. Also, any methods in the interface must be declared as throwing the java.rmi.RemoteException. RemoteException acts as a base class for exceptions that may occur in remote operations.

Defining a Remote interface is merely having to choose which methods in your class you want exposed remotely. For SimpleServlet, weÆve chosen the method getResultTable(), and named its interface IDBQuerier. See Example 2-1.

Example 2-1: IDBQuerier.java


package JBExamples.database.servlets.rmi;

public interface IDBQuerier extends java.rmi.Remote {
  public IDataTable getResultTable(String dbQuery)
    throws java.rmi.RemoteException;
}

The method getResultTable returns an instance of IDataTable. IDatatTable is being passed through the RMI system as well. We have two choices on how IDataTable is to be sent through. One choice is to have IDataTable extend the java.rmi.Remote interface, not unlike IDBQuerier. Or, we can have IDataTable extend serializable. By having IDataTable extend serializable, IDataTable would be passed by value. If IDataTable was to implement java.rmi.Remote, IDataTable would be passed by refererence. Example 2-2 will make clear which interface was implemented.

Example 2-2: IDataTable.java


package JBExamples.database.servlets.rmi;

public interface IDataTable extends java.rmi.Remote {
  public String[] getColumnNames() throws java.rmi.RemoteException;
  public int getRowCount() throws java.rmi.RemoteException;
  public int getColumnCount() throws java.rmi.RemoteException;
  public String getDataAt(int row, int column) throws java.rmi.RemoteException;
  public String toHTMLString() throws java.rmi.RemoteException;
  public String toTableString() throws java.rmi.RemoteException;
} 

As you can see, the interface is very similar to the IDataTable interface created in the SimpleServlet example. The only difference is that the RMI version extends from java.rmi.Remote and all the methods throw java.rmi.RemoteException.

The next step is to write the implementation of these interfaces. LetÆs start with the implementation of IDataTable. Fortunately, since we are working off the code weÆve created in the SimpleServlet example, we wonÆt have to write two much. The name of the class is DataTableImpl. See Example 2-3 for DataTableImplÆs implementation code.

Example 2-3: DataTableImpl.java


package JBExamples.database.servlets.rmi;

//Packages for RMI support
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;

//Packages for database support
import borland.sql.dataset.QueryDataSet;
import borland.jbcl.dataset.DataRow;
import borland.jbcl.dataset.DataSetException;
import java.util.Vector;

/*
 *  A convenience class that copies the data from QueryDataSet
 *  into a table of Strings.
 */
public class DataTableImpl extends UnicastRemoteObject
  implements IDataTable
{
  private String[] columnNames;
  private Vector tableData;
  private int columnCount;
  private int rowCount;

  public DataTableImpl() throws RemoteException {
    super();
  }

  public DataTableImpl(QueryDataSet queryDataSet)
    throws RemoteException, DataSetException {
        DataRow dataRow   = new DataRow(queryDataSet);
        this.columnCount  = dataRow.getColumnCount();
        this.rowCount     = queryDataSet.getRowCount();
        this.columnNames  = dataRow.getColumnNames( columnCount );
        copyQueryData(queryDataSet, dataRow);
  }

  private void copyQueryData(QueryDataSet queryDataSet, DataRow dataRow)
    throws DataSetException
  {
    tableData = new Vector();

    for(int i=0; i",
       "</table>\n","<tr align=center>","</tr>\n","<td>","</td>");
  }

  private String toTableString(String tblStart, String tblEnd, String rowStart,
    String rowEnd, String dataStart, String dataEnd ) throws RemoteException
  {
    StringBuffer results = new StringBuffer();

    try {
    results.append(tblStart);
    //Column names
    results.append(rowStart);
    for(int i=0; i"+e.toString();  }

    return results.toString();
  }

}

Again in comparing the IDataTableImpl class created in the SimpleServlet example with the IDataTableImpl class for this example, the only difference is that this time IDataTableImpl now extends java.rmi.server.UnicastRemoteObject class. UnicastRemoteObject is an extension of RemoteServer class, which acts as a base class for server implementation of objects in RMI. RMI does not require your remote server to derive from a RemoteServer subclass, but doing this lets your server inherit specialized implementations of some methods from Object (hashCode(), equals(), and toString()) so that they do the right thing in a remote object scenario.

Now lets examine the interface in Example 2-1. Recall that this interface is needed to define methods of our JDBCRmiServlet which we want exposed to the RMI system. JDBCRmiServlet will have to implement this interface as well as extend from java.rmi.server.UnicastRemoteObject. Recall that Java does not allow multiple inheritance. By looking at SimpleServlet we see that it extends from javax.servlet.http.HttpServlet. We cannot have JDBCRmiServlet extend HttpServlet because we need it to extend from UnicastRemoteObject. The HttpServlet is a subclass of the abstract class javax.servlet.GenericServlet. GenericServlet implements javax.servlet.Servlet, javax.servlet.ServletConfig, and Serializable. To make things simple, weÆll just have our JDBCRmiServlet implement Servlet, and ServletConfig. WeÆll leave the Serializable, features up to whomever wants to implement them. The choice of having JDBCRmiServlet implement ServletConfig, is a matter of convenience to make getting the configuration data easier to get to by other servlets. For example, a servlet can implement getServletContext by writing,


public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
   }
making access to the servletÆs context object a single method invocation. Example 2-4 is the complete code for JDBCRmiServlet.

Example 2-4: JDBCRmiServlet.java


package JBExamples.database.servlets.rmi;

//Packages for servlet support
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;

//Packages for database support
import borland.sql.dataset.*;
import borland.jbcl.dataset.DataRow;
import borland.jbcl.dataset.DataSetException;

//Packages for rmi support
import java.rmi.registry.*;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.*;

/*
 * A JDBC Servlet as an RMI Server.  This class performs queries on a database
 * and returns the results to a remote client agent.
 */
public class JDBCRmiServlet extends UnicastRemoteObject
	implements IDBQuerier, Servlet, ServletConfig
  {
  Database database1 = new Database();

  public JDBCRmiServlet() throws RemoteException {
    super();
  }

  private void jbInit() throws Exception{
    database1.setConnection(new
borland.sql.dataset.ConnectionDescriptor("jdbc:odbc:DemoDatabase", "",
"", false, "sun.jdbc.odbc.JdbcOdbcDriver")); } /** * A method that is accessible through RMI. * This method performs a query with the given query string * and stores the results in an implementation of IDataTable. */ public IDataTable getResultTable(String dbQuery) throws RemoteException { IDataTable dataTable = null; try { QueryDataSet queryDataSet = getQueryDataSet(dbQuery); queryDataSet.open(); dataTable = new DataTableImpl(queryDataSet); queryDataSet.close(); } catch(Exception e) { throw new RemoteException(e.toString()); } return dataTable; } public QueryDataSet getQueryDataSet(String dbQuery) throws Exception { QueryDataSet queryDataSet = new QueryDataSet(); queryDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database1, dbQuery, null, true, Load.ALL)); return queryDataSet; } /* SERVLET SUPPORT STARTS HERE... */ private ServletConfig conf; public void log(String msg) { getServletContext().log(msg); } public void destroy() { try { //Close the database connection System.out.println("JDBCRmiServlet closing database connection."); database1.closeConnection(); } catch(DataSetException e) { System.out.println("Error in closing the database connection"); } } public ServletConfig getServletConfig() { return conf; } //Get Servlet information public String getServletInfo() { return "JBExamples.database.servlets.rmi.JDBCRmiServlet Information"; } public void init(ServletConfig conf) throws ServletException { this.conf = conf; //Initialize the database connection try { jbInit(); } catch (Exception e) { e.printStackTrace(); } //Register this RMI object System.out.println("Registering JDBCRmiServlet..."); try { Naming.rebind("DBQuerier", this); System.out.println("JDBCRmiServlet is ready"); } catch(Exception e) { e.printStackTrace(); System.out.println(e.toString()); } } /** * Servlet's service method. * Results of the query will be formatted into an HTML table, and streamed * to the client. */ public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { //Set content type response.setContentType("text/html"); //A database query String dbQuery = ""; try {dbQuery = request.getParameter("dbQuery");} catch (Exception e) { e.printStackTrace(); } //Get a result table from the dbQuery IDataTable dataTable = getResultTable(dbQuery); //Get a print stream to the client PrintWriter out = response.getWriter(); out.println("<CENTER>"); out.println("<TABLE width=\"80%\" cellpadding=\"0\" border=\"2\"
cellspacing=\"0\">"); out.println("<TR bgcolor=\"#000000\">"); out.println("<TD
align=\"center\">"); out.println("<FONT color=\"ffffff\"
face=\"Arial\" size=\"3\"><B>Database Results</B></FONT>");
out.println("</TD>"); out.println("</TR>"); out.println("<TR bgcolor=\"#ffffff\">");
out.println("<TD align=\"center\">"); out.println( dataTable.toHTMLString() ); out.println("</TABLE>"); out.println("</TD>"); out.println("</TR>");
out.println("</TABLE>"); out.println("</CENTER>"); } /* Implementation of ServletConfig interface */ public ServletContext getServletContext() { return conf.getServletContext(); } public String getInitParameter(String name) { return conf.getInitParameter(name); } public Enumeration getInitParameterNames() { return conf.getInitParameterNames(); } }

The log method was added to make up for not extending HttpServlet, this method is implemented to allow you to print your debug/error messages to a log file. The getServletConfig method is implemented for the Servlet interface. This returns the ServletConfig object which was passed in by the servlet runner in the init method which we implemented from the SimpleServlet example. Another new method implemented for the Servlet interface is the service method. The service method with a different signature was implemented in the SimpleServlet example. . In the SimpleServlet example weÆve implemented the service(HttpServletRequest, HttpServletResponse) method. This time we are required to implement the service(ServletRequest, ServletResponse) method. The classes, ServletRequest, and ServletResponse are superclasses of HttpServletRequest and HttpServletResponse. Fortunately the methods we invoked from HttpServletResponse, particularly getWriter() and setContentType() are defined in the ServletResponse interface. The same is true for the getParameter() method invoked from HttpServletRequest. This method is defined in the ServletRequest interface. So basically all we had to do was change the signature of the service method to take in classes of type ServletRequest, and ServletResponse. The three methods invoked in behalf of the ServletConfig interface are, getServletContext, getInitParameter, and getInitParameterNames, these methods simply passes on the invokation of the corresponding methods to the member variable, conf. The conf variable is an instance of ServletConfig which was set in the init method.

JDBCRmiServlet has to bind itself into the RMI registry. This makes the JDBCRmiServlet object available for RMI lookup by clients. This is done in the init method by:

Naming.rebind("DBQuerier", this);

The next step is to compile JDBCRmiServlet, and generate its RMI stubs and skeletons. The next section steps you through doing just that.

Using JBuilderÆs built-in RMI support
By now you should have the four java files in your project: IDataTable.java, IDBQuerier.java, DataTableImpl.java, and JDBCRmiServlet.java. The next step is to generate the client stub and server skeleton class files for the two concrete classes, DataTableImpl.java and JDBCRmiServlet.java. To generate the stub and skeleton code for these two classes, do the following:

  1. Set DataTableImpl to have its stub and skeleton generated. In the project tree, right click on DataTableImpl.java, and check the generate RMI stub / skeleton box. Click Ok.
  2. Set JDBCRmiServlet to have its stub and skeleton generated. In the project tree, right click on JDBCRmiServlet.java, and check the generate RMI stub / skeleton box. Click Ok.
  3. Make the project. Hit Ctrl+F9 to compile.

Invoking JDBCRmiServlet
Once youÆve compiled, the next step is to copy your class files into the <servlet_runner_home>/servlets directory, the JDBCRmiServlet should be able to be invoked by either of the two ways:

  • Through the HTTP transport. You can call JDBCRmiServlet using the same methods as described to invoke SimpleServlet in Tutorial1a. See Invoking SimpleServlet.
  • Through the RMI transport. You can invoke the getResultTable method from an RMI client. . This will be discussed in detail in later sections.

Loading JDBCRmiServlet on init

If you recall, the JDBCRmiServlet makes itself available for RMI lookup in its init method. The init method is called when the servlet is loaded by the servlet runner. RMI clients can only get to the RMI server processes if they are registered for lookup. This means the JDBCRmiServlet has to be available in the RMI registry before any RMI clients can look it up. An error will occur if JDBCRmiServlet is looked up by an RMI client before it is loaded by the servlet runner. Just having your RMI servlet available in the servlet runnerÆs servlet directory is not enough to have it available for an RMI lookup. Unless specified otherwise, a servlet is only loaded by the servlet runner when it is asked for from an HTTP client through the web server. When it is asked for, and if the servlet exists under the servlet runnerÆs servlets directory, and if it has not been loaded yet, then it is loaded, and the init method of the servlet is called. From then on until the web server is stopped, the servlet is available for servicing HTTP and RMI requests. So, in order for the RMI servlet to be available through RMI lookup, it has to be requested through the HTTP transport first. This may not be acceptable. One way to work around this is to specify that the servlet be loaded by the servlet runner when the web server starts up. This is done through the servlet runnerÆs admin. Setting this "load on init" property for a servlet, makes the servlet available for HTTP and RMI servicing as long as the web server is running.

Example: Creating a JDBC Servlet as CORBA Server

The purpose of this topic is to help you become acquainted with using the Java Servlet API, and at the same time acquainting you with using JBuilderÆs built-in CORBA support. This tutorial takes you through extending the capabilities of a servlet to provide CORBA services for client agents. This will give servlet developers a wider option of distributing objectsÆ responsibilities. This example continues from Tutorial1a: creating a database servlet using Data Express. In this example you will learn how to:

  • Implement the Servlet interface
  • Add CORBA functionality to a servlet
  • Use JBuilderÆs built-in Visibroker support to create stubs and skeletons

See also:
Creating distributed applications with CORBA

A Simple Database CORBA Servlet
Although this example is a continuation of Tutorial1a, we will be creating a new project. Creating a new project for each example will hopefully help you understand the transitions made from one example to another. Also, keeping these examples separate will prevent your projectÆs window from unnecessary clutter. Do the following steps to start this exampleÆs project.

  1. Follow the same steps as with Creating the SimpleServlet in JBuilder with the exception of part 1 and part 5. In part 1 we will be defining a new package, so select File|New Project. In the name field, append the directory path, /JBExamples/database/servlets/corba/JDBCCorbaServlet.jpr directly to the path to myproject. Click Finish. In part 5 name the servlet JDBCCorbaServlet.

In order for an object to be used in the CORBA system, it has to implement the org.omg.CORBA.Object interface. The org.omg.CORBA.Object interface does not introduce any new methods it just acts as a marker for CORBA objects. Defining an org.omg.CORBA.Object interface is merely having to choose which methods in your class you want exposed remotely. For SimpleServlet, weÆve chosen the method getResultTable(), and named its interface IDBQuerier. See Example 3-1.

Example 3-1: IDBQuerier.java


package JBExamples.database.servlets.corba;

public interface IDBQuerier extends org.omg.CORBA.Object
{
    public IDataTable getResultTable(String dbQuery);
}
The method getResultTable returns an instance of IDataTable. IDatatTable is being passed through the CORBA system as well. This means the IDataTable interface will also have to implement the org.omg.CORBA.Object. See Example 3-2.

Example 3-2: IDataTable.java


package JBExamples.database.servlets.corba;

public interface IDataTable extends org.omg.CORBA.Object
{
    public String[] getColumnNames();
    public int getRowCount();
    public int getColumnCount();
    public String getDataAt(int row, int column);
    public String toHTMLString();
    public String toTableString();
}
As you can see, the interface is very similar to the IDataTable interface created in the SimpleServlet example. The only difference is that the CORBA version extends from org.omg.CORBA.Object.

Using JBuilderÆs built-in CORBA support
Before we write the implementations of the above interfaces. WeÆll first need the client stubs and server skeletons to be generated. Since JBuilder provides CORBA support through Visibroker, we can generate the needed class files without having to write any IDL code. This is done by using the java2iiop compile command. You can set the above java interfaces to be compiled with java2iiop by following these steps:

  1. Set IDataTable to be compiled with java2iiop. In the project tree, right click on IDataTable.java. Select Java Source Properties. Check the box Generate IIOP interface. Click Ok.
  2. Set IDBQuerier to be compiled with java2iiop. In the project tree, right click on IDBQuerier.java. Select Java Source Properties. Check the box Generate IIOP interface. Click Ok.
  3. Compile the existing code. Hit Ctrl+F9.

With the default settings of the java2iiop compiler, the following files should be generated:
IIOP files for IdataTable IIOP files for IDBQuerier
_IdataTableImplBase.java _ IDBQuerierImplBase.java
_sk_IdataTable.java _sk_IDBQuerier.java
_st_IdataTable.java _st_IDBQuerier.java
IdataTableHelper.java IDBQuerierHelper.java
IdataTableHolder.java IDBQuerierHolder.java
IdataTableOperations.java IDBQuerierOperations.java

The base classes _IDataTableImplBase, and _IDBQuerierImplBase are abstract classes. The definition of _IDataTableImplBase follows.

abstract public class _IDataTableImplBase extends org.omg.CORBA.portable.Skeleton implements JBExamples.database.servlets.corba.IDataTable {

The _IDBQuerierImplBase class is defined similarly. _IDataTableImplBase, and _IDBQuerierImplBase are the classes which implement the IDataTable and IDBQuerier interfaces respectively. We wonÆt go into the implementation of org.omg.CORBA.portable.Skeleton. These are details that hopefully should not concern you. The org.omg.CORBA.portable.Skeleton is the interface which the server ORB will be looking for when invoking methods on the base objectÆs implementation. The next step is to extend the _IDBQuerierImplBase, and _IDataTableImplBase and implement the methods for the interfaces of their base class.

LetÆs start with extending the _IDataTableImplBase class. Fortunately, since we are working off the code weÆve created in the SimpleServlet example, we wonÆt have to write two much. The name of the class is DataTableImpl. See Example 3-3 for DataTableImplÆs implementation code.

Example 3-3: DataTableImpl.java


package JBExamples.database.servlets.corba;

import borland.sql.dataset.QueryDataSet;
import borland.jbcl.dataset.DataRow;
import borland.jbcl.dataset.DataSetException;
import java.util.Vector;

/*
 *  A convenience class that copies the data from QueryDataSet
 *  into a table of Strings.
 */
public class DataTableImpl extends _IDataTableImplBase
{
  private String[] columnNames;
  private Vector tableData;
  private int columnCount;
  private int rowCount;

  /** Construct a transient object. */
  public DataTableImpl() {
    super();
  }

  public DataTableImpl(QueryDataSet queryDataSet)
    throws DataSetException
  {
    DataRow dataRow   = new DataRow(queryDataSet);
    this.columnCount  = dataRow.getColumnCount();
    this.rowCount     = queryDataSet.getRowCount();
    this.columnNames  = dataRow.getColumnNames( columnCount );
    copyQueryData(queryDataSet, dataRow);
  }

  private void copyQueryData(QueryDataSet queryDataSet, DataRow dataRow)
    throws DataSetException
  {
    tableData = new Vector();

    for(int i=0; i"+e.toString();  }

    return results.toString();
  }

}
In comparing the IDataTableImpl class created in the SimpleServlet example with this exampleÆs IDataTableImpl class, the only difference is, this time IDataTableImpl now extends _IDataTableImplBase class.

Now lets revisit the interface in Example 2-1. Recall that this interface is needed to define methods of our JDBCCorbaServlet which we want exposed to the CORBA system. JDBCCorbaServlet will have to extend the _IDBQuerierImplBase class.

Recall that Java does not allow multiple inheritance. By looking at SimpleServlet we see that it extends from javax.servlet.http.HttpServlet. We cannot have JDBCCorbaServlet extend HttpServlet because we need it to extend from _IDBQuerierImplBase. The HttpServlet is a subclass of the abstract class javax.servlet.GenericServlet. GenericServlet implements javax.servlet.Servlet, javax.servlet.ServletConfig, and Serializable. To make things simple, weÆll just have our JDBCCorbaServlet implement Servlet, and ServletConfig. WeÆll leave the Serializable features up to whomever wants to implement them. The choice of having JDBCCorbaServlet implement ServletConfig, is a matter of convenience to make getting the configuration data easier to get to by other servlets. For example, a servlet can implement getServletContext by writing,


public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
   }
making access to the servletÆs context object a single method invocation. Example 3-4 is the complete code for JDBCCorbaServlet.

Example 3-4: JDBCCORBServlet.java


package JBExamples.database.servlets.corba;

//Packages for servlet support
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;

//Packages for database support
import borland.sql.dataset.*;
import borland.jbcl.dataset.DataRow;
import borland.jbcl.dataset.DataSetException;

//Packages for CORBA support
import org.omg.CORBA.*;

/**
 * A servlet that also acts as a CORBA server for performing database
 * queries.
 */
public class JDBCCorbaServlet extends _IDBQuerierImplBase
  implements Servlet
{
  Database database1 = new Database();

  Thread BOAThread = null;

  //A Runnable member class used to listen
  //for CORBA requests
  class BOARunnable implements Runnable
  {
    BOA boa;
    public BOARunnable(BOA boa) {
      this.boa = boa;
    }
    public void run() {
      boa.impl_is_ready();
    }
  }

  /**
   * The servlet runner instantiates this servlet through it's empty constructor.
   * This is also where we name this CORBA server.  
   */
  public JDBCCorbaServlet() {
    super("DBQuerier");
  }

  private void jbInit() throws Exception {
    System.out.println("Connecting to database...");
    database1.setConnection(new
borland.sql.dataset.ConnectionDescriptor("jdbc:odbc:DemoDatabase", "",
"", false, "sun.jdbc.odbc.JdbcOdbcDriver")); System.out.println("Database is ready"); } /** * A method that is accessible through CORBA. This method performs a query * with the given query string and stores the results in an implementation * of IDataTable. */ public IDataTable getResultTable(String dbQuery) { IDataTable dataTable = null; try { //dataTable = new DataTableImpl( getQueryDataSet(dbQuery) ); QueryDataSet queryDataSet = getQueryDataSet(dbQuery); queryDataSet.open(); dataTable = new DataTableImpl(queryDataSet); queryDataSet.close(); } catch(Exception e) { System.err.println("Error in getResultTable: "+e.toString()); } return dataTable; } /** * Execute the given query string. */ public QueryDataSet getQueryDataSet(String dbQuery) throws Exception { QueryDataSet queryDataSet = new QueryDataSet(); queryDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database1, dbQuery, null, true, Load.ALL)); return queryDataSet; } /* SERVLET SUPPORT STARTS HERE... */ private ServletConfig conf; public void log(String msg) { getServletContext().log(msg); } public void destroy() { try { //Close the database connection System.out.println("JDBCCorbaServlet closing database connection."); database1.closeConnection(); } catch(DataSetException e) { System.out.println("Error in closing the database connection"); } //Stop the BOA thread System.out.println("Stopping BOAThread"); if( this.BOAThread != null ) this.BOAThread.stop(); } public ServletConfig getServletConfig() { return conf; } //Get Servlet information public String getServletInfo() { return "JBExamples.database.servlets.corba.JDBCCorbaServlet Information"; } public void init(ServletConfig conf) throws ServletException { this.conf = conf; //Initialize the database connection try { jbInit(); } catch (Exception e) { e.printStackTrace(); } // Initialize the ORB. System.out.println("Initializing ORB..."); String[] args = new String[0]; ORB orb = ORB.init(args, null); BOA boa = orb.BOA_init(); boa.obj_is_ready(this); //Start up a thread that waits for incoming requests through the ORB this.BOAThread = new Thread( new BOARunnable(boa) ); this.BOAThread.start(); System.out.println("DBQuerier is ready"); } /** * Servlet's service method. * Results of the query will be formatted into an HTML table, and streamed * to the client. */ public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { //Set content type response.setContentType("text/html"); //A database query String dbQuery = ""; try {dbQuery = request.getParameter("dbQuery");} catch (Exception e) { e.printStackTrace(); } //Get a result table from the dbQuery IDataTable dataTable = getResultTable(dbQuery); //Get a print stream to the client PrintWriter out = response.getWriter(); out.println("<CENTER>"); out.println("<TABLE width=\"80%\" cellpadding=\"0\" border=\"2\" cellspacing=\"0\">"); out.println("<TR bgcolor=\"#000000\">"); out.println("<TD align=\"center\">");
out.println("<FONT color=\"ffffff\" face=\"Arial\" size=\"3\"><B>Database
Results</B></FONT>"); out.println("</TD>"); out.println("</TR>");
out.println("<TR bgcolor=\"#ffffff\">"); out.println("<TD align=\"center\">");
out.println( dataTable.toHTMLString() ); out.println("</TABLE>"); out.println(</TD>"); out.println("</TR>");
out.println("</TABLE>"); out.println("</CENTER>"); } /* Implementation of ServletConfig interface */ public ServletContext getServletContext() { return conf.getServletContext(); } public String getInitParameter(String name) { return conf.getInitParameter(name); } public Enumeration getInitParameterNames() { return conf.getInitParameterNames(); } }
Lets compare again our JDBCorbaServlet with SimpleServlet. The log method was added to make up for not extending HttpServlet, this method is implemented to allow you to print your debug/error messages to a log file. The getServletConfig method is implemented for the Servlet interface. This returns the ServletConfig object which was passed in by the servlet runner in the init method which we implemented from the SimpleServlet example. Another method implemented for the Servlet interface is the service method. The service method with a different signature was implemented in the SimpleServlet example. In the SimpleServlet example weÆve implemented the service(HttpServletRequest, HttpServletResponse) method. This time we are required to implement the service(ServletRequest, ServletResponse) method. The classes, ServletRequest, and ServletResponse are superclasses of HttpServletRequest and HttpServletResponse. Fortunately the methods we invoked from HttpServletResponse, particularly getWriter() and setContentType() are defined in the ServletResponse interface. The same is true for the getParameter() method invoked from HttpServletRequest. This method is defined in the ServletRequest interface. So basically all we had to do was change the signature of the service method to take in classes of type ServletRequest, and ServletResponse. The three methods invoked in behalf of the ServletConfig interface are, getServletContext, getInitParameter, and getInitParameterNames, these methods simply passes on the invokation of the corresponding methods to the member variable, conf. The conf variable is an instance of ServletConfig which was set in the init method.

JDBCCorbaServlethas to make itself available for lookup in the CORBA system. This is done in JDBCCORBServletÆs init method. The following lines initializes the server side ORB, and initializes the Basic Object Adapter.


ORB orb = ORB.init(args, null);
BOA boa = orb.BOA_init();
boa.obj_is_ready(this);

See "What is the Basic Object Adapter", at http://www.visigenic.com/techpubs/htmlhelp/vbj30/pg/frames/vbj_5_1.htm for details on the BOA object. The next few lines:

this.BOAThread = new Thread( new BOARunnable(boa) );
this.BOAThread.start();

Starts up a thread that enables the JDBCCorbaServlet instance to begin handling CORBA requests. The BOARunnable class is a member class which basically waits for the incoming requests by invoking boa.impl_is_ready() in itÆs run method. Stopping of the BOAThread instance is done in JDBCCorbaServletÆs destroy method.

Invoking JDBCCorbaServlet
Now that we have our implementation classes, we are ready to do one last build. Once youÆve compiled, you will have to copy the class files directly into the <servlet_runner_home>/servlets directory. The JDBCCorbaServlet should be able to be invoked by either of the two ways:

  • Through the HTTP transport. You can call JDBCCorbaServlet using the same methods as described to invoke SimpleServlet in Tutorial1a. See Invoking SimpleServlet.
  • Through the CORBA transport. You can invoke the getResultTable method from a CORBA client. This will be discussed in detail in later sections.

Loading JDBCCorbaServlet on init

If you recall, the JDBCCorbaServlet makes itself available for CORBA lookup in its init method. The init method is called when the servlet is loaded by the servlet runner. CORBA clients can only get to the CORBA server processes if they are registered for lookup. This means the JDBCCorbaServlet has to be available in the RMI registry before any CORBA clients can look it up. An error will occur if JDBCCorbaServlet is looked up by a CORBA client before it is loaded by the servlet runner. Just having your CORBA servlet available in the servlet runnerÆs servlet directory is not enough to have it available for a CORBA lookup. Unless specified otherwise, a servlet is only loaded by the servlet runner when it is asked for from an HTTP client through the web server. When it is asked for, and if the servlet exists under the servlet runnerÆs servlets directory, and if it has not been loaded yet, then it is loaded, and the init method of the servlet is called. From then on until the web server is stopped, the servlet is available for servicing HTTP and CORBA requests. So, in order for the CORBA servlet to be available through CORBA lookup, it has to be requested through the HTTP transport first. This may not be acceptable. One way to work around this is to specify that the servlet be loaded by the servlet runner when the web server starts up. This is done through the servlet runnerÆs admin. Setting this "load on init" property for a servlet, makes the servlet available for HTTP and CORBA servicing as long as the web server is running. Once the web server is stopped, the destroy method of the servlet is called. For our case, in the destroy method, the database connection is closed and our BOA thread is stopped.

Continue to Part III

Back To Top
Return to Part I
Home Page
Trademarks & Copyright © 1998 INPRISE Corporation.