Chapter 7. Servers I—unicast servers

  • Introduction—Writing the server—Implementing remote interface methods—Threads, sockets, and ports—the Unreferenced interface—Building the server—Foundation classes—Serialization—Alternative server classes—Exercises

In this chapter

The simplest form of RMI server is the “unicast” server. This chapter describes how to write and build such servers. Along the way, it provides general information about implementing remote interfaces, sharing sockets and ports, and using the Unreferenced interface. Finally, we discuss the classes RemoteObject and RemoteServer—foundation classes applicable to all RMI servers—in §7.8. For more advanced server types, see Chapter 10, Chapter 14, and Chapter 17.

Introduction

In object-oriented programming, any object can be considered to be a server. In RMI, remote objects are remote servers. An RMI server is a remote object which:

  • implements a remote interface

  • is exported to the RMI system.

RMI provides several base classes which can be used to define server classes. These classes form an inheritance chain shown in Figure 7.1.

Foundation class hierarchy

Figure 7.1. Foundation class hierarchy

RemoteObject provides basic remote object semantics suitable for servers and stubs. RemoteServer provides getClientHost and getLog methods for use by servers. UnicastRemoteObject supports simple transient point-to-point RMI servers.

A unicast remote object is a server object whose characteristics are as follows:[1]

  • references—remote stubs—to such objects are valid only for, at most, the life of the process that creates the remote object

  • communication with the remote object uses a TCP transport

  • invocations, parameters, and results use a stream protocol for communicating between client and server.

“Unicast” indicates point-to-point communications (as opposed to broadcasting or multicasting: these advanced topics are discussed in Chapter 17). A unicast remote object is a TCP/IP server which listens at a TCP/IP port.

Writing the server

As we saw above, writing an RMI server is a matter of defining a class, exporting it when constructed, and implementing one or more remote interfaces. If necessary, you can also make it obey appropriate remote object semantics, discussed in §7.8.3.

There are essentially three ways to write a server using the UnicastRemoteObject class. We will illustrate these, in each case implementing the remote interface of Example 7.1.

Example 7.1. Remote interface to be implemented

import java.rmi.*;
import java.rmi.server.*;

// The remote interface to be implemented by the server
interface MyRemoteInterface extends Remote
{
       void  remoteMethod() throws RemoteException;
}

Extend UnicastRemoteObject

Remote classes can be defined by extending UnicastRemoteObject, as shown in Example 7.2.

Example 7.2. Server implementation extending UnicastRemoteObject

class ExtendedUnicastServer extends UnicastRemoteObject
      implements MyRemoteInterface
{
      public ExtendedUnicastServer() throws RemoteException
      {
             // auto-export happens here
             super();
      }

      public void  remoteMethod() throws RemoteException
      {
      }
}

Objects of such classes are automatically exported on construction as transient point-to-point servers.

When a UnicastRemoteObject is constructed, it is automatically exported—registered with the RMI system and made to listen to a TCP port. The various constructors for UnicastRemoteObject allow derived classes to choose between (a) exporting on a default port chosen at runtime, (b) exporting on a specified port, and (c) exporting on a specified port with specified client and server socket factories (discussed in Chapter 11).

Because the automatic export step occurs on construction, all the protected constructors of UnicastRemoteObject throw RemoteException. By the rules of Java, this means that if your server class extends UnicastRemoteObject, its constructors must also throw RemoteException.[2] See also Exercise 1 at the end of this chapter.

A server class which extends UnicastRemoteObject inherits remote object semantics from RemoteObject, and cloning and serialization behaviour from UnicastRemoteObject. UnicastRemoteObject implements the Object.clone method by cloning the entire state of the remote object and exports it as another listener on the same port.[3] However, the class does not implement the Cloneable interface—this is left up to derived classes. Therefore, a derived class may choose for itself whether or not it is cloneable, by implementing or not implementing Cloneable. UnicastRemoteObject has special behaviour under serialization, discussed in §7.9.

