CSC409 Advanced Java Programming

Advanced Java ProgrammingUnit 813 min read

RMI vs CORBA: Distributed Computing in Java

Unit 8 of Advanced Java Programming covers Remote Method Invocation (RMI) and Common Object Request Broker Architecture (CORBA), explaining their architectures, implementation steps, IDL generation, and key differences through Java examples and comparison tables.

TAKEAWAYS:

  • RMI uses Java’s native object serialization for distributed communication, while CORBA supports heterogeneous systems via IDL and IIOP.
  • Both rely on stubs/skeletons (RMI) or ORB (CORBA) to bridge client-server gaps, but CORBA’s IDL enables cross-language interoperability.
  • RMI’s architecture layers (client, stub, ORB, skeleton, server) mirror CORBA’s ORB-based model, but CORBA adds Interface Definition Language (IDL) for platform independence.
  • CORBA’s Dynamic Invocation Interface (DII) and Dynamic Skeleton Interface (DSI) allow runtime method calls, unlike RMI’s compile-time binding.
  • Key exam focus: RMI steps (registry, stub generation, server/client code), IDL syntax, and comparison tables (e.g., language support, performance, use cases).
  • Practical applications: RMI for Java-to-Java distributed apps (e.g., banking systems), CORBA for enterprise systems (e.g., healthcare, telecom) requiring multi-language support.

1. Introduction to Distributed Computing

Distributed computing enables communication between independent systems (clients/servers) across networks. Java provides two frameworks:

  • Remote Method Invocation (RMI): Java-centric, leveraging object serialization.
  • CORBA (Common Object Request Broker Architecture): Language-agnostic, using Interface Definition Language (IDL).

Why Distributed Systems?

  • Resource sharing (e.g., databases, printers).
  • Scalability (load balancing across servers).
  • Fault tolerance (redundant services).

2. Remote Method Invocation (RMI)

2.1 RMI Architecture

RMI follows a client-server model with the following layers:

flowchart LR
    A["Client"] -->|1. Method Call| B["Stub"]
    B -->|2. Marshaling| C["ORB (Java RMI Registry)"]
    C -->|3. Unmarshaling| D["Skeleton"]
    D -->|4. Server Execution| E["Server"]
    E -->|5. Return Result| D
    D -->|6. Marshaling| C
    C -->|7. Unmarshaling| B
    B -->|8. Return to Client| A

Key Components:

Component Role
Stub Client-side proxy; marshals method calls into network data.
Skeleton Server-side proxy; unmarshals data and invokes methods.
ORB (RMI Registry) Binds remote objects to names (default port: 1099).
Remote Interface Extends java.rmi.Remote; declares methods that throw RemoteException.

2.2 Steps to Create an RMI Application

  1. Define the Remote Interface:

    import java.rmi.Remote;
    import java.rmi.RemoteException;
    
    public interface Calculator extends Remote {
        int add(int a, int b) throws RemoteException;
    }
    
  2. Implement the Remote Object:

    public class CalculatorImpl extends UnicastRemoteObject implements Calculator {
        public CalculatorImpl() throws RemoteException {
            super();
        }
        public int add(int a, int b) { return a + b; }
    }
    
  3. Compile and Generate Stub/Skeleton:

    javac Calculator.java CalculatorImpl.java
    rmiregistry &  # Start RMI registry
    rmic CalculatorImpl  # Generates stub/skeleton
    
  4. Create the Server:

    public class Server {
        public static void main(String[] args) {
            try {
                Calculator calc = new CalculatorImpl();
                Naming.rebind("rmi://localhost:1099/Calculator", calc);
                System.out.println("Server ready");
            } catch (Exception e) { e.printStackTrace(); }
        }
    }
    
  5. Create the Client:

    public class Client {
        public static void main(String[] args) {
            try {
                Calculator calc = (Calculator) Naming.lookup("rmi://localhost:1099/Calculator");
                int result = calc.add(5, 3);
                System.out.println("Result: " + result);
            } catch (Exception e) { e.printStackTrace(); }
        }
    }
    

2.3 Role of Stub and Skeleton

  • Stub:
    • Acts as a local representative of the remote object.
    • Converts method calls into network calls (marshalling).
    • Example: When calc.add(5, 3) is called, the stub sends the parameters over the network.
  • Skeleton:
    • Receives network data and unmarshals it into method calls on the server.
    • Invokes the actual method on the remote object.

