A roadmap to flexibly configurable apps
Give your client/server programs a variety of user interfaces and access methods
By Seth Cohen, JavaWorld.com, 11/20/99
- Digg
- Reddit
- SlashDot
- Stumble
- del.icio.us
- Technorati
- dzone
Any program that processes user requests can be viewed as a client and a server. The client consists of feature code, UI code,
and a UI layout. The server consists of server code and usually a database. UI code is responsible for acquiring user input
and presenting user output. Feature code is the UI-independent part of the client; it fulfills user-requested transactions
by invoking methods on one or more servers. Server code does the real work, such as managing a bank account, so it is often
called the program's business logic.
You can configure these code pieces -- UI code, UI layout, and so forth -- in different ways across nodes. Figure 1 shows
two common approaches. The upper part of Figure 1 shows one approach: The client code is an app on a desktop machine; the
UI layout is created using Swing; and the server code is part of the app. (The term app is used here to mean an applet or an application.)
The bottom part shows another approach: The UI layout is HTML running in a browser on a desktop machine; the UI code and feature
code are in a servlet running on a Web-server machine; and the server code and database run on a server-application machine.
(Note: The term servlet derives from the fact that it runs in a Web server, not that it contains server code. Although a servlet can contain server
code, its main function is UI-related -- namely, it interfaces to browsers.)

Figure 1. Two common program configurations
When you first start to develop a program, these code pieces often correspond one to one, so there is no strong motivation
to keep them distinct. For instance, developers often intermix UI code and feature code. But as a program evolves, you may
need to configure its pieces in different ways, support multiple UI styles, or provide features that use multiple servers.
So keeping these pieces distinct from day one can provide great benefits down the road. However, that is easier said than
done, for the following reasons:
- A servlet gets and presents UI data using code that's different from a client app's code.
- A client app supports a single user, whereas a servlet supports multiple users, one per servlet thread.
- Extra machinery needs to be written in clients and servers to allow the use of multiple communication protocols.
- The sheer complexity of delivering fast, robust, distributed programs can keep you too busy to attempt to keep the code pieces
distinct.
This article presents guidelines on how to develop distributed programs that are flexibly configurable, fast, and robust.
There are two levels of guidelines. The general guidelines help you effectively organize your program and, as a side effect,
enable you to take full advantage of the Servit package (see Resources). The remaining guidelines explain how to use the Servit package. The main benefits of this server invocation tool are:
- It can start multiple servers and the Remote Method Invocation (RMI) machinery from a single command line.
- It takes care of the detailed machinery of using a server, like locating and instantiating server objects.
- It helps you share feature code among servlets, applets, and applications.
- It lets you define your server configuration through properties set outside your code. For example, during testing you might
want to have an in-process server to facilitate debugging, but then use an RMI server when you release your program.
- It optimizes server-object use by detecting session-stateless servers and by maintaining connection pools within multiple
server-object clients (such as servlets).
- It provides a framework for recovering from network errors.
Developing servers
Granularity of server methods
Accessing a "small" method in a remote server takes milliseconds rather than microseconds. Thus, you should define high-level
server methods. If a single server can perform a user transaction, you should probably create a single-server method to do
the work of this transaction. If the transaction calculates a number of output items, you should define a class that contains
those items and return an object of that class, rather than using individual accessor methods (for example,
getAccountBalance) to retrieve each output item.
Modifiable server state
Servers are usually multithreaded so that multiple client requests can be processed in parallel. If your server code can modify
fields in a server thread, you must synchronize the code sections that use the modifiable state. Obviously, synchronization
reduces the degree of possible client parallelism. So you should define a modifiable server state only when necessary. For
example, a stock price monitor needs to maintain a database of those who register to receive stock price changes. On the other
hand, servers that manipulate client-specific data, like client bank accounts, could often be developed without a modifiable
state.
Normally, you would have to use synchronized methods or blocks to achieve any needed thread synchronization. But if your servers are accessed in process and only from
servlets, a second synchronization mechanism is available to you.
Session state
You need to decide how the session state is managed. You essentially have two choices as to how to organize your server. It
can be
- Session stateless. This kind of server receives the client state only from method arguments and does not cache any data in server fields during
a transaction. Thus, two client transactions executing in parallel can safely use the same server object. (In RMI terms, this
means that all clients can perform operations on the server object returned by
Naming.lookup; the clients do not each acquire a unique server object.)
- Session stateful. This kind of server maintains the client state in the server object's fields. Servit will treat a server as session stateful
if it has a
public Server createSession() method. That method's job is to return a unique server object. Its code can be a simple return new ServerImpl();. The reference object used with createSession is called a factory object.
Loosely speaking, there are two types of session state:
- Internal state. If a server object contains just an internal state, the only issue is the transaction integrity. That is, each client transaction
needs its own server object so that two client transactions executing in parallel do not step on each other's state.
- Identifying state. If a server object contains an identifying state, even a single user could need to access multiple server objects. For example,
a user could need to access two bank account objects, one for checking and one for savings. A client inserts an identifying
state into a server object after constructing it because there is no way to specify an identifying state while the server
object is constructed. The bank account case might incorporate a
setAccount method:
Servit handle = factoryBank.startSession();
Bank acct = (Bank)handle.getServer();
acct.setAccount("Acct#");
Session-stateless servers initialize faster and use fewer resources. If your server can be coded this way, the extra work
of maintaining all the states in arguments and local variables may well be worth it.
Server-access methods
This section describes how to write servers that can be accessed in process, by RMI, and by sockets. For in-process access,
server objects are constructed within the client's Java Virtual Machine. RMI access means that the client can invoke methods
on remote server objects. With a socket-based server, the client and server communicate via application-defined socket messages.
For example, see the code in
Broker*.java in the Servit kit's demo (see
Resources).
There are some general rules that you must follow. First, you must create a public interface named Server.It should contain declarations of all the client-accessible methods of your server. Also, any method that passes or returns
a server object should specify Server (and not ServerImpl). You must also create a public class that implements Server -- this is the class that actually contains your server code. It must be named ServerImpl.
The remaining rules are access-method specific. If you follow all these rules, your server can be accessed all three ways.
- Digg
- Reddit
- SlashDot
- Stumble
- del.icio.us
- Technorati
- dzone