Extend RemoteServer or RemoteObject

Remote classes can be defined by extending RemoteServer or RemoteObject, as shown in Example 7.3 and Example 7.4.

Example 7.3. Server implementation extending RemoteServer

class ExtendedRemoteServer extends RemoteServer
      implements MyRemoteInterface
{
      public void  remoteMethod() throws RemoteException
      {
      }
}

Example 7.4. Server implementation extending RemoteObject

class ExtendedRemoteObject extends RemoteObject
      implements MyRemoteInterface
{
      public void  remoteMethod() throws RemoteException
      {
      }
}

In this case, your server inherits remote object semantics from RemoteObject. Its behaviour under cloning and non-RMI serialization is up to you. Other than inheriting remote object semantics and various public static methods, such a server is identical to a server constructed as discussed in the following section.

As RemoteServer only exports static methods, there is little to choose between extending RemoteServer or RemoteObject.

Extend another class

Remote classes can be defined by extending none of the base classes discussed above: they can extend any other class, or no class (i.e. it can implicitly extend java.lang.Object), as shown in Example 7.5.

Example 7.5. Server implementation extending java.lang.Object

public class ExtendedRemoteServer /*extends Object*/
       implements MyRemoteInterface
{
       public void  remoteMethod() throws RemoteException
       {
       }
}

If your remote class doesn't directly or indirectly extend RemoteObject, its remote object semantics and its behaviour under cloning and non-RMI serialization are all up to you.

Exporting

We saw above that a remote object which extends UnicastRemoteObject is automatically exported on construction. By contrast, a remote object which does not extend UnicastRemoteObject must be explicitly exported by one of the static UnicastRemoteObject.exportObject methods. The object is exported as a transient point-to-point server.

Such an object may export itself. Alternatively, it can be exported by whoever constructs it, or can be exported by some (local) recipient of the constructed object. These alternatives allow the interesting, possibly very confusing, option of defining a class with both local and remote behaviour. If an object of such a class is exported, it is available for RMI and local use; otherwise it functions purely locally.

UnicastRemoteObject provides several static exportObject methods, corresponding to its various constructors used by remote objects not derived from UnicastRemoteObject. The various forms of this method allow derived classes to choose between (a) exporting on a default port chosen at runtime, (b) exporting on a specified port, and (c) exporting on a specified port with specified client and server socket factories (discussed in Chapter 11).

Unexporting

A remote object is automatically unexported—de-registered from the RMI system—when it is garbage-collected locally. Local garbage collection can only occur after any clients of the remote object have had their remote references to it garbage-collected in their own local JVMs—an event which is notified by RMI's Distributed Garbage Collection (DGC) subsystem. This topic is discussed in §18.2.

When using a shared TCP port, the listening port is closed when all remote objects exported via that port have been unexported.

Normally it is safest to allow remote servers to be unexported automatically, for reasons discussed in §7.6. However, conditions can arise in which a remote object must be forcibly unexported regardless of the consequences to clients. For this purpose, UnicastRemoteObject provides a static unexportObject method, allowing a remote object to be “manually” unexported from the RMI system. (This method is not present in JDK 1.1.) The unexportObject method provides a force parameter, which can be set to true if the object should be forcibly unexported regardless of whether or not remote calls are currently in progress, or false otherwise. The unexportObject method throws a NoSuchObjectException if the object is not currently exported at the time of the call (regardless of the value of the force parameter); otherwise, the return value indicates whether or not the call was successful, i.e. if force was false, whether remote calls were in progress. (Obviously if force is true and the object is currently exported, the call always succeeds and returns true.)

Summary

The above information on writing the server in summarized in Table 7.1.

Table 7.1. Writing the server

 extends UnicastRemoteObject extends RemoteServer or RemoteObject extends other