Trace Example:

  1. Client calls calc.add(5, 3) → Stub marshals (5, 3) into bytes.
  2. Bytes sent to server → Skeleton unmarshals into method call.
  3. Server executes add(5, 3) → Returns 8 → Skeleton marshals result.
  4. Stub receives 8 → Returns to client.

2.4 Advantages and Disadvantages of RMI

Advantages Disadvantages
Seamless Java-to-Java communication. Limited to Java (no cross-language support).
Uses Java serialization (type safety). Performance overhead due to serialization.
Simple API for developers. Security risks (e.g., malicious stubs).
Built-in support for object passing. Firewall issues (ports 1099, 1024-65535).

3. Common Object Request Broker Architecture (CORBA)

3.1 CORBA Architecture

CORBA uses an Object Request Broker (ORB) to enable communication between objects in different languages/environments.

flowchart LR
    A["Client"] -->|1. Method Call| B["ORB Client"]
    B -->|2. IIOP Protocol| C["ORB Server"]
    C -->|3. Method Invocation| D["Server Object"]
    D -->|4. Return Result| C
    C -->|5. IIOP Protocol| B
    B -->|6. Return to Client| A

Key Components:

Component Role
ORB Middleware that handles communication (e.g., IIOP protocol).
Object Adapter Binds server objects to the ORB (e.g., Basic Object Adapter).
Interface Repository Stores IDL definitions for runtime inspection.
IDL (Interface Definition Language) Language-neutral interface specification.

3.2 Interface Definition Language (IDL)

IDL defines interfaces for CORBA objects, enabling cross-language compatibility. Example IDL File (Calculator.idl):

interface Calculator {
    long add(in long a, in long b);
};

Steps to Generate Stub/Skeleton:

  1. Compile IDL to Java stubs/skeletons using idlj:

    idlj -fall Calculator.idl
    

    Outputs:

    • Calculator.java (client stub)
    • CalculatorHolder.java (data holder)
    • CalculatorOperations.java (interface)
    • _CalculatorStub.java (stub)
    • _CalculatorImplBase.java (skeleton base)
  2. Implement the Server:

    public class CalculatorImpl extends _CalculatorImplBase {
        public int add(int a, int b) { return a + b; }
    }
    
  3. Run the ORB Server:

    public class Server {
        public static void main(String[] args) {
            ORB orb = ORB.init(args, null);
            CalculatorImpl calc = new CalculatorImpl();
            orb.connect(calc);
            System.out.println("Server ready");
        }
    }
    
  4. Run the Client:

    public class Client {
        public static void main(String[] args) {
            ORB orb = ORB.init(args, null);
            org.omg.CORBA.Object obj = orb.resolve_initial_references("NameService");
            NamingContext nc = NamingContextHelper.narrow(obj);
            Calculator calc = CalculatorHelper.narrow(nc.resolve("Calculator"));
            int result = calc.add(5, 3);
            System.out.println("Result: " + result);
        }
    }
    

3.3 Dynamic Invocation in CORBA

CORBA supports dynamic method calls at runtime:

  • Dynamic Invocation Interface (DII): Clients invoke methods without stubs.
  • Dynamic Skeleton Interface (DSI): Servers handle requests without skeletons.

Example (DII):

// Client-side dynamic call
Request req = orb.create_request("add", "Calculator");
req.add_in_arg(new org.omg.CORBA.LongHolder(5));
req.add_in_arg(new org.omg.CORBA.LongHolder(3));
org.omg.CORBA.Any result = req.invoke();
System.out.println("Result: " + result.extract_long());

3.4 Advantages and Disadvantages of CORBA

Advantages Disadvantages
Cross-language support (C++, Java, Python). Complex IDL and ORB setup.
Standardized (OMG specification). Performance overhead (IIOP protocol).
Supports heterogeneous systems. Steep learning curve.
Dynamic invocation (DII/DSI). Legacy technology (less modern than gRPC).

4. RMI vs CORBA: Comparison

Feature RMI CORBA
Language Support Java-only Multi-language (C++, Java, etc.)
Protocol Java RMI (proprietary) IIOP (standardized)
Interface Definition Java interfaces IDL (Interface Definition Language)
Dynamic Invocation No Yes (DII/DSI)
Performance Faster (native Java) Slower (IIOP overhead)
Use Cases Java-to-Java apps Enterprise systems (healthcare, telecom)
Security Basic (Java security model) Advanced (ORB-level security)

