You are on page 1of 16

Introduction to Java Servlets

Today we all are aware of the need of creating dynamic web pages i.e the ones which have the capability to change the site
contents according to the time or are able to generate the contents according to the request received by the client. If you like
coding in Java, then you will be happy to know that using Java there also exists a way to generate dynamic web pages and
that way is Java Servlet. But before we move forward with our topic let’s first understand the need for server-side
extensions.
Servlets are the Java programs that runs on the Java-enabled web server or application server. They are used to handle the
request obtained from the web server, process the request, produce the response, then send response back to the web server.
Properties of Servlets :
 Servlets work on the server-side.
 Servlets capable of handling complex request obtained from web server.
Execution of Servlets :
Execution of Servlets involves the six basic steps:
1. The clients send the request to the web server.
2. The web server receives the request.
3. The web server passes the request to the corresponding servlet.
4. The servlet processes the request and generate the response in the form of output.
5. The servlet send the response back to the web server.
6. The web server sends the response back to the client and the client browser displays it on the screen.

A servlet life cycle can be defined as the entire process from its creation till the destruction. The following are the paths
followed by a servlet.

 The servlet is initialized by calling the init() method.


 The servlet calls service() method to process a client's request.
 The servlet is terminated by calling the destroy() method.
 Finally, servlet is garbage collected by the garbage collector of the JVM.
Now let us discuss the life cycle methods in detail.

The init() Method


The init method is called only once. It is called only when the servlet is created, and not called for any user requests
afterwards. So, it is used for one-time initializations, just as with the init method of applets.
The servlet is normally created when a user first invokes a URL corresponding to the servlet, but you can also specify that
the servlet be loaded when the server is first started.
When a user invokes a servlet, a single instance of each servlet gets created, with each user request resulting in a new
thread that is handed off to doGet or doPost as appropriate. The init() method simply creates or loads some data that will be
used throughout the life of the servlet.
The init method definition looks like this −

public void init() throws ServletException {


// Initialization code...
}
The service() Method
The service() method is the main method to perform the actual task. The servlet container (i.e. web server) calls the
service() method to handle requests coming from the client( browsers) and to write the formatted response back to the
client.
Each time the server receives a request for a servlet, the server spawns a new thread and calls service. The service() method
checks the HTTP request type (GET, POST, PUT, DELETE, etc.) and calls doGet, doPost, doPut, doDelete, etc. methods
as appropriate.
Here is the signature of this method −

public void service(ServletRequest request, ServletResponse response)


throws ServletException, IOException {
}

The service () method is called by the container and service method invokes doGet, doPost, doPut, doDelete, etc. methods
as appropriate. So you have nothing to do with service() method but you override either doGet() or doPost() depending on
what type of request you receive from the client.
The doGet() and doPost() are most frequently used methods with in each service request. Here is the signature of these two
methods.

The doGet() Method


A GET request results from a normal request for a URL or from an HTML form that has no METHOD specified and it
should be handled by doGet() method.

public void doGet(HttpServletRequest request, HttpServletResponse response)


throws ServletException, IOException {
// Servlet code
}

The doPost() Method


A POST request results from an HTML form that specifically lists POST as the METHOD and it should be handled by
doPost() method.

public void doPost(HttpServletRequest request, HttpServletResponse response)


throws ServletException, IOException {
// Servlet code
}

The destroy() Method


The destroy() method is called only once at the end of the life cycle of a servlet. This method gives your servlet a chance to
close database connections, halt background threads, write cookie lists or hit counts to disk, and perform other such cleanup
activities.
After the destroy() method is called, the servlet object is marked for garbage collection. The destroy method definition
looks like this −

public void destroy() {


// Finalization code...
}

Architecture Diagram
The following figure depicts a typical servlet life-cycle scenario.

 First the HTTP requests coming to the server are delegated to the servlet container.
 The servlet container loads the servlet before invoking the service() method.
 Then the servlet container handles multiple requests by spawning multiple threads, each thread executing the
service() method of a single instance of the servlet.
Servlet API