Exporting Automatically exported on construction Explicit export step required Explicit export step required
Remote semantics Inherited Inherited Undefined
Cloning Clone is auto-exported if the derived class implements Cloneable Undefined Undefined

Implementing remote interface methods

A remote server must implement one or more remote interfaces: to satisfy those interfaces it must provide implementations for one or more remote methods.

When implementing a remote method, all the normal rules of Java apply:[4]

  • you must provide a method implementation with exactly the same parameters and return type as declared by the interface method

  • you cannot reduce the access level of the method from public, as inherited from the interface method

  • you may declare the method implementation as synchronized: as always, this must be done with care, and after a proper concurrency analysis to eliminate any potential for deadlock

  • the method implementation cannot throw, or be declared to throw, a checked exception of a type not thrown by the interface method.

The last rule is often misunderstood. Because of inheritance, the implementation may throw, and declare that it throws, an exception which is a subtype of an exception declared as thrown in the interface method. Also, the declaration for the method implementation may omit exceptions which it doesn't actually throw, even though the interface method declared them.[5] RemoteException itself can often be omitted in this way, because it is usually not thrown by the method implementation itself, but by the RMI framework. Example 7.6 illustrates this technique.

The technique may be used when defining classes with both local and remote semantics. Clients of the remote interface must concern themselves with RemoteException, but local clients of the implementation class need not be concerned with RemoteException.

Example 7.6. Not throwing RemoteException

interface RemoteData extends Remote
{
       String getData() throws RemoteException;
}

class DataServer extends UnicastRemoteObject
      implements RemoteData
{
      public String getData() // throws nothing
      {
             return "here is the data";
      }
}

However, a remote method implementation which calls other remote methods is still liable to throw a RemoteException, which therefore must still be declared. The Java compiler will detect this case.

Threads, sockets, and ports

When a remote object is exported, it is registered with the RMI run-time system. This implies a number of “behind-the-scenes” activities:

  • a listening TCP port—a ServerSocket—and a listening thread (listener) are created if necessary

  • the remote object is associated with the listening port and listener

  • when an incoming connection is accepted by the listener, a connection to the client is formed

  • when an incoming RMI call is received on a connection, it is dispatched to the object and method concerned, on a thread determined by the implementation

  • clients may make a new connection or reuse an existing connection for any RMI call.

Threads

The RMI specification says “A method dispatched by the RMI runtime to a remote object implementation may or may not execute in a separate thread. The RMI runtime makes no guarantees with respect to mapping remote object invocations to threads. Since remote method invocation on the same remote object may execute concurrently, a remote object implementation needs to make sure its implementation is thread-safe.” [6]

In other words, the RMI implementation is free to dispatch an incoming RMI call on any thread. It may dispatch them all consecutively to the same thread; concurrently to many threads; or any other way it likes. There is no implication that there is—or is not—one specific dispatch thread per exported object. There is no guarantee about mapping clients, or client threads, to server threads. There are no guarantees and you can make no assumptions. Your implementations of remote methods must be thread-safe. It is up to you.

This information is most important when doing concurrency analysis.

Server sockets

For servers, a new listening port and listener are created only when necessary, and shared where possible. Ports can be shared when the remote object for which the port was created and the newly exported remote object for which a port is now required were both exported from the same host and JVM with:

  • an omitted or zero port number, or the same port number

  • an omitted or null client socket factory, or “equal” client socket factories

  • an omitted or null server socket factory, or “equal” server socket factories.

For the purposes of this test, socket factories are equal if (a) they are of the same class and (b) the class's implementation of the Object.equals method returns true when invoked to compare the factory objects (e.g. ssf1.equals(ssf2)).

This means that whether a listening port can be shared or not is ultimately determined by the server and client socket factories' implementations of the Object.equals method.

The reasoning behind this is that socket factories generally imply superimposed protocols, and different socket factories are unlikely to superimpose the same protocol. Different instances of the same socket factory class may or may not obey the same protocol, or permit sharing of a port—session sharing—for other reasons internal to the socket factory, so the socket factory is given the ultimate decision as to whether its ports can be shared.

