The proxy pattern has many practical applications. This post discusses an implementation of the proxy pattern using the Java Remote Method Invocation (RMI) framework. This post assumes you have a basic understanding of the RMI framework. This post describes using the proxy pattern to communicate with a remote machine as if it were a local class. This example shows a client/remote implementation that prints the username
of the server machine.
The Proxy Pattern
The proxy pattern uses a representative object that controls access to another object. The representative in this case is an interface named ServerRemote
. The interface only has one method getUsername
which returns the username of the system. This allows the server to define exactly how that work is done. Here’s the interface in action:
Representative Object (Proxy)
1 2 3 4 5 6 | import java.rmi.Remote; import java.rmi.RemoteException; public interface ServerRemote extends Remote { public String getUsername() throws RemoteException; } |
This is the representative (proxy) object that both the client and server will use to communicate. The implementation acts as the proxy allowing the server to do things like filter and modify the requests as needed.
Server Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class ServerRemoteImpl extends UnicastRemoteObject implements ServerRemote { protected ServerRemoteImpl() throws RemoteException {} @Override public String getUsername() throws RemoteException { return System.getProperty("user.name"); } public static void main (String[] args) { try { ServerRemote serverRemote = new ServerRemoteImpl(); Naming.rebind("RemoteUsername", serverRemote); } catch (Exception exception) { exception.printStackTrace(); } } } |
The server implementation binds the RMI object and uses System.getProperty()
to retrieve the username. This implementation will vary depending on the remote machine. I installed this code as a service on my headless Ubuntu server using systemd. When the server starts it executes the jar and binds the object with RMI. Clients are then able to lookup the RMI service and communicate with the machine.
Client Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import java.rmi.Naming; public class ClientRemote { public static void main(String[] args) { new ClientRemote().go(); } public void go() { try { ServerRemote serverRemote = (ServerRemote) Naming.lookup("rmi://my.server.address/RemoteUsername"); System.out.println(serverRemote.getUsername()); } catch (Exception exception) { exception.printStackTrace(); } } } |
The client uses ServerRemote
to communicate with the remote machine from a single point.
Summary
The client is able to communicate with the remote machine through a single proxy object. The client doesn’t need to know the details of what’s happening in between, it just needs a single “service” to communicate with. This is a very simple example, the proxy pattern can be implemented in many different ways.