1. Servlet API
2. Interfaces in javax.servlet package
3. Classes in javax.servlet package
4. Interfaces in javax.servlet.http package
5. Classes in javax.servlet.http package

The javax.servlet and javax.servlet.http packages represent interfaces and classes for servlet api.

The javax.servlet package contains many interfaces and classes that are used by the servlet or web container. These are not
specific to any protocol.

The javax.servlet.http package contains interfaces and classes that are responsible for http requests only

Multi-tier Applications using JDBC from a Servlet


Servlets are the server-side components that enhance the capability of Java-enabled servers and allow a variety of network-
based services. For example, servlets with the database communication can facilitate solutions for distributed applications.
Typical three-tier architecture for database applications is shown in the Figure. The first tier (client) contains a browser (such
as Netscape or Microsoft IE). The second tier contains the Java-enabled web server and the JDBC driver (for example,
JDBC-ODBC bridge driver). The database is contained in the third tier. Servlets allow dynamic HTML pages to
communicate with the client and database through JDBC.
Writing JDBC/Servlet
Consider the example of the TestDataBaseCon servlet in Program which illustrates the use of the servlet framework in
JDBC/Servlet communication. This servlet makes a connection to the database and returns data in HTML form.
Program Making a database connection using the init() method.
public class TestDataBaseCon extends HttpServlet
{
       Connection connection = null;
       public void init() throws ServletException
      {
              try
              {
                      String host = config.getlnitParameter("host");
                      String uname = config.getlnitParameter("user");
                      String pwd = config.getlnitParameter("Password");
                      Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
                      url = "jdbc:microsoft:SqIServer://"+host+":1433;"+
                        "User = "+uname+ "Password="+pwd;
                      con= DriverManager.getConnection(url);
               }
                      catch(ClassNotFoundException e)
                           {
                                 System.out.println("problem in loading the class:");
                           }
                      catch(SQLException e)
                          {
                                   System.out.println("Sql error");
                           }
       }
}
Servlets are built by extending a basic Servlet class and overriding some of the methods to deal with incoming client
requests. TestDataBaseCon extends the HttpServlet class that provides most of the capabilities needed to serve client
requests. After the servlet is loaded, three main methods are involved in the life-cycle of a servlet.

Initialization
On receiving the request from the client, the servlet engine (container) checks whether it is the first request to the servlet. If it
is the first request, then the servlet engine instantiates the servlet and initializes it by sending the initialization method call
that is, init(). The code related to database connections is placed in the init() method.

Service calls
After initialization, servlets are capable of handling many requests, by means of a single servlet instance. Each client request
generates one service call (that is, thread to provide service) and these calls can be concurrent. In a  JDBC servlet, the service
calls process incoming name value pair information from a browser, and return raw data or HTML pages (dynamic or static)
as output. Note that in the name-value pair, the name indicates the parameter name and value indicates the value(s) of that
parameter.
Servlet termination
The destroy method provided by the HttpServlet class destroys the servlet and logs the destruction. This method is
overridden to destroy the resources used in the servlet. The destroy method should undo any initialization work that is done
in the init() method. In the TestDataBaseCon example of Program, the destroy method is the used for this purpose.
Program Using the destroy method for servlet termination.
public class TestDataBaseCon extends
{
        Connection connection =  null;
          // init() method
         // service() method
       public void destroy()
       {
                   // Close the connection and allow it to be garbage collected
                   connection.close();
                connection =  null;
       }
}
A server calls the destroy method after all service calls have been completed, or a server specific number of seconds have
passed without there being any request from the client. If the servlet handles any long-running operations, the service
methods might still be running when the server calls the destroy method. Hence, it must be ensured that those threads
complete their function. The destroy method described in Program expects all client interactions to be completed when it is
called, because the servlet has no long-running operations.

A sample JDBC/Servlet application


