Pecan Consulting

  • Home
  • ¿Quiénes Somos?
    • Trabajos Anteriores
  • Servicios
  • Blog
  • Contacto
Esta usted aqui: Inicio / Java / JAVA RMI. PRÁCTICA UNED. PARTE 2. EL SERVIDOR(II).

JAVA RMI. PRÁCTICA UNED. PARTE 2. EL SERVIDOR(II).

22 julio, 2014 By DavidMS Leave a Comment

Continuamos con el tutorial Java RMI. En la última entrada vimos las interfaces que va a publicar el Servidor. En esta entrada vamos a implementar ésas mismas interfaces. Los archivos que contienen la definición de las interfaces de todos los servicios deben ser accesibles por todos los agentes del sistema, por lo que es conveniente crear una carpeta/proyecto y añadirlo a cada uno de los proyectos (Servidor, Cliente, Repositorio). Bueno, vamos con la implementación de las interfaces.

ServicioDatosImpl

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import es.uned.common.ServicioDatosInterface;
import es.uned.common.Utils;

public class ServicioDatosImpl extends UnicastRemoteObject implements ServicioDatosInterface {

     private static final long serialVersionUID = 1526643248021674437L;
     // Conjunto de Maps para almacenar y relacionar los clientes, los
     // repositorios y los numeros de sesion
     private Map<Integer, String> sesion_cliente = new HashMap<Integer, String>();
     private Map<String, Integer> cliente_sesion = new HashMap<String, Integer>();
     private Map<Integer, String> sesion_repositorio = new HashMap<Integer, String>();
     private Map<String, Integer> repositorio_sesion = new HashMap<String, Integer>();
     private Map<Integer, Integer> cliente_repositorio = new HashMap<Integer, Integer>();

     // Nombre del archivo que mantiene el Log del Servidor.
     private String nombreLog;

     protected ServicioDatosImpl() throws RemoteException {
          super();
     }

     protected ServicioDatosImpl(String nombreLog) throws RemoteException {
          super();
          this.nombreLog = nombreLog;
     }

     // Meetodo que añade un Cliente al sistema recibiendo como parámetro un
     // nombre y una id. No se permiten nombres de clientes repetidos. Tambien
     // asocia al Cliente con un repositorio existente. En el caso de no haber
     // repositorios no se ingresa el Cliente.
     @Override
     public boolean ingresaCliente(String nombre, int id) throws RemoteException {
          // Comprobamos que el cliente no exista
          if (cliente_sesion.containsKey(nombre.toUpperCase())) {
          Utils.escribeLog(nombreLog,
          "El cliente ya se encuentra dado de alta.");
          return false;
          } else {
               // Recogemos la lista de repositorios disponibles
               List<Integer> repositorios = new ArrayList<Integer>(
               repositorio_sesion.values());
               if (repositorios.isEmpty()) {
                    Utils.escribeLog(nombreLog, "No hay repositorios disponibles.");
                    return false;
               } else {
                    // Añadimos el cliente a la "base de datos"
                    sesion_cliente.put(id, nombre.toUpperCase());
                    cliente_sesion.put(nombre.toUpperCase(), id);
                    // Asociamos al cliente con un repositorio al azar
                    int n = (int) (Math.random() * repositorios.size());
                    cliente_repositorio.put(id, repositorios.get(n));
                    Utils.escribeLog(nombreLog, "Autenticando a " + nombre + " con la id " + id);
                    return true;
                }
          }
     }

     // Método que añade un Repositorio al sistema recibiendo como parámetros un
     // nombre y una id. No se permiten nombres de Repositorios repetidos.
     @Override
     public boolean ingresaRepositorio(String nombre, int id) throws RemoteException {

          if (repositorio_sesion.containsKey(nombre.toUpperCase())) {
               Utils.escribeLog(nombreLog, "El repositorio ya se encuentra dado de alta.");
               return false;
          }
          // De ser así lo añadimos a la "base de datos"
          else {
               sesion_repositorio.put(id, nombre.toUpperCase());
               repositorio_sesion.put(nombre.toUpperCase(), id);
               Utils.escribeLog(nombreLog, "Autenticando a " + nombre + " con la id " + id);
               return true;
          }
     }

