Developing for Deployment


In the real world, virtually all Jini services and clients will be run in multimachine environments. This means that services may be scattered across any number of machines on a network. The downloadable code for these services may be served by any number of HTTP servers, and clients may be connecting to these services from any machine.

But often--whether through convenience or necessity--you need to develop and test your code on only one machine. It's quite easy to run into problems in such cases, simply because by running everything on one machine you're not exercising parts of your code that may cause things to break when the components of your distributed system run on different hosts.

For most Jini development, you will have three Jini-aware applications running: a lookup service, the service you're testing, and a client that uses that service (these applications are in addition to whatever other programs are needed, such as HTTP servers and RMI activation daemons). If all of these programs run on the same machine, and share the same resources (the same CLASSPATH, the same HTTP server, and so on), then potential problems with dynamic class loading or with security may be masked. Developing and testing in such an environment can allow problems to lurk unnoticed in your code.

This is the great danger to only testing locally. The apparent early convenience of taking the easy way out can result in greater headaches down the road. So even though a multimachine environment may require more up-front work, such as starting more HTTP servers, setting security policies, and so on, youll be rewarded for this effort by easier debugging and deployment later. For this reason, its a good idea to get in the habit of thinking about multimachine environments, and even simulating such environments when you develop and test.

Fortunately this simulation is fairly easy to do. There are some simple tips you can follow when you run and test your code to ensure that it will work in such a multi-machine environment, even if youre developing on only one computer. These tips address most of the common problems in a multimachine setting.

These are the guidelines I follow when developing Jini applications, and they're the guidelines that I follow in the Core Jini book. I hope they help. Here are the tips I recommend following when developing.

  • Run a separate HTTP server for each program that provides downloadable code to other programs.
  • Watch out for codebase problems.
  • Always set a SecurityManager.
  • Pay attention to security policies.
  • Take care with CLASSPATH.
  • Consider bundling downloadable code into a JAR file.
Let's look at each of these in turn.

Run Multiple HTTP Servers

    It's a good idea to run a separate HTTP server for each and every program that needs to provide downloadable code to other programs. This strategy allows you to clearly separate the downloadable code for each program from that of every other program. An alternative, like running one HTTP server with a root directory that points to the top of your Java development tree, will almost certainly be more convenient--because all of the classes you write will be accessible anywhere--but will keep you from identifying dependencies in your downloadable code that might keep your applications and services from working if they need to be moved to different machines.

    If you can clearly separate all the downloadable code for a given program on one HTTP server, and then run that program with a codebase property that instructs clients of the program to fetch code only from that HTTP server, then you can tell when you don't have all the necessary code together in one place--the clients will complain that they cannot load certain needed classes.

Watch Out for Codebase Problems
    Recall that the codebase property is set on a server (a program that exports downloadable code) to tell its clients (consumers of that code) where to load the required classes from. See here for an overview of how to use codebase.

    There are a few good general tips you should follow when setting the codebase property, though. First, never use file: URLs. If a server passes a file: URL to a client, the client will try to download any needed code from its own local filesystem. If you're developing and testing both your client and your server on the same machine, your code may work--since the class files will live in the same place for both client and server. But if you ever run the client and server on separate machines that do not share a filesystem, your code will suddenly break.

    Likewise, never use "localhost" in a codebase as a hostname. Localhost is used to refer to the current host, so if a server sets the codebase to a URL containing localhost, the client will evaluate this codebase and attempt to load the code from its system, rather than the server's. Again, this situation may deceptively work if you're testing the client and the server on the same machine, as you're likely to do. But if you use actual hostnames in codebase URLs, and run separate HTTP servers for each, as noted above, then you can identify potential problems in code loading early.