This also means that you can't share the same listening port between two remote objects which use different socket factories, even by explicitly specifying the same port number. In this case, RMI will attempt to create a new ServerSocket on the same port number for both objects when exporting them, and only the first export will succeed.

Normally you would choose to export via the default port, unless Internet firewall considerations force you to choose a fixed port number—see the discussion in Chapter 15. In either case, subject to the conditions above, a single listening TCP port can automatically be shared between several RMI servers executing in the same JVM; you do not need to make any provision for multiple TCP ports within that JVM.

You only need multiple TCP port numbers within a single physical host when more than one JVM is running; for instance, when multiple activation groups are executing.

If you are running an “embedded” RMI registry, by executing LocateRegistry.createRegistry, you can use the registry port number, 1099, when exporting any other RMI server from the same JVM as the registry.

Socket factories being equal, there is little to choose between using a different port for each exported remote object and sharing the same port among as many remote objects as possible. Allocating ports consumes operating system and protocol stack resources; sharing ports economizes on those resources, and on listening threads within RMI, but slightly increases the risk of timed-out client connections under heavy load. Measure and choose.

Listening ports have a finite “backlog” of pending connection requests; once the backlog is reached, further incoming connection requests are ignored (not refused, because the condition is transient, so it is reasonable for the other end to retry, as it does if it receives no response whatever). A pending connection request is one which has been accepted by the TCP/IP implementation but not by the application. The rate at which an application can accept connections is determined by processor speed, priority, and the rate at which threads can be created. In Sun's implementation, the “backlog” parameter for server sockets is 50 (unless the server socket factory specifies its own), but the underlying TCP/IP implementation will reduce this to its own maximum backlog if lower.[7]

Client sockets

For clients, an existing idle connection (client socket) to a remote object may be reused if the already connected remote object and the required remote object were both exported from the same host with:

  • an omitted or zero port number, or the same port number

  • an omitted or null client socket factory, or “equal” client socket factories

where equality among socket factories is as defined in the previous section.

It is up to the client socket factory's implementation of the Object.equals method whether an existing connection can be reused or not.

For further information on the Object.equals method in socket factories see Chapter 11.

The Unreferenced interface

The java.rmi.server.Unreferenced interface provides a mechanism for notifying a server object when no further remote clients have remote stubs for it. A remote object is not obliged to implement Unreferenced. If it does, it must provide an implementation of the unreferenced method, by the rules of Java. The unreferenced method is a callback invoked by the RMI system when the DGC subsystem has determined that the number of remote clients of the object has fallen to zero.

Note

This event may occur more than once in the lifetime of a remote server.

This interface is typically used for two purposes: to schedule idle-time activity of the server, and to allow a remote server to exit when idle.

Idle-time activity

Many remote servers have things they could usefully do while there are no clients: cleanups, reorganizations, reports, and so on. The Unreferenced interface provides an ideal means of scheduling these activities.

One particularly useful thing an unreferenced method can do is to schedule the Java garbage collector by calling System.gc.

Exiting when idle

The Unreferenced.unreferenced method is executed when an exported object's client count has fallen to zero, i.e. when remote references to it no longer exist. An exported remote object is automatically unexported and garbage-collected locally when no remote or local references to it exist. If you want the object to be unexported and garbage-collected locally, all you have to do is arrange for all local references to it to be cleared when its unreferenced method is called.

You might want this behaviour if the remote server was dedicated to a specific client or session.

You should usually not unexport the object yourself (by calling an unexportObject method) when the unreferenced method is executed. The reasoning behind this recommendation is complex. A remote object can only be unexported safely—i.e. without disrupting clients—when there are no clients. This is only really safe if it is assured that there will be no future clients of the object. These could arise if other remote servers—including other instances of the current class—are holding local references to the object, which may subsequently be returned as RMI results. Obviously, in the general case, assuring the absence of future clients is an unsolvable problem in fortune-telling.