     // Metodo que devuelve una colección con los nombres de los Clientes.
     @Override
     public Collection<String> listaClientes() throws RemoteException {
          Collection<String> clientes = (Collection<String>) sesion_cliente.values();
          return clientes;
     }

     // Metodo que devuelve una colección con los nombres de los Repositorios.
     @Override
     public Collection<String> listaRepositorios() throws RemoteException {
          Collection<String> repositorios = (Collection<String>) sesion_repositorio.values();
          return repositorios;
     }

     // Metodo que devuelve la id del repositorio que le corresponde a un cliente
     // cuya id que se pasa como parámetro.
     @Override
     public int buscaRepositorio(int cliente) throws RemoteException {

          int repositorio = 0;
          try {
               repositorio = cliente_repositorio.get(cliente);
          } catch (Exception e) {
               System.out.println("ServicioDatosImpl.buscaRepositorio: " + e.getMessage());
               System.out.println(cliente_repositorio.get(cliente));
          }
          return repositorio;
     }

     // Método que imprime por pantalla la lista de repositorios junto con los
     // clientes asociados a los mismos.
     @Override
     public void listarRepositoriosClientes() throws RemoteException {
          ArrayList<Integer> repositorios = new ArrayList<Integer>(repositorio_sesion.values());
          ArrayList<Integer> clientes = new ArrayList<Integer>(
          cliente_repositorio.keySet());
               if (repositorios.isEmpty()) {
                    Utils.escribeLog(nombreLog, "No hay repositorios registrados actualmente.");
               } else if (clientes.isEmpty()) {
                    Utils.escribeLog(nombreLog, "No hay clientes registrados actualmente.");
               } else {
                    for (int n : repositorios) {
                         System.out.println("REPOSITORIO " + sesion_repositorio.get(n));
                         System.out.println("===========================================");
                         System.out.println("CLIENTES");
                         System.out.println("===========================================");
                         for (int c : clientes) {
                              if (cliente_repositorio.get(c) == n) {
                                   System.out.println(sesion_cliente.get(c));
                         }
                    }
               System.out.println("===========================================");
               }
          }
     }
}

Vamos a analizar esta clase. Todas las clases que queramos publicar como objetos remotos deberán extender de UnicastRemoteObject. Hay otras formas de publicar objetos que no extienden de UnicastRemoteObject, pero no los vamos a ver en este ejemplo. La clase además implementa por supuesto ServicioDatosInterface.