When to Use Which?

  • Use RMI for pure Java distributed applications (e.g., internal tools, banking systems).
  • Use CORBA for enterprise systems requiring cross-language interoperability (e.g., legacy systems, heterogeneous environments).

5. Worked Example: RMI Factorial Calculator

Task: Create an RMI application where a client sends an integer to the server, and the server returns its factorial.

Step 1: Remote Interface

public interface Factorial extends Remote {
    long computeFactorial(int n) throws RemoteException;
}

Step 2: Server Implementation

public class FactorialImpl extends UnicastRemoteObject implements Factorial {
    public FactorialImpl() throws RemoteException { super(); }

    public long computeFactorial(int n) {
        long result = 1;
        for (int i = 2; i <= n; i++) result *= i;
        return result;
    }
}

Step 3: Server Code

public class Server {
    public static void main(String[] args) {
        try {
            Factorial factorial = new FactorialImpl();
            Naming.rebind("rmi://localhost:1099/Factorial", factorial);
            System.out.println("Server ready");
        } catch (Exception e) { e.printStackTrace(); }
    }
}

Step 4: Client Code

public class Client {
    public static void main(String[] args) {
        try {
            Factorial factorial = (Factorial) Naming.lookup("rmi://localhost:1099/Factorial");
            long result = factorial.computeFactorial(5);
            System.out.println("5! = " + result);  // Output: 120
        } catch (Exception e) { e.printStackTrace(); }
    }
}

Step 5: Compile and Run

rmiregistry &  # Start RMI registry
rmic FactorialImpl  # Generate stub
javac *.java
java Server
java Client

Output:

Server ready
5! = 120

6. Worked Example: CORBA IDL and Stub Generation

Task: Write an IDL file for a TemperatureConverter and generate stubs.

Step 1: IDL File (TemperatureConverter.idl)

module Math {
    interface TemperatureConverter {
        float celsiusToFahrenheit(in float celsius);
        float fahrenheitToCelsius(in float fahrenheit);
    };
};

Step 2: Generate Stubs

idlj -fall TemperatureConverter.idl

Output files:

  • Math/TemperatureConverter.java
  • Math/TemperatureConverterHolder.java
  • Math/TemperatureConverterOperations.java
  • _Math_TemperatureConverterStub.java

Step 3: Server Implementation

public class TemperatureConverterImpl extends _Math_TemperatureConverterImplBase {
    public float celsiusToFahrenheit(float celsius) {
        return (celsius * 9/5) + 32;
    }
    public float fahrenheitToCelsius(float fahrenheit) {
        return (fahrenheit - 32) * 5/9;
    }
}

Step 4: Client Code

public class Client {
    public static void main(String[] args) {
        try {
            ORB orb = ORB.init(args, null);
            org.omg.CORBA.Object obj = orb.resolve_initial_references("NameService");
            NamingContext nc = NamingContextHelper.narrow(obj);
            TemperatureConverter converter = TemperatureConverterHelper.narrow(nc.resolve("Math/TemperatureConverter"));
            float result = converter.celsiusToFahrenheit(25);
            System.out.println("25°C = " + result + "°F");  // Output: 77.0°F
        } catch (Exception e) { e.printStackTrace(); }
    }
}

7. Exam Tip: Key Focus Areas

  1. RMI Steps:

    • Remember the 5-step process (interface → implementation → stub generation → server → client).
    • Common pitfalls: Forgetting rmiregistry, incorrect port binding, or missing RemoteException.
  2. CORBA IDL:

    • Syntax for interface, module, and parameter types (in, out, inout).
    • Tool: idlj generates stubs; orbd runs the ORB server.
  3. Stub vs Skeleton:

    • Stub: Client-side; marshals calls.
    • Skeleton: Server-side; unmarshals calls.
    • ORB: Middleware for both RMI and CORBA.
  4. Comparison Table:

    • Always include language support, protocol, and use cases in comparisons.
  5. Practical Code:

    • RMI: Focus on Naming.rebind() and Naming.lookup().
    • CORBA: Focus on ORB.init(), NamingContext, and IDL syntax.
  6. Shortcuts for Exams:

    • For RMI, draw the 5-layer architecture (client → stub → ORB → skeleton → server).
    • For CORBA, highlight IDL and ORB as key differentiators.

Based on the TU BSc CSIT syllabus for Advanced Java Programming (CSC409), unit 8.

Discussion

Loading…