Chapter  23

Creating Web Services in Java

by Mark Wutka


CONTENTS

Several Web servers now allow you to create Java applets that use Web services. This allows you use Java instead of some of the popular languages like C++ and Perl.

If you are developing applications in Java, you can provide Web access to these applications without complicated, native method calls. As the Web servers improve, they will eventually be able to get Java programs from their clients and run them, turning the Web server into a computing server.

Although Web servers are very popular right now, the limitations of the HTTP protocol will become more of a hindrance than a help as the world of distributed objects takes shape. Your application may get away with HTML forms this year but it may need to use CORBA or RMI to communicate with a complex applet next year.

You can design your applications right now with the possibility of CORBA or RMI in the future.

Using Java Objects Instead of CGI

Java objects provide some distinct advantages over CGI-based Web programs. They have less start-up cost, they continue to run, and they can be used on any software platform that supports Java.

Whenever the server gets a request that is handled by a CGI program, it must start the CGI program, which has some fixed amount of overhead. After the CGI program finishes processing a request, it terminates.

If a CGI program needs to maintain information across requests, it must store the information in a database or a file, and read it in again the next time it starts up. These start-up costs can be very high if the CGI program has to establish a session with a database every time.

FastCGI is an improvement over CGI. Instead of running a new program every time, FastCGI programs are always running. When a new request comes in, the Web server passes information to a FastCGI program via an interface protocol. Although this is certainly faster than regular CGI, the communication between the Web server and the FastCGI program can still be rather slow.

The most desirable option so far is to run the request handler as part of the Web server. Some commercial Web servers have hooks that allow you to add request handlers directly to the server. These hooks, or plug-ins, give you the speed you need.

Of course, when you want to run the same service on a different hardware platform or a different operating system, you have to create another version of the plug-in.

Figure 23.1 illustrates the relationship between the Web server and the request handling code for CGI, FastCGI, and plug-in modules.

Figure 23.1 : Traditional Web servers have evolved from simple, slow CGI to high-speed plug-ins.

Java is an ideal platform for using Web services. It runs on multiple platforms, it can be dynamically loaded, and it has a good security system.

In a Java Web server, the objects that handle requests are written entirely in Java. These request-handling objects are called servlets.

Unlike traditional CGI request handlers, servlets do not go away when they finish processing a request. This eliminates the heavy start-up overhead.

Unlike FastCGI, servlets run within the Web server itself, eliminating the communications overhead incurred when the server passes a request to the handler. And unlike plug-ins, servlets can run on any platform that supports Java.

Servlets can also take advantage of Java's security framework, allowing different levels of security for different servlets. For instance, you could define a security policy that allowed a servlet to access only certain directories on your file system. In addition, you could limit other Java features, like network access.

This feature is ideal for Web-space providers who have been unable to provide CGI access to their customers for fear of a malicious CGI program destroying the system. Now they can provide a Java Web server and allow their customers to write servlets that can only access the customer's files, and not those belonging to other customers.

If you get the same old story from your Web provider about why they can't give you CGI, suggest to them that they set up a Java Web server. If they won't, find a provider who will.

The Servlet API

Sun has defined an API for writing servlets and has used the API in the Jeeves server. The core of the API is, of course, the Servlet class.

The two most important methods in the Servlet class are init and service. The init method is called when the servlet is first created and is responsible for initializing the servlet. It is like the init method in the Applet class.

The service method takes two parameters, an object using the ServletRequest interface and an object using the ServletResponse interface. The service is responsible for handling an HTTP request, which is in the ServletRequest object, and returning a response, which is transmitted in the ServletResponse object.

The API also includes ServletStub and ServletContext classes. The ServletStub, like the AppletStub, is not normally used for Servlet programming.

The ServletContext class has information about the server in which the servlet is running, as well as information about other servlets on the server. The Servlet API is discussed in greater detail in Chapter 24, "Writing Web Services in Jeeves."

The Web Server as a Computing Server

Java Web servers open up new possibilities for Web-based services. Since Java can dynamically load new code and execute it, what's to stop you from downloading servlets over the network the same way a browser downloads an applet?

You could set up a high-performance computing Web service, running a Java Web server on a mainframe-class machine. Customers who had to perform computations that might take hours on their own systems could send servlets to your computing server. Your mainframe could crunch their numbers in a shorter time and return the results.

If you have some large, numerical non-Java application, for instance, you could provide access to the application via native methods. A customer would send you a servlet that makes various calls to your numerical application. This is discussed in more detail in Chapter 33, "Web-Enabling Legacy Systems."

Adding Web Access to Your Java Applications

As you write new Java applications, you may want to provide access to these applications via the Web. If you design your application well, adding new interfaces to the application should not be a problem.

As this book has stressed from the beginning, you should strive to separate your application logic from your user interface. Once the interface to the application is well-defined, you can add new ways to access your application without changing the application.

In the case of a Web server, the servlet acts as a proxy for the user interface. In other words, the servlet acts like a user as far as the application is concerned and then passes information back to the Web browser, which implements the real user interface.

