Advanced Java ProgrammingUnit 911 min read
Remote Method Invocation (RMI): Architecture, Implementation & Real-World Use
Unit 9 of Advanced Java Programming explores how Java’s RMI enables distributed objects to communicate across networks, covering its architecture, stub/skeleton generation, security, and practical applications in banking, e-commerce, and cloud services. This note includes step-by-step implementation, real-world example
TAKEAWAYS:
- RMI lets Java objects invoke methods on remote machines as if they were local, using stubs, skeletons, and a registry.
- The architecture follows a client-server model with RMI runtime (rmiregistry, RMI compiler, and transport layers).
- Interfaces are mandatory in RMI to define remote methods, and classes must extend
java.rmi.Remoteand declare exceptions asRemoteException. - Security requires policy files (
server.policy,client.policy) to grant permissions for remote access. - Real-world uses include Ncell’s remote billing systems, eSewa’s distributed transaction processing, and Google’s internal microservices.
- Debugging RMI issues requires checking firewall settings, port conflicts (default: 1099), and class version mismatches.
Core Concepts of RMI
Remote Method Invocation (RMI) is a Java API that allows objects on different JVMs (even on different machines) to communicate seamlessly. Unlike traditional network programming (e.g., sockets), RMI abstracts away low-level details like serialization, marshalling, and transport, making distributed programming intuitive.
How RMI Works: The Magic Behind the Scenes
When a client calls a remote method, the following steps occur (visualized below):
flowchart TD
A["Client JVM"] -->|"1. Method Call"| B["Stub (Local Proxy)"]
B -->|"2. Serialization"| C["Transport Layer (TCP/IP)"]
C -->|"3. Remote JVM"| D["Skeleton (Remote Object)"]
D -->|"4. Deserialization"| E["Remote Object"]
E -->|"5. Method Execution"| F["Result"]
F -->|"6. Serialization"| C
C -->|"7. Transport"| B
B -->|"8. Return"| AKey Components:
- Stub: A local proxy that forwards method calls to the remote object.
- Skeleton: A server-side object that receives calls and invokes the actual remote object.
- Remote Reference Layer (RRL): Handles object references and communication.
- Registry (rmiregistry): A name service that binds remote objects to names (default port: 1099).
Step-by-Step RMI Implementation
1. Define the Remote Interface
All remote objects must implement an interface that extends java.rmi.Remote. Methods must declare RemoteException.
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Calculator extends Remote {
double add(double a, double b) throws RemoteException;
double subtract(double a, double b) throws RemoteException;
}
2. Implement the Remote Object
The server class must extend UnicastRemoteObject (for single-JVM instances) or RemoteObject (for multi-JVM).
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class CalculatorImpl extends UnicastRemoteObject implements Calculator {
public CalculatorImpl() throws RemoteException {
super(); // Generates stub/skeleton
}
@Override
public double add(double a, double b) throws RemoteException {
return a + b;
}
@Override
public double subtract(double a, double b) throws RemoteException {
return a - b;
}
}
3. Create and Export the Remote Object
The server binds the remote object to the registry.
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Server {
public static void main(String[] args) {
try {
Calculator calculator = new CalculatorImpl();
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("calculator", calculator);
System.out.println("Server ready");
} catch (Exception e) {
e.printStackTrace();
}
}
}
4. Client-Side Code
The client looks up the remote object and invokes methods.
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
public static void main(String[] args) {
try {
Registry registry = LocateRegistry.getRegistry("localhost", 1099);
Calculator calculator = (Calculator) registry.lookup("calculator");
double result = calculator.add(5.0, 3.2);
System.out.println("Result: " + result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Visualizing RMI in Action: Step-by-Step Trace
Let’s trace the execution of calculator.add(5.0, 3.2) with a state diagram for each step.
State After Client Calls add(5.0, 3.2)
stateDiagram-v2
[*] --> ClientStub: Method Call
ClientStub -->|Serializes Args| TransportLayer: [5.0, 3.2]
TransportLayer --> ServerStub: TCP Packet
ServerStub --> CalculatorImpl: Deserializes
CalculatorImpl --> CalculatorImpl: Computes 8.2
CalculatorImpl --> ServerStub: Serializes Result
ServerStub --> TransportLayer: TCP Packet
TransportLayer --> ClientStub: [8.2]
ClientStub --> Client: Returns 8.2
Client --> [*]Network Packet Flow (Simplified)
Client (192.168.1.100:1234) → Server (192.168.1.101:1099)
[TCP Packet: Method=add, Args=[5.0, 3.2], ObjectID=123]
Server → Client
[TCP Packet: Result=8.2, ObjectID=123]
Real-World Applications of RMI
1. Ncell’s Billing System
- Use Case: Ncell’s central billing server processes transactions from thousands of base stations across Nepal.
- How RMI Helps:
- Each base station runs a lightweight client that invokes
chargeCustomer()on the central server. - Visual: The central server is a remote object bound to
rmiregistryon port 1099. - Advantage: Avoids polling; clients call methods only when needed (e.g., after a call ends).
- Each base station runs a lightweight client that invokes
2. eSewa’s Distributed Transaction Processing
- Use Case: When you pay a bill via eSewa, your request is routed to a load-balanced server farm.
- How RMI Helps:
- The eSewa app (client) calls
processPayment()on a remotePaymentServiceobject. - Visual: Multiple
PaymentServiceImplinstances run on different servers, all bound to the same registry name ("paymentService").
- The eSewa app (client) calls
3. Google’s Internal Microservices
- Use Case: Google uses RMI-like mechanisms (though now mostly gRPC) for internal services like Ads, Maps, and YouTube.
- How RMI Helps:
- A
UserProfileServiceremote object might exposegetUserData()for authentication across data centers. - Visual: A distributed system diagram with clients in multiple regions calling a global registry.
- A
Security in RMI
RMI requires explicit security policies due to its network nature. Two key files are needed:
1. Server Policy File (server.policy)
grant {
permission java.security.AllPermission;
};
- Grants the server full access to local resources (e.g., files, network).
2. Client Policy File (client.policy)
grant {
permission java.net.SocketPermission "localhost:1099", "connect";
};
- Restricts the client to only connect to
localhost:1099.
How to Enable Security:
- Compile with
-Djava.security.policy=server.policy(server side). - Run with
java -Djava.security.policy=client.policy Client.
Common Pitfalls and Debugging
| Issue | Cause | Solution |
|---|---|---|
java.rmi.ConnectException |
Firewall blocking port 1099 | Open port 1099 in firewall (ufw allow 1099). |
ClassNotFoundException |
Client/server class versions mismatch | Ensure both use the same .class files. |
AccessControlException |
Missing policy file | Run with -Djava.security.policy=file.policy. |
java.rmi.ServerException |
Stub/skeleton mismatch | Recompile with rmic (deprecated in Java 9+). |
Note: In Java 9+, rmic is removed. Use dynamic stub generation (default behavior).
RMI vs. Alternatives: Comparison Table
| Feature | RMI | Sockets | REST/gRPC | Java EE EJB |
|---|---|---|---|---|
| Ease of Use | High (object-oriented) | Low (manual serialization) | Medium (JSON/XML) | High (container-managed) |
| Performance | Medium (Java serialization) | High (raw bytes) | High (Protocol Buffers) | Medium (JNDI overhead) |
| Language Independence | No (Java-only) | No (language-specific) | Yes (HTTP/JSON) | No (Java EE) |
| Scalability | Limited (registry bottleneck) | High (manual load balancing) | High (stateless) | Medium (container-dependent) |
| Use Case | Internal Java apps (e.g., banks) | Custom protocols (e.g., games) | Public APIs (e.g., YouTube) | Enterprise apps (e.g., ERP) |
Worked Example: Bank Loan Calculator
Scenario: A bank’s head office wants to expose a LoanCalculator service to branches. Each branch runs a client that calls calculateEMI() remotely.
1. Remote Interface
public interface LoanCalculator extends Remote {
double calculateEMI(double principal, double rate, int years) throws RemoteException;
}
2. Server Implementation
public class LoanCalculatorImpl extends UnicastRemoteObject implements LoanCalculator {
public LoanCalculatorImpl() throws RemoteException {
super();
}
@Override
public double calculateEMI(double p, double r, int y) throws RemoteException {
double monthlyRate = r / 12 / 100;
int months = y * 12;
return (p * monthlyRate) / (1 - Math.pow(1 + monthlyRate, -months));
}
}
3. Client Usage (Branch Office)
public class BranchClient {
public static void main(String[] args) {
try {
Registry registry = LocateRegistry.getRegistry("bank-server", 1099);
LoanCalculator calculator = (LoanCalculator) registry.lookup("loanService");
double emi = calculator.calculateEMI(1000000, 8.5, 5);
System.out.println("Monthly EMI: Rs." + emi);
} catch (Exception e) {
e.printStackTrace();
}
}
}
State After calculateEMI(1000000, 8.5, 5)
sequenceDiagram
participant Branch as Branch Client
participant Stub as Stub (Local)
participant Network as TCP/IP
participant Skeleton as Skeleton (Server)
participant Server as LoanCalculatorImpl
Branch->>Stub: calculateEMI(1M, 8.5, 5)
Stub->>Network: Serialized Args
Network->>Skeleton: TCP Packet
Skeleton->>Server: Deserializes
Server->>Server: Computes EMI = Rs. 20,556.50
Server->>Skeleton: Serializes Result
Skeleton->>Network: TCP Packet
Network->>Stub: Rs. 20,556.50
Stub->>Branch: Returns EMIExam Tip: How to Score Full Marks
Architecture Diagram: Always draw the client-stub-skeleton-server flow in your answer. Label:
- Stub (client-side proxy)
- Skeleton (server-side dispatcher)
- Registry (
rmiregistry) - Transport layer (TCP/IP).
Code Snippets: Include one complete remote interface and one server/client class in your answer. Use comments to highlight:
extends Remotethrows RemoteExceptionUnicastRemoteObjectconstructor.
Security: Mention policy files and their purpose. Example:
"The server requires
server.policyto grantAllPermission, while the client needsSocketPermissionfor the registry port (1099)."Real-World Tie-In: Relate RMI to Ncell’s billing or eSewa’s transactions. Example:
"In Ncell’s system, the
BillingServerremote object implementsChargeCustomer, allowing base stations to invokedeductAmount()without direct database access."Common Errors: List 2-3 pitfalls (e.g., port blocking, class mismatch) with fixes.
Pro Tip: For short-answer questions, use bullet points for the architecture:
- Client ↔ Stub (local proxy)
- Stub ↔ Skeleton (via TCP)
- Skeleton ↔ Remote Object
- Registry binds names to objects (port 1099).
Based on the TU BIT syllabus for Advanced Java Programming (BIT401), unit 9.
Discussion
Loading…