Program gives a simple JDBC/Servlet application .
Program Illustration of initializing, implementing and destroying a servlet.
public class TestDataBaseCon extends HttpServlet
{
  //declaration of the connection
  private Connection con;
  public void init(ServletConfig conf) throws ServletException
 {
           // initializing the servlet
          super.init( conf);
           try
          {
               String host = config.getlnitParameter("host");
               String dsource = config.getlnitParameter("dsource");
               String uname = config.getlnitParameter("uname");
               String pwd = config.getlnitParameter("pwd");
                // loading the driver class and registering to DriverManager
               Class.forName(" oracle.jdbc.driver.OracleDriver");
                 //getting connection
               ur1="jdbc:oracle:thin:@"+host+":1521:"+dsource;
               con =DriverManager.getConnection( url,uname,pwd);
          }
                catch (ClassNotFoundExcepticn e)
               {
                       System.out.pritnln ("Driver class is not found:" + e.getMessage());
                }
                catch (SQLException se)
                {
                       System.err.println("Problem in making the connection:" + se);
                 }
    }
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException
{
               res.setContent Type("text/html");
    try
 {
            PrintWriter pout = res.getWriter();
            pout.println("<html>");
            pout.println("<head>");
            pout.println("<title>Sample JDBC Servlet Demo</title>");
            pout.println ("<lhead>");
            pout.println("<body >");
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery("select * from Emp_info");
             pout.println("Getting the values from the Oracle Table")
             while(rs.next())
             {
                         pout.println(rs.getString(1)+" ");
                         pout.println (rs.getString(2));
               }
                          pout.println();
                          rs.c1ose();
                          stmt.c1ose();
   }
             catch(SQLException e)
          {
                        // SqlException describes problem with connection
                         pout.println("An SQL Exception was thrown.");
         }
             catch(IOException e)
            {
                        pout.println("An IOException was thrown.");
              }
             pout.println("</body>");
             pout.println ("</html>");
   }
             //closing the connection to the database
             public void destroy()
            {
                   con.c1ose();
            }
}

Networking and Remote Method Invocation:

The term network programming refers to writing programs that execute across multiple devices (computers), in which the
devices are all connected to each other using a network.
The java.net package of the J2SE APIs contains a collection of classes and interfaces that provide the low-level
communication details, allowing you to write programs that focus on solving the problem at hand.
The java.net package provides support for the two common network protocols −

 TCP − TCP stands for Transmission Control Protocol, which allows for reliable communication between two
applications. TCP is typically used over the Internet Protocol, which is referred to as TCP/IP.
 UDP − UDP stands for User Datagram Protocol, a connection-less protocol that allows for packets of data to be
transmitted between applications.
This chapter gives a good understanding on the following two subjects −

 Socket Programming − This is the most widely used concept in Networking and it has been explained in very
detail.
 URL Processing − This would be covered separately. Click here to learn about URL Processing in Java language.

Socket Programming
Sockets provide the communication mechanism between two computers using TCP. A client program creates a socket on
its end of the communication and attempts to connect that socket to a server.
When the connection is made, the server creates a socket object on its end of the communication. The client and the server
can now communicate by writing to and reading from the socket.
The java.net.Socket class represents a socket, and the java.net.ServerSocket class provides a mechanism for the server
program to listen for clients and establish connections with them.
The following steps occur when establishing a TCP connection between two computers using sockets −
 The server instantiates a ServerSocket object, denoting which port number communication is to occur on.
 The server invokes the accept() method of the ServerSocket class. This method waits until a client connects to the
server on the given port.
 After the server is waiting, a client instantiates a Socket object, specifying the server name and the port number to
connect to.
 The constructor of the Socket class attempts to connect the client to the specified server and the port number. If
communication is established, the client now has a Socket object capable of communicating with the server.
 On the server side, the accept() method returns a reference to a new socket on the server that is connected to the
client's socket.
After the connections are established, communication can occur using I/O streams. Each socket has both an OutputStream
and an InputStream. The client's OutputStream is connected to the server's InputStream, and the client's InputStream is
connected to the server's OutputStream.
TCP is a two-way communication protocol, hence data can be sent across both streams at the same time. Following are the
useful classes providing complete set of methods to implement sockets.