UnicastRemoteObject ( http://docs.oracle.com/javase/7/docs/api/java/rmi/server/UnicastRemoteObject.html ) nos permite exportar un objeto remoto y obtener un stub que se comunica con el objeto remoto.

Por lo demás las funciones son bastante autoexplicativas. Se usan una serie de Maps para almacenar los distintos datos de clientes y repositorios y relacionarlos y creamos un constructor que recibe como parámetro un nombre de fichero que se corresponde al log del Servidor en el que podremos escribir distintos mensajes de carácter informativo, luego pondré la función que hace esto.

ServicioAutenticacionImpl

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Random;

import es.uned.common.ServicioAutenticacionInterface;
import es.uned.common.ServicioDatosInterface;
import es.uned.common.Utils;

public class ServicioAutenticacionImpl extends UnicastRemoteObject implements ServicioAutenticacionInterface {

	private static final long serialVersionUID = 593676645816200166L;
	// Numero aleatorio que nos va a servir para obtener los numeros       // de sesion de los Clientes y Repositorios
	private static int sesion = new Random().nextInt();
    private static int miSesion = 0;
    // Objeto para el acceso al servicio Datos.
    private static ServicioDatosInterface datos;
    private String nombreLog;

    protected ServicioAutenticacionImpl() throws RemoteException {
		super();
		// TODO Auto-generated constructor stub
    }

    protected ServicioAutenticacionImpl(String nombreLog) throws RemoteException {
		super();
		this.nombreLog = nombreLog;
	}

	// Función que autentica un cliente y devuelve el número de sesión que le ha
	// sido asignado o 0 en caso de que no se haya podido llevar a cabo la
	// autenticación.
	@Override
	public int autenticarCliente(String nombre) throws RemoteException {
		Utils.escribeLog(nombreLog, nombre + " esta intentando autenticarse");
		int sesionUsuario = getSesion();
		try {
			datos = (ServicioDatosInterface) Naming.lookup("rmi://localhost:1492/datos");
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}

		if (datos.ingresaCliente(nombre, sesionUsuario)) {
			return sesionUsuario;
		} else {
			return 0;
		}
	}

	// Función que autentica un repositorio y devuelve el número de sesión que
	// le ha sido asignado o 0 en caso de que no se haya podido llevar a cabo la
	// autenticación.
	public int autenticarRepositorio(String nombre) throws RemoteException {

		Utils.escribeLog(nombreLog, nombre + " esta intentando autenticarse");
		int sesionUsuario = getSesion();

		try {
			datos = (ServicioDatosInterface) Naming.lookup("rmi://localhost:1492/datos");
		} catch (NotBoundException e) {
		// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}

		if (datos.ingresaRepositorio(nombre, sesionUsuario)) {
			return sesionUsuario;
		} else {
			return 0;
		}
	}

	public static int getSesion() {
		return ++sesion;
	}

}

La implementación de esta interfaz publica dos métodos: autenticarCliente y autenticarRepositorio. Ambas reciben el nombre de usuario, generan una id, que va a ser única para cada usuario del sistema y haciendo uso del Servicio de Datos, autentican al cliente, para ello, buscan el servicio de Datos, haciendo uso del método lookup de la clase Naming que es una clase que nos permite almacenar y recuperar referencias a objetos remotos de un registro rmi.

Al método lookup le pasamos como parámetro la URL del objeto que queremos recuperar ( http://docs.oracle.com/javase/7/docs/api/java/rmi/Naming.html ).

El objeto devuelto por lookup es casteado a la interfaz que queremos recuperar, en este caso ServicioDatosInterface y a partir de ese momento ya podemos invocar los métodos expuestos por la interfaz.

ServicioGestorImpl

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import es.uned.common.ServicioDatosInterface;
import es.uned.common.ServicioGestorInterface;

public class ServicioGestorImpl extends UnicastRemoteObject implements ServicioGestorInterface {

     private static final long serialVersionUID = 1L;

     private static String nombreLog;
     //Haremos uso del servicio de DATOS del Servidor.
     private static ServicioDatosInterface datos;

     protected ServicioGestorImpl() throws RemoteException {
          super();
          // TODO Auto-generated constructor stub
     }

     protected ServicioGestorImpl(String nombreLog) throws RemoteException{
          super();
          this.nombreLog = nombreLog;
     }

     //Método que obtiene la dirección del servicio ClienteOperador
     @Override
     public String obtenerServicioClienteOperador(int id) throws RemoteException, NotBoundException,
     MalformedURLException {

          datos = (ServicioDatosInterface) Naming.lookup("rmi://localhost:1492/datos");
          int repositorio = datos.buscaRepositorio(id);
          String URL_repositorio = "rmi://localhost:1492/ServicioClOperador/"+ repositorio;
          return URL_repositorio;
     }

     //Método que obtiene la dirección del servicio ServidorOperador
     @Override
     public String obtenerServicioServidorOperador(int id) throws RemoteException, NotBoundException,
     MalformedURLException {

          datos = (ServicioDatosInterface) Naming.lookup("rmi://localhost:1492/datos");
          int repositorio = datos.buscaRepositorio(id);
          String URL_repositorio = "rmi://localhost:1492/ServicioSrOperador/"+ repositorio;
          return URL_repositorio;
     }

}

Esta interfaz exponía dos métodos: obtenerServicioClienteOperador y obtenerServicioServidorOperador. En ambos casos, reciben como parámetro la id de un cliente y a partir de ésta, usando el servicio de Datos, forman una Url del tipo «rmi://localhost:1492/Servicio»+idRepositorio con el repositorio que corresponde al cliente que invoca el método, con ésta Url, los clientes pueden localizar el servicio de su correspondiente Repositorio y llevar a cabo las operaciones de subida, bajada, borrado de ficheros,…
Como se puede ver, los métodos lanzan distintas excepciones (comentaré al final del tutorial las distintas excepciones que aparecen en el proyecto) en lugar de capturarlas en su interior. Cuando implementemos el cliente, veremos que esto nos permite informar en la parte del cliente con una mayor claridad.

Servidor

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;

public class Servidor {

     // Variable para leer la entrada por teclado
     private static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

     // Direccion del fichero que contiene el Log de esta sesion
     private static String nombreLog;

     // Variable que indica el puerto donde se levantara el registro
     private static int puertoRegistro = 1492;

     // Main de la Clase Servidor
     public static void main(String[] args) throws Exception {

     if (creaLog()) {
          System.out.println("Log creado correctamente.");

          // Iniciamos el registro en el puerto indicado
          startRegistry(puertoRegistro);

          // Levantamos el SERVICIO DE DATOS
          ServicioDatosImpl datos = new ServicioDatosImpl(nombreLog);
          Naming.rebind("rmi://localhost:" + puertoRegistro + "/datos", datos);
          System.out.println("Servicio Datos listo");

          // Levantamos el SERVICIO DE AUTENTICACION
          ServicioAutenticacionImpl autenticacion = new ServicioAutenticacionImpl(nombreLog);
          Naming.rebind("rmi://localhost:" + puertoRegistro + "/autenticacion", autenticacion);
          System.out.println("Servicio Autenticacion listo");

          // Levantamos el SERVICIO DE GESTION
          ServicioGestorImpl gestor = new ServicioGestorImpl(nombreLog);
          Naming.rebind("rmi://localhost:" + puertoRegistro + "/gestor", gestor);
          System.out.println("Servicio Gestor listo");

          // Imprimimos el MENU
          int option = 1;
          do {
               System.out.println("1.- Listar Clientes.");
               System.out.println("2.- Listar Repositorios.");
               System.out.println("3.- Listar Parejas Repositorio-Cliente.");
               System.out.println("4.- Salir.");
               option = Integer.parseInt(reader.readLine());
               switch (option) {
                    case 1:
                         Collection<String> clientes = datos.listaClientes();
                         if (!clientes.isEmpty()) {
                              System.out.println("==================================");
                              System.out.println("Clientes.");
                              System.out.println("==================================");
                              for (String nombre : clientes) {
                                   System.out.println(nombre);
                              }
                              System.out.println("==================================");
                         } else {
                              System.out.println("==================================");
                              System.out.println("No hay clientes registrados.");
                              System.out.println("==================================");
                         }
                    break;
                    case 2:
                         Collection<String> repositorios = datos.listaRepositorios();
                         if (!repositorios.isEmpty()) {
                              System.out.println("==================================");
                              System.out.println("Repositorios.");
                              System.out.println("==================================");
                              for (String nombre : repositorios) {
                                   System.out.println(nombre);
                              }
                              System.out.println("==================================");
                         } else {
                              System.out.println("==================================");
                              System.out.println("No hay repositorios registrados.");
                              System.out.println("==================================");
                         }
                    break;
                    case 3:
                         datos.listarRepositoriosClientes();
                    break;
                    case 4:
                         // Finalizamos el servicio de Autenticacion
                         Naming.unbind("rmi://localhost:" + puertoRegistro + "/autenticacion");
                         // Finalizamos el servicio de Datos
                         Naming.unbind("rmi://localhost:" + puertoRegistro + "/datos");
                         // Finalizamos el servicio Gestor
                         Naming.unbind("rmi://localhost:" + puertoRegistro + "/gestor");
                    break;
                    default:
                         System.out.println("Opción incorrecta.");
                    break;
               }
          } while (option != 4);

     } else {
          System.out.println("Error en la creación del log. Saliendo.");
     }
 }

Esta clase contiene el main del Servidor.
Lo primero que hacemos es levantar el registro con el método startRegistry que recibe como parámetro un número de puerto (al final del post pondré las funciones auxiliares) y a continuación publicamos los distintos servicios…

Para ello, creamos un objeto de la clase que queramos publicar y a continuación utilizamos el método rebind de la clase Naming que recibe como parámetro dicho objeto (que debe ser de tipo UnicastRemoteObject) y una Url que será la que se usará más tarde para localizar el objeto cuando queramos hacer uso de él. El método rebind sustituye el objeto que hubiera en dicha Url en el caso de existir uno. También podríamos usar bind que no hace nada en el caso de que ya existiera un objeto en dicha dirección, pero todo eso lo podreis ver en la documentación de oracle.

Al finalizar el servidor deberemos «desenlazar» todos estos objetos, para ello usaremos el método unbind de la clase Naming, por lo demás el main es bastante autoexplicativo.

Funciones Auxiliares

private static void startRegistry(int RMIPortNum) throws RemoteException {
     try {
          Registry registry = LocateRegistry.getRegistry(RMIPortNum);
          registry.list(); // This call throws a exception if the registry
                           // does not already exist
     } catch (RemoteException ex) {
          // No valid registry at that port.System.out.println("RMI registry cannot be located at port " + RMIPortNum);
          Registry registry = LocateRegistry.createRegistry(RMIPortNum);
          System.out.println("RMI registry created at port " + RMIPortNum);
     }
 }

 public static boolean creaLog() {
      Date date = new Date();
      DateFormat hourdateFormat = new SimpleDateFormat("HHmmss_ddMMyyyy");
      System.out.println("Hora y fecha: " + hourdateFormat.format(date));
      URL rutaca = Servidor.class.getProtectionDomain().getCodeSource().getLocation();
      String[] rutaTemporal = rutaca.toString().split("/");
      StringBuilder rutaFinal = new StringBuilder();
      for (int i = 1; i < rutaTemporal.length - 1; i++) {
           rutaFinal.append(rutaTemporal[i]);
           rutaFinal.append("/");
      }
      nombreLog = rutaFinal.toString() + hourdateFormat.format(date).toString() + ".txt";
      try {
           File log = new File(nombreLog);
           log.createNewFile();
      } catch (IOException e) {
      // TODO Auto-generated catch block
            e.printStackTrace();
            return false;
      }
      return true;
 }

Estas funciones se encargan de iniciar el registro y crear un archivo de Log para el Servidor. Son bastante autoexplicativas, simplemente comentar que el método getRegistry de la clase LocateRegistry nos devuelve una referencia al registro que se encuentre en el puerto pasado como parámetro. El método createRegistry crea el registro en el puerto que se le pasa como parámetro.

Y hasta aquí la implementación del Servidor y de los servicios que publica. En el próximo post nos encargaremos de los repositorios. Un saludo.

Compártelo:

  • Haz clic para enviar por correo electrónico a un amigo (Se abre en una ventana nueva)
  • Haz clic para compartir en Facebook (Se abre en una ventana nueva)
  • Haz clic para compartir en Twitter (Se abre en una ventana nueva)
  • Haz clic para compartir en Google+ (Se abre en una ventana nueva)
  • Haz clic para compartir en LinkedIn (Se abre en una ventana nueva)
  • Haz clic para compartir en Pocket (Se abre en una ventana nueva)
  • Haz clic para compartir en Pinterest (Se abre en una ventana nueva)
  • Haz clic para compartir en Tumblr (Se abre en una ventana nueva)

Filed Under: Java, news, programacion, RMI, Sistemas Distribuidos, UNED

Date una vuelta por nuestro Blog

  • enero 2015 (1)
  • diciembre 2014 (12)
  • noviembre 2014 (1)
  • octubre 2014 (1)
  • julio 2014 (3)
  • febrero 2014 (1)

Deja un comentario Cancelar respuesta

¿Tienes alguna pregunta? No dudes en ponerte en contacto con nosotros.

Su nombre (requerido)

Su e-mail (requerido)

Asunto

Su mensaje

Contacto

  • Pecan Soluciones Informaticas
  • C/ La Gaviota, 6
    28022 Madrid
  • 660 811 495
  • info@pecan.es
Facebook

Pecan Consulting

Somos una consultoría informática especializada en el desarrollo web, las aplicaciones móviles y el márketing online. En Pecan buscamos la satisfacción de nuestros clientes. Para ello proporcionamos un trato cercano desde las primeras fases de desarrollo, garantizando una perfecta toma de requisitos que nos permite aportar soluciones informáticas apropiadas a las necesidades de cada proyecto.

Categorías

.net asp.net css diseño web Java Microsoft news plugins woocommerce plugins wordpress programacion RMI servicios Sistemas Distribuidos trabajos tutoriales UNED woocommerce wordpress
PMP Certificate Scrum Manager Member PMP Certificate
  • Home
  • ¿Quiénes Somos?
  • Servicios
  • Blog
  • Contacto

Copyright © 2022· PECAN CONSULTING

loading Cancelar
La entrada no fue enviada. ¡Comprueba tus direcciones de correo electrónico!
Error en la comprobación de email. Por favor, vuelve a intentarlo
Lo sentimos, tu blog no puede compartir entradas por correo electrónico.