1. Introduction
Java contains many packages and constructs that facilitate the creation of "distributed" applications --- applications whose constituent classes are running on geographically separated machines. However, the process of learning about these constructs (or just remembering them) and creating the requisite code for a distributed application can be very time-consuming. What's needed is a software infrastructure that assists one in putting classes in a network accessible form and enables the creation of applications that utilize both ``local'' and ``remote'' class instances. Ideally the use of this infrastructure should be as simple as creating and ``publishing'' Web pages. In particular, the use of the infrastructure should not require knowledge of the networking/communications constructs that are are used to implement the infrastructure.

There are a variety of ways that this infrastructure can be created. For example, if the communication between components is constrained to be through stream connections, than one can create a modest infrastructure that possesses these features. The classes in the
cam.netapp [1] [2] package provide such an infrastructure. While it is not difficult to create components that communicate via streams, it's a non-standard programming style. One therefore seeks an infrastructure that allows code components to communicate via standard method calls. One infrastructure that provides this is the Java RMI package . The general idea behind the RMI package is to provide an infrastructure that allows one to create client-server applications. The client classes execute on a local machine and communicate over the network with server classes executing on a remote machine. The client classes have the capability of invoking server class methods using standard method calls. The default use of this package requires one to explicitly create classes that implement either a ``client'' structure or a ``server'' structure. If one has an existing application then there can be a bit of programming to get the application into the appropriate client-server form. In an effort to minimize the amount of programming it takes to get components into a network accessible form, we describe an alternate infrastructure that supports code components that communicate via standard method calls.

The approach is based upon "wrapper" classes. The general idea for using wrapper classes is as follows: Suppose one has an application with the following structure :

In the application, we consider App the "front", or client, and Aclass, the "back" or server class. To keep things simple for now, we assume that App only accesses methods of Aclass. The challenge is to figure out how, with minimal programming, this application can be made to run in a distributed fashion e.g. App executing on one machine and Aclass executing on another.

One means of creating such a distributed application in which App and Aclass are separated is to have App communicate with another class possessing the same interface as Aclass, but whose functionality is provided by a remote instance of Aclass. This remote functionality is obtained through remote method requests sent via a stream connection (implemented using cam.netapp.NetworkConnection) to a class on a remote machine that invokes the appropriate methods of an Aclass instance and then returns the results. Thus a distributed version of the application has the form

Here AclassCI (which stands for Aclass (C)lient (I)mplementation) is the class whose interface is identical to Aclass and communicates with AclassSI (which stands for Aclass (S)erver (I)mplementation). AclassSI contains a local instance of Aclass to obtain its functionality. AclassCI and AclassSI are the wrapper classes utilized in the creation of this distributed implementation. Once the wrapper classes are created for Aclass, identical programming constructs can be use for either local or remote use of an Aclass instance.

The cost of creating a distributed application in this way is the cost of creating the wrapper classes. Fortunately this construction can be automated and the application cam.codegen.CreateCISI does this. Thus, the task of creating a distributed version of an application involves only a modest number of code changes (a constructor change, and a call specifying the address and port of the remote instance), as well as the invocation of the cam.codegen.CreateCISI application.

In the following section we present an extended an example where a distributed version of an application is constructed. In section 3, the nature of the Client Implementation and Server Implementation classes, and "how they work" is discussed. Callbacks from the server class to a client class are possible, and these are described in section 4. In section 5, we discuss how the use of class interfaces can minimize the amount of code that must change when one switches between the a local and a remote class instance. Lastly we discuss the use of "wrappers" with the Java RMI package.

For this work, our primary Java references were the books [3], [4] and [5].