ServerSocket Class Methods


The java.net.ServerSocket class is used by server applications to obtain a port and listen for client requests.
The ServerSocket class has four constructors −

Sr.No Method & Description


.

public ServerSocket(int port) throws IOException


1
Attempts to create a server socket bound to the specified port. An exception occurs if the
port is already bound by another application.

public ServerSocket(int port, int backlog) throws IOException


2
Similar to the previous constructor, the backlog parameter specifies how many incoming
clients to store in a wait queue.

public ServerSocket(int port, int backlog, InetAddress address) throws IOException


3 Similar to the previous constructor, the InetAddress parameter specifies the local IP address
to bind to. The InetAddress is used for servers that may have multiple IP addresses,
allowing the server to specify which of its IP addresses to accept client requests on.

public ServerSocket() throws IOException


4
Creates an unbound server socket. When using this constructor, use the bind() method
when you are ready to bind the server socket.

If the ServerSocket constructor does not throw an exception, it means that your application has successfully bound to the
specified port and is ready for client requests.
Following are some of the common methods of the ServerSocket class −

Sr.No Method & Description


.

1
public int getLocalPort()
Returns the port that the server socket is listening on. This method is useful if you passed in
0 as the port number in a constructor and let the server find a port for you.

public Socket accept() throws IOException


2 Waits for an incoming client. This method blocks until either a client connects to the server
on the specified port or the socket times out, assuming that the time-out value has been set
using the setSoTimeout() method. Otherwise, this method blocks indefinitely.

3 public void setSoTimeout(int timeout)


Sets the time-out value for how long the server socket waits for a client during the accept().

public void bind(SocketAddress host, int backlog)


4
Binds the socket to the specified server and port in the SocketAddress object. Use this
method if you have instantiated the ServerSocket using the no-argument constructor.

When the ServerSocket invokes accept(), the method does not return until a client connects. After a client does connect, the
ServerSocket creates a new Socket on an unspecified port and returns a reference to this new Socket. A TCP connection
now exists between the client and the server, and communication can begin.

Socket Class Methods


The java.net.Socket class represents the socket that both the client and the server use to communicate with each other. The
client obtains a Socket object by instantiating one, whereas the server obtains a Socket object from the return value of the
accept() method.
The Socket class has five constructors that a client uses to connect to a server −

Sr.No Method & Description


.

public Socket(String host, int port) throws UnknownHostException, IOException.


1
This method attempts to connect to the specified server at the specified port. If this
constructor does not throw an exception, the connection is successful and the client is
connected to the server.

public Socket(InetAddress host, int port) throws IOException


2
This method is identical to the previous constructor, except that the host is denoted by an
InetAddress object.

public Socket(String host, int port, InetAddress localAddress, int localPort) throws
3 IOException.
Connects to the specified host and port, creating a socket on the local host at the specified
address and port.

public Socket(InetAddress host, int port, InetAddress localAddress, int localPort)


4 throws IOException.
This method is identical to the previous constructor, except that the host is denoted by an
InetAddress object instead of a String.
5 public Socket()
Creates an unconnected socket. Use the connect() method to connect this socket to a server.

When the Socket constructor returns, it does not simply instantiate a Socket object but it actually attempts to connect to the
specified server and port.
Some methods of interest in the Socket class are listed here. Notice that both the client and the server have a Socket object,
so these methods can be invoked by both the client and the server.

Sr.No Method & Description


.

public void connect(SocketAddress host, int timeout) throws IOException


1
This method connects the socket to the specified host. This method is needed only when
you instantiate the Socket using the no-argument constructor.

2 public InetAddress getInetAddress()


This method returns the address of the other computer that this socket is connected to.

3 public int getPort()


Returns the port the socket is bound to on the remote machine.

4 public int getLocalPort()


Returns the port the socket is bound to on the local machine.

5 public SocketAddress getRemoteSocketAddress()


Returns the address of the remote socket.

public InputStream getInputStream() throws IOException