The only special case in which future clients obviously cannot arise is the case where no local references to the server exist, i.e. when the garbage-collection system is about to collect the object. It is safest to leave the solution of this problem to the local garbage-collection system rather than try to anticipate its workings.

If a network partition (router, bridge, gateway, and so on) is present between a client and a remote server, it is possible for the server's end of the transport to believe incorrectly that the client has crashed. In this event, DGC may execute prematurely: i.e. the unreferenced method may be called prematurely. If a remote server is unexported prematurely, any existing clients will incur a NoSuchObjectException if they try to use a “stale” remote reference to the server.

For these reasons, remote objects—at least non-activatable ones—should use the “exit when idle” technique with care. For activatable remote objects, see the discussion in §10.9.

Building the server

Each RMI server must be (a) compiled by the Java compiler and (b) processed by the RMI stub compiler rmic, which generates the remote stub class used by clients to access each remote server.

From JDK 1.2, rmic can generate three kinds of stubs, according to the setting of the -v option, as shown in Table 7.2.

Table 7.2. rmic stub generation

Option Comment
-v1.1 Generates stubs which can be used by clients running under JDK 1.1 or later; also generates skeletons. This generates the same kinds of stubs and skeletons as the JDK 1.1 rmic, which does not support the -v option at all.
-v1.2 Generates stubs which can only be used by clients running under JDK 1.2 or later.
-vcompat Generates “compatible” stubs, which behave like 1.2 stubs if JDK 1.2 is installed, otherwise like 1.1 stubs, at a slight cost in code size and class initialization time. If no -v option is specified, this is the default.

rmic is invoked with the command syntax:

rmic [options] class ...

where options is one or more of the supported options, and class is the Java qualified name of a remote class: a class which implements a remote interface. For each class XXX, rmic generates a stub class whose class file is named XXX_Stub.class. If the -v1.1 or -vcompat option is specified, or if you are using JDK 1.1, it also produces a skeleton class whose .class file is named XXX_Skel.class. You must avoid defining classes with names of these forms, so as to avoid clashing with classes generated by rmic.

The stub and skeleton classes generated by rmic are defined in the same package as the server class. Up to and including JDK 1.2.2, these class files are produced in the current directory. From JDK 1.3, the class files are produced in the same directory as the source class. In either case, if the behaviour is not what you want, specify the directory with the -d directory option. In our experience the JDK 1.3 behaviour is what you want, and indeed this is why it was changed.

Consult the JDK documentation for full details on rmic.

Stub protocols

The RMI stub protocol is used by the stub to communicate with the server. So far there are two versions of this protocol:

  • 1.1, which communicates with a skeleton

  • 1.2, which communicates with a reflection-based dispatcher introduced in JDK 1.2.

Which protocol is used depends on two factors: what kind of stub was generated, and which JDK the client is executing under. The 1.1 stub protocol is used when the client is executing under JDK 1.1, or when the stub was generated with rmic -v1.1 (or both). The 1.2 protocol is used in all other cases. This information is summarized in Table 7.3.

Table 7.3. Stub protocols

rmic flag Server JDK Client JDK Stub protocol
-vcompat (default) 1.1 1.1 1.1
-vcompat (default)1.11.2Not supported[a]
-vcompat (default)1.21.11.1
-vcompat (default)1.21.21.2
-v1.1AnyAny1.1
-v1.21.1AnyNot supported[b]
 1.21.1Not supported
 1.21.21.2

[a] This case shouldn't arise, because the stub must be generated by the JDK which is used to support the server. JDK 1.1 always generates 1.1-style stubs. If the situation is constructed artificially, a run-time protocol error may result.

[b] This case shouldn't arise, for a similar reason to the above: JDK 1.1 can't generate a 1.2-style stub.