Figure 23.2 illustrates the relationship between the servlet, the application, and the user, as compared to a typical user interface.

Figure 23.2 : A servlet can act as a user interface proxy to an application.

The interface between the servlet and the application objects can take a number of different forms. The application could run in the same Java environment as the Web server. The servlets would then make normal Java method calls to the application. Figure 23.3 illustrates this relationship.

Figure 23.3 : A Java application can run in the same Java environment as the Java Web server.

The application and the Web server could also be running on the same physical host but running in separate Java environments. The servlet would need to use RMI, CORBA, or some other form of interprocess communication to access the application, as illustrated in Figure 23.4.

Figure 23.4 : A servlet can use RMI or CORBA to communicate with the real application.

Once a servlet uses RMI or CORBA to communicate with the application, there is no need to keep the application and the Web server on the same physical host. Figure 23.5 illustrates a possible configuration.

Figure 23.5 : The server can access the application across the network.

Note
Two of the factors for deciding whether to put the servlet and the application on two different hosts are the amount of computation performed by the application and the amount of interaction between the application and the servlet.
If the application needs a lot of CPU time, it would be better off on a separate host. If the application and the servlet exchange large volumes of data or pass many messages between them, they would be better off on the same host.

Suppose you want to add Web access to the banking application from Chapter 18, "Using CORBA IDL with Java." You could create a servlet to handle each of the four operations in the banking interface. Each servlet would have a pointer to a banking object, possibly even the same object, if you want to use the banking object as a singleton object.

A banking servlet could create an instance of the banking implementation in its init method:

public void init()
{
     bank = new banking.BankingImpl();
}

Then the service method, which handles incoming requests, would translate the incoming HTTP request to a method call to the BankingImpl object as shown in Listing 23.1.


Listing 23.1  Method Call to BankingImpl Object
public void service(ServletRequest req, ServletResponse resp)
{
// Get the table of request paramaters
     Hashtable params = req.getQueryParameters();

// Get the account number, account password, and account type
     String account = params.get("account");
     String password = params.get("password");
     String accountTypeName = params.get("accountType");

// Convert the account type name into one of the allowable
// account types, or return an error if it's an illegal type
     int accountType;
     if (accountTypeName.equals("checking")) {
          accountType = banking.Account.CHECKING;
     } else if (accountTypeName.equals("savings")) {
          accountType = banking.Account.SAVINGS;
     } else {
          res.writeErrorResponse(SC_BAD_REQUEST,
"Invalid account type");
          return;
     }

// Get the balance using the BankingImpl object
     try {
          int balance = bank.getBalance(
               new Account(account, password, accountType);

// Store the resulting information in the response/
          res.setStatus(SC_OK);
          res.setContentType("text/html");
          res.writeHeaders();

// Get a print stream for writing the HTML for the response
          PrintStream out = new PrintStream(
res.getOutputStream());

// Generate an HTML response containing the balance
          out.println("<HTML><HEAD>");
          out.println("<TITLE>Bank Account Balance</TITLE>");
          out.println("</HEAD><BODY>");
          out.println("<H1>Current Account Balance:</H1>");

// The BankingImpl object stores balances in cents, we have
// to convert it to dollars manually.
          out.println("<P>$"+balance/100+"."+balance%100);
          out.println("</BODY></HTML>");
          out.flush();
     } catch (banking.InvalidAccountException) {
// If there was an invalid account exception, pass this on
// to the client
          res.writeErrorResponse(SC_UNAUTHORIZED,
               "Invalid account");
          return;
     } catch (Exception e) {

// If there was any other exception, something's wrong internally
          res.writeErrorResponse(SC_INTERNAL_SERVER_ERROR,
               "Got error performing request");
          return;
     }
}

As you can see, the servlet makes use of the existing BankingImpl object without actually doing any of the banking operations itself. In this configuration, the BankingImpl object must be running in the same Java environment as the Web server. You could also replace the BankingImpl object with a CORBA or RMI stub, and make remote method invocations to a banking object running somewhere else.

Migrating off the Web Server in the Future

You may be completely focused on writing Web-server-based solutions right now, but that doesn't mean that you will still be doing that a year from now. Web browsers are becoming much more intelligent and some of them are starting to use more protocols than just HTTP.

Netscape, for instance, has announced that a future version of their browser will include a CORBA client. You don't want to write all these applications right now, only to turn around next year and have to rewrite them again from scratch.

The secret to migrating your Web applications is quite simple: Don't write Web applications. Instead, write applications and then provide Web access to them.

That may sound like a contradiction but it is just a reiteration of the separation of user interface from application idea. When you write Web server applications, you tend to think of them only in terms of the Web server.

You may take certain shortcuts that you will regret later or you may intermingle the handling of Web documents with the real function of your application. Don't do that.

First, think of the task your application is really trying to do and write the application without any mention of servlets or HTTP. Finally, when you have a working application, write the servlet or servlets that link the application to the Web.

As always, you will find that it takes more effort to develop a Web service by splitting it into two parts. You will save time in the long run, however, because you can add new ways to access your application without changing the application at all.