6
Returns the input stream of the socket. The input stream is connected to the output stream
of the remote socket.

public OutputStream getOutputStream() throws IOException


7
Returns the output stream of the socket. The output stream is connected to the input stream
of the remote socket.

public void close() throws IOException


8
Closes the socket, which makes this Socket object no longer capable of connecting again to
any server.

InetAddress Class Methods


This class represents an Internet Protocol (IP) address. Here are following usefull methods which you would need while
doing socket programming −
Sr.No. Method & Description

1 static InetAddress getByAddress(byte[] addr)


Returns an InetAddress object given the raw IP address.

2 static InetAddress getByAddress(String host, byte[] addr)


Creates an InetAddress based on the provided host name and IP address.

3 static InetAddress getByName(String host)


Determines the IP address of a host, given the host's name.

4 String getHostAddress()
Returns the IP address string in textual presentation.

5 String getHostName()
Gets the host name for this IP address.

6 static InetAddress InetAddress getLocalHost()


Returns the local host.

7 String toString()
Converts this IP address to a String.

Understanding ports

port

On computer and telecommunication devices, a port (noun) is generally a specific place for being physically connected to

some other device, usually with a socket and plug of some kind. Typically, a personal computer is provided with one or

more serial ports and usually one parallel port. The serial port supports sequential, one bit-at-a-time transmission to

peripheral devices such as scanners and the parallel port supports multiple-bit-at-a-time transmission to devices such as

printers.

2) In programming, a port (noun) is a "logical connection place" and specifically, using the Internet's protocol, TCP/IP, the

way a client program specifies a particular server program on a computer in a network. Higher-level applications that use

TCP/IP such as the Web protocol, Hypertext Transfer Protocol, have ports with preassigned numbers. These are known as

"well-known ports" that have been assigned by the Internet Assigned Numbers Authority (IANA). Other application

processes are given port numbers dynamically for each connection. When a service (server program) initially is started, it is
said to bind to its designated port number. As any client program wants to use that server, it also must request to bind to the

designated port number.

Port numbers are from 0 to 65535. Ports 0 to 1024 are reserved for use by certain privileged services. For the HTTP service,

port 80 is defined as a default and it does not have to be specified in the Uniform Resource Locator (URL).

3) In programming, to port (verb) is to move an application program from an operating system environment in which it was

developed to another operating system environment so it can be run there. Porting implies some work, but not nearly as

much as redeveloping the program in the new environment. Open standard programming interface (such as those specified in

X/Open's 1170 C language specification and Sun Microsystem's Java programming language) minimize or eliminate the

work required to port a program.

RMI (Remote Method Invocation)

The RMI (Remote Method Invocation) is an API that provides a mechanism to create distributed application in java. The
RMI allows an object to invoke methods on an object running in another JVM.

The RMI provides remote communication between the applications using two objects stub and skeleton.

Understanding stub and skeleton

RMI uses stub and skeleton object for communication with the remote object.

A remote object is an object whose method can be invoked from another JVM. Let's understand the stub and skeleton
objects:

stub

The stub is an object, acts as a gateway for the client side. All the outgoing requests are routed through it. It resides at the
client side and represents the remote object. When the caller invokes method on the stub object, it does the following tasks:

1. It initiates a connection with remote Virtual Machine (JVM),


2. It writes and transmits (marshals) the parameters to the remote Virtual Machine (JVM),
3. It waits for the result
4. It reads (unmarshals) the return value or exception, and
5. It finally, returns the value to the caller.

skeleton

The skeleton is an object, acts as a gateway for the server side object. All the incoming requests are routed through it. When
the skeleton receives the incoming request, it does the following tasks:

1. It reads the parameter for the remote method


2. It invokes the method on the actual remote object, and
3. It writes and transmits (marshals) the result to the caller.

RMI Architecture Java


