En el artículo anterior vimos como estaba estructurada la capa Servicio y cuales eran las ideas principales. Pero para que sea realmente útil, nos quedaba responder las siguientes dos preguntas:
-
¿Cómo vamos a hacer para crear una instancia que sea un proxy de la clase MathServiceImpl, que implemente la interfaz MathService en forma automática y en tiempo de ejecución?
-
¿Cómo vamos a hacer un RequestListener genérico que “decodifique” el RequestPacket e invoque al método correcto de MathServiceImpl?
Primero la primera. Para poder ejecutar un método, necesitamos saber: qué método de qué servicio y con qué parámetros lo vamos a ejecutar y mandar esa información al servidor; para esto vamos a crear la clase ServicePacket, que contiene esta información (el nombre del servicio, el nombre del método y un array de Object con los parámetros que toma el método).
Ahora necesitamos el proxy. Afortunadamente Java nos provee un mecanismo para crear proxies en tiempo de ejecución. Para ver la documentación sobre proxies dinámicos ver http://java.sun.com/javase/6/docs/technotes/guides/reflection/proxy.html. Ahh! El poder de la reflexión
Entonces, lo que vamos a hacer es un InvocationHandler que arme el ServicePacket y con ayuda de la capa Pedido lo mande al servidor:
public class ServiceInvocationHandler implements InvocationHandler {
// implements InvocationHandler
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
RequestPacket req = new RequestPacket(new ServicePacket(serviceName, m.getName(), args), getUniqueKey());
ResponsePacket result = requestManager.send(req);
return result.getData();
}
}
Vamos a tener una instancia de ServiceInvocationHandler por cada servicio y a cada servicio lo vamos a identificar con un String: serviceName.
Para crear un proxy utilizaremos la clase ServiceProxyFactory que tiene el método createProxy() implementado según la guía sobre proxies dinámicos que va a crear por nosotros el ServiceInvocationHandler configurado. Y así obtenemos los proxies:
MathService mathService = serviceProxyFactory.createProxy(“MathService”);
Luego la invocación:
double pi = mathService.getPI();
No hay que crear ninguna clase extra ni nada por el estilo. Lo único que hay que hacer es pedirle a la serviceProxyFactory un proxy del servicio con el nombre del servicio deseado. Este nombre es el identificador con el que se registró el servicio en el servidor, por lo que es buena práctica ponerlo como constante en la interfaz del servicio.
Obviamente hay más detalles de implementación, como que pasa con las excepciones en el servidor, pero no vale la pena adentrarnos en este punto ya que se puede ver claramente en la implementación de ServiceInvocationHandler.
Ahora la segunda pregunta: ¿Cómo vamos a hacer un RequestListener genérico que “decodifique” el RequestPacket en invoque al método correcto de MathService?
Simple, utilizando otra vez el poder de la reflexión. Vamos a explotar la capacidad de invocar métodos teniendo solamente el nombre y el nombre de la clase. Ahora es cuando vamos a “decodificar” RequestPacket, o mejor dicho, su payload: el ServicePacket. Con este payload, sabemos qué tenemos que ejecutar y con qué parámetros.
Entonces, vamos a tener un componente RequestPacketListener para escuchar los pedidos de los clientes y con los datos en el ServicePacket podemos ejecutar el método requerido.
Ahora un poco de UML:

Diseño de la capa Servicio
La clase ServiceManager implementa RequestPacketListener, por lo que acepta paquetes de la capa Pedido. Además contiene la colección de servicios registrados. Cuando llega un ServicePacket, con el nombre obtiene la instancia del servicio, con el nombre del método, obtiene el objeto método a ejecutar y con los parámetros (array de Object) lo ejecuta. La respuesta le envía al la capa Pedido en forma de ResponsePacket.
Las clases RPCClient y RPCServer nos dan las funcionalidades para interactuar con el RPC de forma sencilla, encapsulando código “pegamento”.
Entonces, un servicio se define:
La declaración:
public interface MathService extends client.service.Service {
String SERVICE_NAME = “math_service”;
double getPI();
}
La implementación:
public class MathServiceImpl extends server.service.Service implements MathService {
@Override
public double getPI() {
return 3.1416;
}
}
Se registra en el main del servidor:
RPCServer rpcServer = new RPCServer(12345); // port en donde escucha el servidor
rpcServer.getServiceManager().addService(
MathService.SERVICE_NAME, // nombre
MathtService.class, // interfaz
MathServiceImpl.class); // implementación
Y se utiliza en el cliente:
RPCClient rpcClient = new RPCClient(“localhost”, 12345); // host y port en donde está el servidor MathServie mathService = (MathService)rpcClient.getService(MathService.SERVICE_NAME); double pi = mathService.getPI();
Así queda el RPC implementado. En el siguiente artículo estaré posteando el código fuente y señalando algunas características extras que no fueron descritas para no agregar complejidad pues no están estrictamente relacionadas con el RPC.
Next!

Por favor podrías enviar o publicar el código fuente de implementación de rpc en java
En breve estaré subiendo el código. Gracias por el interés.
HOla, quizá ya hayas subido el código pero no lo encuentro en tu blog, nos podrías indicar el link? gracias
Hola, el código está en http://blog.aquait.info/2009/10/180/
Qué lo disfrutes
Hola,
El tutorial es genial. Muchísimas gracias. Esto usando tus indicaciones pero veo que falta algo, si se hacen más peticiones al servidor de las que puede atender los clientes se quedarán bloqueados hasta que el servidor satisfaga sus peticiones, ¿se podría implementar de alguna forma que cuando no haya hilos libres para aceptar las peticiones no se quedaran bloqueados?
Gracias por todo
Un saludo, Alberto.