If you are not deploying servers or clients with JDK 1.1, you should use the -v1.2 parameter to rmic, which does not generate skeleton classes—one less thing to install at the server.

Installation and distribution

Stub class files are required by both clients and servers. You can use RMI code mobility, discussed in Chapter 9, to make stub files available to clients; otherwise you must ensure that stub files are distributed with the client parts of your application.

Server implementation-class files and skeleton files are normally not required by clients at all, and should not be distributed to them, except when clients export their own servers (e.g. to implement a callback function): in this case, clients need all the classes concerned.

Foundation classes

This section describes the foundation classes RemoteObject and RemoteServer, and provides general information about remote object semantics.

RemoteObject

java.rmi.server.RemoteObject is the abstract base class for the standard RMI server and stub classes. It implements remote object semantics by overriding the methods for equals, hashCode, and toString. The hashCode and equals methods are implemented to allow RemoteObjectreferences to be stored in hashtables and compared:

  • the equals method returns true if two RemoteObjects refer to the same remote object

  • the hashCode method returns the same value for all remote references that refer to the same underlying RemoteObject (because references to the same object are considered equal)

  • the toString method “is defined to return a string which represents the remote reference of the RemoteObject”.[8]

Equality of two RemoteObjects is not tested by comparing the contents of the objects, because (a) that would require two remote method calls, which would be slow, and (b) these method calls could throw a remote exception, which the equals method can neither deal reasonably with nor throw.

Objects that require these remote semantics may extend RemoteObject, typically via RemoteServer, UnicastRemoteObject, or Activatable. RemoteObject also provides a getRef method which returns the remote reference for the object.

A remote reference is an internal handle for a remote object, used by remote stubs to carry out remote method invocations to the remote object, or by remote servers to export themselves or get the client's hostname.

RemoteServer

java.rmi.server.RemoteServer is the abstract base class for the classes UnicastRemoteObject and Activatable. It provides a getClientHost method, which returns the hostname of the current client (or throws a ServerNotActiveException if not called within a remote method invocation), and getLog and setLog methods, for controlling server logging.[9]

Semantics of remote objects

The public methods exported by java.lang.Object include equals, hashCode, and toString. These methods define the semantics of a local object—properties which Java can rely on as being exhibited by any Java object.

The semantics of a remote object are a compromise between being identical with the semantics of local objects, which would require RMI calls for each of the methods listed above, and the requirements of efficiency, which dictate that each of these methods be implemented without requiring a remote method invocation.

Remote semantics are only required of objects acting as proxies for remote objects—i.e. remote stubs which, as generated by rmic, always inherit the required behaviour from RemoteObject. Remote objects—exported servers—may implement remote semantics: either those of RemoteObject or some other semantics (e.g. equality of a remote server and its stub). Remote objects should implement remote semantics if they are going to be used in local hashtables (e.g. to associate remote objects with their stubs, to enable local call optimization).

Serialization

If an exported remote object is also serializable, it is still passed by reference. In other words the recipient receives a remote reference to the original remote object, rather than a de-serialized copy of it. The fact that the object is exported takes precedence over the fact that it is serializable.

This statement applies whether or not the remote object extends UnicastRemoteObject. However, if a UnicastRemoteObject is serialized, either in an unexported state or other than via RMI,[10] all its non-static non-transient state is serialized as usual, including the UnicastRemoteObject's own port and socket factory settings and any serializable data of the derived class.[11] When the resulting stream is de-serialized, the resulting UnicastRemoteObject is automatically exported to the RMI system—on the same port and with the same socket factories, if any, that it had when serialized, or the defaults for these—so that it may receive remote calls. If the export fails for some reason, the de-serialization will fail with an exception.

This facility allows RMI servers to be written to files and recovered from them as active entities. It also allows an inactive RMI server to be passed as a parameter or returned as the result of a remote method call, whereupon the RMI server is exported at the target. This provides a sophisticated form of code mobility—see Chapter 9 and §12.3.

