Client/Server Programming -- Week 11

Introduction

This week we'll finish covering servlets.

Note that the links from this page are to handouts that will be distributed the night of class.  Only print out those handouts if you could not attend class.

Main topics this week:

Using Multiple Servlets
Servlet Template Engines
Servlets and Other Technologies
Assignment 9-1 Notes
Next Week

Using Multiple Servlets

So far we've looked at using one servlet to create multiple web pages.  We could just as easily using one servlet for each web page.  To do this, we need to organize the servlets into a "web application", a collection of web pages all working toward solving the same problem. 

The web.xml file you created for deploying your servlet describes a single web application.  That web application may contain multiple servlets.  For example:

<web-app>

  <display-name>ExampleServlet</display-name>
  <description>This is an example servlet</description>

  <servlet>
  <servlet-name>ExampleServlet</servlet-name>
  <servlet-class>ExampleServlet</servlet-class>
  </servlet>

  <servlet>
  <servlet-name>AnotherServlet</servlet-name>
  <servlet-class>AnotherServlet</servlet-class>
  </servlet>

</web-app>

ExampleServlet and AnotherServlet are both part of the same web application.  What does that mean, in a practical sense?  All the servlets in a web application share the same HttpSession instance for a client.  Each servlet will be working with the same session data (you'll also hear the term "context" used, as in "all the servlets in the same web application share the same context"). 

This also brings up the fact that the session data might be accessed by more than one thread at a time.  It would seem pretty obvious that the HttpSession object should synchronize itself to provide safe multithreaded access.  However, I have not been able to find anything that says that will always be the case.  To be safe, you should synchronize on HttpSession yourself.

Servlet Template Engines

If you find yourself doing much work in servlets, you will quickly get tired of doing System.out.println statements to output HTML code.  Template engines are a way to avoid doing that, but to still use servlets.  A template engine is a way of writing the HTML separate from the servlet code, but still allowing the servlet to make changes to the HTML as it runs.

There are two basic approaches to templates in servlets:

  1. Write a separate HTML file that includes scripting commands. 
  2. Compile an HTML file into Java code that you call from the servlet.

Write a separate HTML file

Products such as WebMacro and FreeMarker allow you to write an HTML file that includes scripting commands.  These commands are executed by Java code that the servlet calls, so what gets transmitted to the user is simple HTML.  How can these scripting commands allow you to control the HTML from the servlet?  Let's look at a simple example from WebMacro. 

Consider that you have a bulleted list you want to display to the user, but when you write the HTML you don't know how many items will be in the list.  The servlet will provide the text of the items at run-time.  So in the HTML you can use scripting commands to build the list:

<ul>
  #foreach $text in $searchResult
  {
    <li>$text </li>
  }
</ul>

The script variable $searchResult is intended to contain multiple strings.  This script will build a bulleted list that contains the right number of items based on what $searchResult contains.

In your servlet, you would do something like this to populate $searchResults:

WebMacro wm = new WebMacro();

String results = {"Hello", "Goodbye", "See You"};

FastWriter out = new FastWriter(response.getOutputStream ());

Context c = wm.getContext();

c.put("searchResults", results);

Template t = wm.getTemplate("search.view");

t.write(out, context);

The servlet now never needs to worry about HTML, it simply uses the WebMacro objects to process templates.  This takes a bit more design time, because you need to design the templates and consider what data the servlet must provide to the templates.  The end result, however, is much more usable than straight servlets.

Compile HTML into Java Code

The other approach is to compile an HTML file into Java code.  That Java code is then used by the servlet to modify the HTML pages.

The basic idea is that the templates are simple HTML pages that contain a prototype of the web site.  The servlet is able to work with the compiled HTML objects to modify HTML elements based on the ids of the elements.  For example, you could add list items to a bulleted list based on the id of the bulleted list and calling methods designed for the task.

Here is a simple example from an online XMLC tutorial:

<HTML>
<HEAD>
    <TITLE id="title">Hello, World</TITLE>
</HEAD>

<BODY BGCOLOR=#FFFFFF TEXT="#000000">

<H1>Hello, World</H1>

<SPAN id="para1">This is a text of XMLC, showing how one can change text 
located in SPAN tags.</SPAN>  Text outside of those tags and not within 
another tag with an id attribute cannot be changed.

</BODY>
</HTML>

Note the use of the "id" argument to all HTML tags we may want to modify later.  This tells the XMLC compiler to generate appropriate methods for modifying the value contained in that tag.  Any tag with an id will have a corresponding get method when the HTML is compiled, and any use of <SPAN> will have a corresponding set method when the HTML is compiled. 

In your servlet, you would then call methods on the compiled HTML objects to change values based on the id arguments (assuming that we compiled the HTML file into a hello.class file):

hello hello = new hello();         

HTMLTitleElement title = hello.getElementTitle();         
title.setText("Hello, New World!");         

hello.setTextPara1("We changed this!");

out.println( hello.toString() );

The HTML output to the user would be:

<HTML>
<HEAD>
    <TITLE>Hello, New World!</TITLE>
</HEAD>

<BODY BGCOLOR=#FFFFFF TEXT="#000000">

<H1>Hello, World</H1>

We changed this!  Text outside of those tags and not within
another tag with an id attribute cannot be changed.

</BODY>
</HTML>

Both ways of doing templates have their advantages and disadvantages.  Which way you end up using largely depends on who is creating the HTML templates.  If the person creating the templates is not a programmer, then a solution like XMLC would be best.  If the person creating the HTML templates is a programmer, then a WebMacro approach would probably be best. 

Servlets and Other Technologies

A servlet is nothing but a Java class that gets called by the web server.  Like any other Java class it can interact with other client/server technologies.

Servlets & RMI

For example, a servlet can be an RMI client and connect to an RMI server by using Naming.lookup.  The servlet class must have access to the server stub, so you'll need to put the stub.class file into the same directory as your servlet.class file.  Keep in mind that servlets may be multithreaded, so the same servlet may be servicing mutliple users.  This alters RMI usage a bit, in that you need to decide whether to have one main RMI connection to the server, or have one RMI connection per user.  The right answer depends on what you're trying to accomplish.

A servlet may also be able to be an RMI server, but this would be an odd usage of servlets.  You're not exactly sure when a servlet instance is created, so you should not assume that the instance is available.  A servlet could very well be a client that implements a remote callback, since by that point the instance has been created due to a user request on the web server.

Servlets & CORBA

We haven't really talked much about CORBA, because we've been focused on Java technologies.  CORBA is a technology similar to RMI that was developed to be compatible with multiple languages.  So a Java servlet could use CORBA to access a C++ server.  The details of the code are different between RMI and CORBA, but the basic idea remains the same: you ask a naming service for the object you want, and then you call methods on that object. 

Here's a sample of using CORBA from a servlet (try/catch blocks have been removed for simplicity):

ORB orb = ORB.init(null, null);

org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
NameComponent nc = new NameComponent("Multiply", " ");

Multiplication mulRef = MultiplicationHelper.narrow(ncRef.resolve({nc}));

org.omg.CORBA.DoubleHolder z = new DoubleHolder();

mulRef.multiply(5.5, 2.3, z);

out.println("The operation "+ x + " * "+y+ " = "+z.value);

CORBA was designed by a committe, so you should notice immediately that there's a bit more code involved with getting the remote reference to the Multiplication object.   Corba does, however, provide you with call by reference parameters (the DoubleHolder class used to get the result back from the multiply method). 

Assignment 9-1 Notes

Your assignmnet 9-1 requires that your servlet connect to an RMI server.  You'll have to decide if you need only one connection to the RMI server (a simple data member in the servlet), or if you need one connection per user (an attribute stored in the user's session).  For the most part, an RMI connection works much like a database connection (e.g.  you can use one RMI connection for multiple users).  If you need to send a client callback to the server, then you'll want to create an instance of the callback for each user.  Keep in mind, though, that each client callback uses a port number (you will probably need to make it a random port number), which ties up resources.   It's probably best to avoid using client callbacks in servlets. 

Next Week

Next week we will look at Java Server pages.  Your assignment 9-1 is also due next week for full credit.