Always Set a Security Manager
    Any Java program that will use downloadable code should set a security manager by calling System.setSecurityManager(). The security manager ensures that any classes that are loaded remotely--through a codebase that is provided via RMI--do not perform any operations they are not allowed to perform.

    If you do not set a security manager, then no classes will be loaded other than those found in the application's CLASSPATH. So, if you only test locally, and do not set a security manager, your code may still work because the classes that would otherwise have to be downloaded may be found in your CLASSPATH. But your application will definitely fail in a multimachine setting.

Pay Attention to Security Policies
    When you run a program with a security manager, the Java 2 security machinery will--by default--use a standard security policy. This standard policy is, unfortunately, often too restrictive to allow Jini applications to run. So in almost all cases you will need to specify a new policy file that allows your program to run.

    You can, for testing purposes, use a very "promiscuous" security policy that allows free and unfettered access to any resources. While such policy files are fine for testing "known" code--meaning code that you have written--it's definitely not suitable for a production environment.

    Here's a simple example of a security policy file that grants all permissions:

        grant {
    	permission java.security.AllPermission;
        };
    
Take Care with CLASSPATH
    As you've probably noticed, most of these development tips have to do with preventing unwanted sharing of resources--primarily, the sharing of code through unanticipated and nonrobust means, such as file: URLs or shared HTTP servers. One other way that code can be shared between two applications--and this is the way that most of us are familiar with--is by running the applications on the same machine and with the same CLASSPATH. If both a client and a server are sharing class files off the disk, then it's virtually impossible to tell what specific classes these programs will need to access remotely. So to prevent unanticipated sharing of class files, you may consider running without any CLASSPATH at all. Instead, try passing the -cp option to the java bytecode interpreter. This option lets you specify a series of directories and JAR files to load class files from. Even if you're developing your client and server on the same machine, you can keep the class files for each in separate directories, unset your CLASSPATH, and use a different -cp argument to the java interpreter for each to ensure that no unwanted crosstalk exists between your applications.

    Furthermore, it's a good habit to get into to provide only those classes the application needs to do its job, rather than all class files "just to be sure." You can start off with the three Jini JAR files in the -cp argument (jini-core.jar, jini-ext.jar, and sun-util.jar), and then copy in your own specific application class files as needed. The compiler is a great help in identifying which class files you need to install, as it will complain if it cannot find needed classes.

    Under no circumstances should you put the -dl JAR files (reggie-dl.jar and so on) from the Jini distribution into your directory of classes--these are meant to be dynamically downloaded from the core Jini services. If you put these in with your application classes, you'll simply be ensuring that you're using the versions of these files that you got with Jini, and not the version that the lookup service expects and tells you to use.

Consider Bundling Downloadable Code into a JAR File
    Perhaps the best way to make sure that you've isolated any unwanted dependencies from your code, and that you're providing exactly and only the code that other programs will need to download, is to create a JAR file that contains the classes that clients will have to download to use your program. This is the strategy taken by the core Jini services--the lookup service, for example, has the classes it needs for its implementation in reggie.jar, and the classes that will be downloaded to clients in reggie-dl.jar. The HTTP server that exports the lookup service's downloadable code has its root directory set to a directory containing reggie-dl.jar. The codebase property for the lookup service provides a URL naming the HTTP server that specifies where clients should download the classes in reggie-dl.jar.

    You should consider breaking your classes into chunks for the implementation and the downloadable components. Creating separate JAR files for each is also handy when you need to move your service, or change where clients download your service's code.

Summary
    These tips are designed to simulate the isolation that would exist between two Jini programs run on different machines--they share no common filesystem and no CLASSPATH. Security must be considered, since programs must go off-machine to access resources. And, in a real deployment setting, you cannot guarantee the existence of one global HTTP server for the network that contains all downloadable class files; instead, you must plan on separating class files for each service, and accessing them through individual HTTP servers.

    Setting up your development environment in this way is a bit of trouble; but in my experience it can pay off in a big way as you begin to develop more complex services and applications.

Go back to Jini Planet

Keith Edwards
kedwards@kedwards.com


Copyright 1999, W. Keith Edwards