Comunicación bidireccional entre procesos distribuidos con RMI de Java

2021-12-19 - Categorías: Java
Java

Para el que lo pueda necesitar, este es un codekata, howto o apunte para implementar la comunicación bidireccional entre Clientes y Servidores usando RMI, lo que se llama implementar callbacks hacia los clientes. Es una vuelta de tuerca al post anterior sobre la implementación del RMI de Java, Remote Method Invocation.

Este post es una ampliación para usar clientes y servidores con RMI de Java, de forma que tanto el servidor como el cliente actúan invocando métodos remotos en el cliente y servidor.

Cómo funciona

Inicialmente, cualquier proceso en Java puede arrancar y exponer servicios RMI, a modo de servidor, que pueden ser utilizados remotamente por los clientes. También de la misma forma tenemos los llamados callbacks, que no son más que la misma idea pero implementada al revés, los servidores llaman a métodos en los clientes.

Lo más interesante de este post, es que al usar RMI, podemos tener en el servidor listas de servicios remotos que estén en cada cliente conectado. Así se simplifica todo.

Al grano, el código fuente..

La estructura modificada queda así:

Lo más nuevo con respecto al post anterior es una clase que por ejemplo se podría llamar CallbackInterface.java compartido en el paquete rmicommon del proyecto:

package rmicommon;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface CallbackInterface extends Remote {
    public void callbackMethod() throws RemoteException;
}

Y su implementación de CallbackImpl.java que se ejecutará en el cliente:

package rmiclient;

import java.io.Serializable;
import rmicommon.CallbackInterface;

public class CallbackImpl implements CallbackInterface, Serializable{
    public void callbackMethod() {
        System.out.println("Callback invoked!");
    }
}

El servicio ServiceInterface.java que implementará y ejecutará el servidor. Aquí la idea es poder almacenar en el servicio los callbacks de todos los clientes para su uso posterior:

package rmicommon;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.ArrayList;

public interface ServiceInterface extends Remote {
    public void sendSmsToServer(String aux) throws RemoteException;

    public void addCallback(CallbackInterface callback) throws RemoteException;

    public ArrayList<CallbackInterface> getCallbacksList() throws RemoteException;
}

Una posible implementación del ServiceImpl.java:

package rmiserver;

import java.rmi.RemoteException;
import java.util.ArrayList;
import rmicommon.CallbackInterface;
import rmicommon.ServiceInterface;

public class ServiceImpl implements ServiceInterface {
    ArrayList<CallbackInterface> callbacksList;

    public ServiceImpl() {
        this.callbacksList = new ArrayList<CallbackInterface>();
    }

    public void sendSmsToServer(String sms) throws RemoteException {
        System.out.println("Client> " + sms);
    }

    public void addCallback(CallbackInterface callback) throws RemoteException {
        this.callbacksList.add(callback);
    }

    public ArrayList<CallbackInterface> getCallbacksList() throws RemoteException {
        return this.callbacksList;
    }
}

Queda el servidor y el cliente, aquí el Server.java:

package rmiserver;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.UUID;

import rmicommon.*;

public class Server {
    static ServiceInterface service;
    static ServiceInterface stubService;
    static String localServiceName = "rmi://localhost:8080/TheService";
    static Registry registry;

    public static void main(String[] args) {
        service = new ServiceImpl();

        System.out.println(UUID.randomUUID().toString());

        try {
            /* Open registry and service.. */
            registry = LocateRegistry.createRegistry(8080);
            stubService = (ServiceInterface) UnicastRemoteObject.exportObject(service, 0);
            Naming.rebind(localServiceName, stubService);
            printObjectsInRmi();

            /* Send callbacks to clients for testing.. */
            System.console().readLine("Launch the Client and press enter here.. Continue? " + System.lineSeparator());
            printObjectsInRmi();
            sendCallbacks();

            UnicastRemoteObject.unexportObject(service, true);
            Naming.unbind(localServiceName);
        } catch (Exception e) {
            System.out.println("ERROR: " + e.toString());
        }
    }

    private static void printObjectsInRmi() {
        try {
            System.out.println("Objects in RMI:");
            for (String string : registry.list()) {
                System.out.println(string);
            }

        } catch (Exception e) {
            System.out.println("ERROR: " + e.getMessage());
        }
    }

    private static void sendCallbacks() {
        try {
            System.out.println("Sending callbacks:");
            for (int index = 0; index < 3; index++) {
                for (CallbackInterface callback : service.getCallbacksList()) {
                    System.out.println("A callback..");
                    callback.callbackMethod("Hello! I'm the server..");
                }
            }
        } catch (Exception e) {
            System.out.println("ERROR: " + e.getMessage());
        }
    }
}

Y el Client.java:

package rmiclient;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import rmicommon.*;

public class Client {
    static CallbackInterface callback;
    static CallbackInterface stubCallback;
    static String localCallbackName = "rmi://localhost:8080/TheCallback";
    static Registry registry;
    static ServiceInterface service;

    public static void main(String[] args) {
        try {
            // Connect to the server..
            registry = LocateRegistry.getRegistry("localhost", 8080);
            service = (ServiceInterface) Naming.lookup("rmi://localhost:8080/TheService");
            service.sendSmsToServer("Hello! I'm a client.");

            // Open the callback service and send to the server, 
            // for letting him send the callbacks..
            callback = new CallbackImpl();
            stubCallback = (CallbackInterface) UnicastRemoteObject.exportObject(callback, 0);
            //Naming.rebind(localCallbackName, stubCallback);

            // Enqueue callback on server to use from there..
            service.addCallback(callback);

            System.console().readLine("Connected to the server, press enter to finish.. Continue? " + System.lineSeparator());

            UnicastRemoteObject.unexportObject(callback, true);
            //Naming.unbind(localCallbackName);
        } catch (Exception e) {
            System.out.println("ERROR: " + e.toString());
        }
    }
}

Ejecutando los procesos

Para que conecten y ver los procesos hay que seguir un orden para ver todos los métodos invocados:

  • Arrancar el servidor.
  • Arrancar el cliente.
  • Aprentar enter en el servidor para lanzar los callbacks al cliente.

Ejecutando el servidor

Ejecutando el cliente

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

 

© 2024 JnjSite.com - MIT license

Sitio hecho con WordPress, diseño y programación del tema por Jnj.