Memra

The remote interface and its implementation

◈ 5 cards

Declare a service the network can reach: extend Remote, throw RemoteException on every method, and keep the implementation an ordinary class the client never sees.

Remote is a marker, not a base class

A remote interface is an ordinary Java interface that extends java.rmi.Remote. Remote declares no methods at all. It exists so that the RMI runtime can recognise the type — and it uses that recognition twice. At export time it asks "which interfaces of this object are remote?" and builds the stub from exactly those. At marshalling time it asks "is this argument a remote object?" and, if so, passes a stub instead of a copy (lesson 4). Methods that are not declared in a Remote interface are simply not callable from another JVM, however public they are.

Every method throws RemoteException

java.rmi.RemoteException extends IOException and is checked. Every method of a remote interface must declare throws RemoteException — not because your logic can fail, but because the call can. It is the compiler's way of stopping you from writing code that quietly assumes the network is infallible. RMI cannot report a broken connection by returning a special value, because your method already owns the return type; so it throws, and the language forces the caller to say what happens then.

The implementing class is allowed to declare fewer checked exceptions than the interface — Java permits an override to narrow a throws clause. So PrimeServiceImpl.largestPrimeInRange can declare no checked exceptions at all: it runs locally in the server JVM, where there is no call to fail. This is normal and worth doing, because it stops server-side code pretending to handle a network error it can never see.

The client only ever names the interface

Split the artefacts in your head by which JVM has the class file:

  • PrimeService (the interface) — both sides need it. It is the contract, and it is the only type the client ever names.
  • PrimeServiceImpl (the implementation) — server only. Shipping it to the client is not merely unnecessary; it invites the mistake below.
  • The stub — created at runtime on export, and arrives at the client as the result of a registry lookup.

Because the stub is a proxy implementing PrimeService, casting a lookup result to PrimeServiceImpl throws ClassCastException even when both classes are on the classpath. Declare the client variable as the interface, always.

Designing the one method

Assignment 3 asks for a service that finds "the largest prime number within a range set by the user". That maps to one coarse-grained call: two bounds in, one answer out. Two design decisions have to be made explicitly, because a remote interface is a published contract and you cannot quietly change your mind later.

  • Bad input. low > high is the caller's bug, so throw IllegalArgumentException — it is unchecked, it is Serializable, and RMI will rethrow it in the client thread as the cause the client sees.
  • No prime in the range. largestPrimeInRange(8, 10) has no answer. Returning -1 and documenting it is a legitimate choice for a numeric result that can never legitimately be negative; the alternative is a custom checked exception, which then has to be on the client's classpath too. Pick one and write it in the javadoc.

Worked example — PrimeService

The whole contract is four lines of interface and a class that knows nothing about networking at all. Note what PrimeServiceImpl does not do: it does not extend any RMI class, does not open a socket, and does not mention RemoteException. It is a plain object that happens to be reachable — which is the entire point of the exercise, and the reason it stays unit-testable without a server running.

artefactclient JVMserver JVMwhat it isPrimeServiceyesyesthe contract;extends RemotePrimeServiceImplnoyesa plain class;server onlythe stubat runtimemade hereproxy built whenyou exportThe client names only the interface.
Read the middle two columns as a packaging checklist. The commonest RMI setup mistake is a client classpath that has neither the interface (the lookup then fails) nor, worse, one that has the implementation and tempts you into casting to it.
NORMAL ~/memra/learn/comp-348/rmi-remote-interface utf-8 LF