In RMI, the client and server do not communicate directly; instead communicates through stub and skeleton (a
special concept of RMI and this is how designers achieved distributed computing in Java). They are nothing but
special programs generated by RMI compiler. They can be treated as proxies for the client and server. Stub
program resides on client side and skeleton program resides on server. That is, the client sends a method call with
appropriate parameters to stub. The stub in turn calls the skeleton on the server. The skeleton passes the stub
request to the server to execute the remote method. The return value of the method is sent to the skeleton by the
server. The skeleton, as you expect, sends back to the stub. Finally the return value reaches client through stub.

. Application Layer
This layer is nothing but the actual systems (client and server) involved in communication. A client Java program
communicates with the other Java program on the server side. RMI is nothing but a communication between two JVMs
placed on different systems.

 Proxy Layer
The proxy layer consists of proxies (named as stub and skeleton by designers) for client and server. Stub is client side
proxy and Skeleton is server side proxy. Stub and skeleton, as many people confuse, are not separate systems but they are
after all programs placed on client and server. The stub and skeleton are not hard coded by the Programmer but they are
generated by RMI compiler (this is shown in execution part later). Stub is placed on client side and skeleton is placed on
server side. The client server communication goes through these proxies. Client sends its request of method invocation (to be
executed on remote server) to stub. Stub inturn sends the request to skeleton. Skeleton passes the request to the server
program. Server executes the method and sends the return value to the skeleton (to route to client). Skeleton sends to stub
and stub to client program.
Marshaling and Unmarshaling
One more job of proxies is marshaling and unmarshaling. Marshaling is nothing but converting data into a special format
suitable to pass through the distributed environment without loosing object persistence. For this reason, the RMI
mechanism implicitly serialize the objects involved in communication. The stub marshals the data of client and then sends to
the skeleton. As the format is not understood by the server program, it is unmarshaled by the skeleton into the original
format and passed to server. Similarly from server to client also.
A marshal stream includes a stream of objects that are used to transport parameters, exceptions, and errors needed for these
streams for communicating with each other. Marshaling and unmarshaling are done by the RMI runtime mechanism
implicitly without any programmers extra coding.

3. Remote Reference Layer


Proxies are implicitly connected to RMI mechanism through Remote reference layer, the layer responsible for object
communication and transfer of objects between client and server. It is responsible for dealing with semantics of remote
invocations and implementation – specific tasks with remote objects. In this layer, actual implementation of communication
protocols is handled.

Transport layer does not exist separately but is a part of Remote reference layer. Transport layer is responsible for actually
setting up connections and handling the transport of data from one machine to another. It can be modified to handle
encrypted streams, compression algorithms and a number of other security/performance related enhancements.
The marshaled stream is passed to RRL(Remote Reference Layer). Task of RRL is to identify the host, that is, remote
machine. The marshaled stream is passed to Transport layer which performs routing.

Implementing a Remote Interface

This section discusses the task of implementing a class for the compute engine. In general, a class that implements a remote
interface should at least do the following:

 Declare the remote interfaces being implemented


 Define the constructor for each remote object
 Provide an implementation for each remote method in the remote interfaces

An RMI server program needs to create the initial remote objects and export them to the RMI runtime, which makes them
available to receive incoming remote invocations. This setup procedure can be either encapsulated in a method of the remote
object implementation class itself or included in another class entirely. The setup procedure should do the following:

 Create and install a security manager


 Create and export one or more remote objects
 Register at least one remote object with the RMI registry (or with another naming service, such as a service
accessible through the Java Naming and Directory Interface) for bootstrapping purposes

The complete implementation of the compute engine follows. The engine.ComputeEngine class implements the remote
interface Compute and also includes the main method for setting up the compute engine. Here is the source code for
the ComputeEngine class:

package engine;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import compute.Compute;
import compute.Task;