However, no method is provided for specifying the required port and socket factories to be used when exporting the object on de-serialization. These parameters are taken from the serialized object, and cannot be controlled other than by actually exporting the object. If the object had never been exported, or had been exported with default port or socket factory settings, the object will be exported using default port and socket factories. If you need to avoid this, you must ensure that the object has been exported with these parameters set as required, and then unexported, prior to serializing it.

Alternative server classes

There are other kinds of RMI server besides the “unicast remote object”.

The java.rmi.activation.Activatable class supports activatable remote objects. For purposes so far in the book, it is largely equivalent to UnicastRemoteObject, with the extra feature that references to it are persistent, not transient: they can be saved and reused; and they remain valid even after the server they refer to has exited. If used in this state, they cause the server to be restarted. Activation is discussed in Chapter 10.

The javax.rmi PortableRemoteObject class supports “portable remote objects”. A portable remote object is an RMI server which communicates via the standard CORBA/IIOP protocol. Portable remote objects provide most of the facilities of RMI while preserving interoperability with CORBA. (Both “unicast” and “activatable” servers communicate via the RMI/JRMP protocol, which is exclusive to Java.) RMI/IIOP is discussed in Chapter 14.

Further speculative RMI server types are discussed in Chapter 17.

Exercises

1:

The ExtendedUnicastRemoteObject sample class provided in Example 7.2 has a “no-args” constructor. Can you remove it and let the Java compiler supply it? Explain. (You may use the Java compiler to experiment.)

2:

The following remote interface defines a remote date/time service, which returns its current date and time to clients. Write an RMI server class which implements this service. (You can use any of the three techniques described in §7.3. The server must export itself.)

public interface RemoteDateTime extends java.rmi.Remote
{
       java.util.Date      getCurrentDateTime()
              throws java.rmi.RemoteException;
}

3:

Add a main procedure to the date/time server of the previous exercise. The main procedure should (a) create an instance of the server, (b) register it with the RMI registry under an appropriate name, and (c) catch and display all exceptions encountered.

4:

Write a client for the date/time server which displays the local and remote date and time. Test the entire system and show the output.

5:

Modify the date/time server to export itself on port 1100. Retest with the client and show the output.

6:

Modify the date/time server to implement the Unreferenced interface and trace all calls to the unreferenced method. Retest with the client and show the output. Is the unreferenced method called after the client exits? How long should you wait? Now, unbind the server from the registry with the reg.jar utility described in Chapter 6. Does the unreferenced method get called after this? Explain.

7:

Modify the date/time server to unbind itself from the registry when the remote method has been called 10 times. Retest with the client and show the output. The server should exit after the client has been run 10 times, after the expiration of the interval measured in the previous exercise.



[1] RMI specification, §5.3.

[2] and because base class constructors can't be called from within try...catch blocks.

[3] The RMI specification is unclear on this point, but in Sun's implementation this happens even if the source object wasn't exported at the time it was cloned. It would be unwise to rely on this behaviour, which may be modified in a future release of Java.

[4] The Java Programming Language, §4.3.2.

[5] The Java Programming Language, §8.3.1.

[6] RMI specification, §3.2.

[7] For further information on TCP/IP backlogs see Stevens, TCP/IP Illustrated, Volume I, §18.11.

[8] RMI specification, §5.1.1.

[9] All these methods are static. Up to JDK 1.3, the JDK documentation described RemoteServer as also providing abstract methods which a concrete implementation class such as UnicastRemoteObject must implement: this statement is incorrect in all versions of Java we have seen.

[10] Strictly, other than via a MarshalOutputStream.

[11] The RMI specification, §5.3.4 says that “information contained in UnicastRemoteObject is transient and is not saved if an object of that type is written to a user-defined ObjectOutputStream”. This specification conflicts with Sun's implementation. Indeed, the “export upon de-serialization” feature as implemented relies on these fields being non-transient.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.126.56