public class ComputeEngine implements Compute {

public ComputeEngine() {
super();
}

public <T> T executeTask(Task<T> t) {


return t.execute();
}

public static void main(String[] args) {


if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
try {
String name = "Compute";
Compute engine = new ComputeEngine();
Compute stub =
(Compute) UnicastRemoteObject.exportObject(engine, 0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind(name, stub);
System.out.println("ComputeEngine bound");
} catch (Exception e) {
System.err.println("ComputeEngine exception:");
e.printStackTrace();
}
}
}

The following sections discuss each component of the compute engine implementation.

Declaring the Remote Interfaces Being Implemented

The implementation class for the compute engine is declared as follows:

public class ComputeEngine implements Compute

This declaration states that the class implements the Compute remote interface and therefore can be used for a remote object.

The ComputeEngine class defines a remote object implementation class that implements a single remote interface and no
other interfaces. The ComputeEngine class also contains two executable program elements that can only be invoked locally.
The first of these elements is a constructor for ComputeEngine instances. The second of these elements is a main method
that is used to create a ComputeEngine instance and make it available to clients.

Defining the Constructor for the Remote Object

The ComputeEngine class has a single constructor that takes no arguments. The code for the constructor is as follows:

public ComputeEngine() {
super();
}

This constructor just invokes the superclass constructor, which is the no-argument constructor of the Object class. Although
the superclass constructor gets invoked even if omitted from the ComputeEngine constructor, it is included for clarity.

Providing Implementations for Each Remote Method

The class for a remote object provides implementations for each remote method specified in the remote interfaces.
The Compute interface contains a single remote method, executeTask, which is implemented as follows:

public <T> T executeTask(Task<T> t) {


return t.execute();
}

This method implements the protocol between the ComputeEngine remote object and its clients. Each client provides
the ComputeEngine with a Task object that has a particular implementation of the Task interface's execute method.
The ComputeEngine executes each client's task and returns the result of the task's execute method directly to the client.

Passing Objects in RMI

Arguments to or return values from remote methods can be of almost any type, including local objects, remote objects, and
primitive data types. More precisely, any entity of any type can be passed to or from a remote method as long as the entity is
an instance of a type that is a primitive data type, a remote object, or a serializable object, which means that it implements
the interface java.io.Serializable.

Some object types do not meet any of these criteria and thus cannot be passed to or returned from a remote method. Most of
these objects, such as threads or file descriptors, encapsulate information that makes sense only within a single address
space. Many of the core classes, including the classes in the packages java.lang and java.util, implement
the Serializable interface.

The rules governing how arguments and return values are passed are as follows:

 Remote objects are essentially passed by reference. A remote object reference is a stub, which is a client-side
proxy that implements the complete set of remote interfaces that the remote object implements.
 Local objects are passed by copy, using object serialization. By default, all fields are copied except fields that are
marked static or transient. Default serialization behavior can be overridden on a class-by-class basis.

Passing a remote object by reference means that any changes made to the state of the object by remote method invocations
are reflected in the original remote object. When a remote object is passed, only those interfaces that are remote interfaces
are available to the receiver. Any methods defined in the implementation class or defined in non-remote interfaces
implemented by the class are not available to that receiver.

For example, if you were to pass a reference to an instance of the ComputeEngine class, the receiver would have access only
to the compute engine's executeTask method. That receiver would not see the ComputeEngine constructor, its main method,
or its implementation of any methods of java.lang.Object.

In the parameters and return values of remote method invocations, objects that are not remote objects are passed by value.
Thus, a copy of the object is created in the receiving Java virtual machine. Any changes to the object's state by the receiver
are reflected only in the receiver's copy, not in the sender's original instance. Any changes to the object's state by the sender
are reflected only in the sender's original instance, not in the receiver's copy.

Implementing the Server's main Method

The most complex method of the ComputeEngine implementation is the main method. The main method is used to start


the ComputeEngine and therefore needs to do the necessary initialization and housekeeping to prepare the server to accept
calls from clients. This method is not a remote method, which means that it cannot be invoked from a different Java virtual
machine. Because the main method is declared static, the method is not associated with an object at all but rather with the
class ComputeEngine.

Creating and Installing a Security Manager

The main method's first task is to create and install a security manager, which protects access to system resources from
untrusted downloaded code running within the Java virtual machine. A security manager determines whether downloaded
code has access to the local file system or can perform any other privileged operations.

If an RMI program does not install a security manager, RMI will not download classes (other than from the local class path)
for objects received as arguments or return values of remote method invocations. This restriction ensures that the operations
performed by downloaded code are subject to a security policy.

Here's the code that creates and installs a security manager:

if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}

Making the Remote Object Available to Clients

Next, the main method creates an instance of ComputeEngine and exports it to the RMI runtime with the following
statements:

Compute engine = new ComputeEngine();


Compute stub =
(Compute) UnicastRemoteObject.exportObject(engine, 0);

The static UnicastRemoteObject.exportObject method exports the supplied remote object so that it can receive invocations
of its remote methods from remote clients. The second argument, an int, specifies which TCP port to use to listen for
incoming remote invocation requests for the object. It is common to use the value zero, which specifies the use of an
anonymous port. The actual port will then be chosen at runtime by RMI or the underlying operating system. However, a non-
zero value can also be used to specify a specific port to use for listening. Once the exportObject invocation has returned
successfully, the ComputeEngine remote object is ready to process incoming remote invocations.

The exportObject method returns a stub for the exported remote object. Note that the type of the variable stub must
be Compute, not ComputeEngine, because the stub for a remote object only implements the remote interfaces that the
exported remote object implements.

The exportObject method declares that it can throw a RemoteException, which is a checked exception type.
The main method handles this exception with its try/catch block. If the exception were not handled in this
way, RemoteException would have to be declared in the throws clause of the main method. An attempt to export a remote
object can throw a RemoteException if the necessary communication resources are not available, such as if the requested
port is bound for some other purpose.

Before a client can invoke a method on a remote object, it must first obtain a reference to the remote object. Obtaining a
reference can be done in the same way that any other object reference is obtained in a program, such as by getting the
reference as part of the return value of a method or as part of a data structure that contains such a reference.

The system provides a particular type of remote object, the RMI registry, for finding references to other remote objects. The
RMI registry is a simple remote object naming service that enables clients to obtain a reference to a remote object by name.
The registry is typically only used to locate the first remote object that an RMI client needs to use. That first remote object
might then provide support for finding other objects.

The java.rmi.registry.Registry remote interface is the API for binding (or registering) and looking up remote objects in the
registry. The java.rmi.registry.LocateRegistry class provides static methods for synthesizing a remote reference to a registry
at a particular network address (host and port). These methods create the remote reference object containing the specified
network address without performing any remote communication. LocateRegistry also provides static methods for creating a
new registry in the current Java virtual machine, although this example does not use those methods. Once a remote object is
registered with an RMI registry on the local host, clients on any host can look up the remote object by name, obtain its
reference, and then invoke remote methods on the object. The registry can be shared by all servers running on a host, or an
individual server process can create and use its own registry.

The ComputeEngine class creates a name for the object with the following statement:

String name = "Compute";

The code then adds the name to the RMI registry running on the server. This step is done later with the following statements:

Registry registry = LocateRegistry.getRegistry();


registry.rebind(name, stub);

This rebind invocation makes a remote call to the RMI registry on the local host. Like any remote call, this call can result in
a RemoteException being thrown, which is handled by the catch block at the end of the main method.

Note the following about the Registry.rebind invocation:

 The no-argument overload of LocateRegistry.getRegistry synthesizes a reference to a registry on the local host and
on the default registry port, 1099. You must use an overload that has an int parameter if the registry is created on a
port other than 1099.
 When a remote invocation on the registry is made, a stub for the remote object is passed instead of a copy of the
remote object itself. Remote implementation objects, such as instances of ComputeEngine, never leave the Java
virtual machine in which they were created. Thus, when a client performs a lookup in a server's remote object
registry, a copy of the stub is returned. Remote objects in such cases are thus effectively passed by (remote)
reference rather than by value.
 For security reasons, an application can only bind, unbind, or rebind remote object references with a registry
running on the same host. This restriction prevents a remote client from removing or overwriting any of the entries
in a server's registry. A lookup, however, can be requested from any host, local or remote.

You might also like