Indice


Volver al Indice Autores


Esta práctica ha sido realizada por el grupo 4 de prácticas.
Tanto la programación como la documentación de la práctica han sido realizadas por Guillem Rull Fort y Jose María Rodríguez Valls.

Volver al Indice Introducción


El objetivo de esta sesión será aprender a utilizar programación en aplicaciones distribuidas.

Para realizar esta práctica dispondremos de la tecnología RMI de java para implementar todas las clases necesarias. Tanto la parte del Cliente como la del Servidor.

Tendremos que emular el comportamiento del problema visto en prácticas anteriores pero utilizando la programación distribuida.

Volver al Indice Entorno


Inicialmente dispondremos de una máquina linux con un compilador java. Apartir del cual tendremos que realizar todas las clases necesarias para resolver la práctica.

Aunque es posible ejecutar el Cliente y Servidor en máquinas diferentes, por comodidad ejecutaremos los dos procesos en un mismo Host.

Volver al Indice Implementación


Los diferentes archivos que forman parte de esta aplicación son:

- tiendaDeMuebles.java
- tiendaDeMueblesImpl.java
- dadesComanda.java
- tiendaDeMueblesCliente.java
- tiendaDeMueblesServidor.java

tiendaDeMuebles.java


Este archivo contendrá la interface que posteriormente tendremos que implementar con los métodos invocados remotamente por el Cliente.

//Importamos la clase vector...
import java.util.Vector;

public interface tiendaDeMuebles extends java.rmi.Remote {

  //Método encargado de añadir un pedido...
  public void comanda(dadesComanda dc) throws java.rmi.RemoteException;

  //Función encargada de retornar el vector de pedidos...
  public Vector llistarComandes() throws java.rmi.RemoteException;
}


tiendaDeMueblesImpl.java


Esta clase será la implementación de la interficie tiendaDeMuebles. En la cual están los diferentes métodos invocados por el Cliente.

//Importamos la clase vector...
import java.util.Vector;

public class tiendaDeMueblesImpl extends java.rmi.server.UnicastRemoteObject implements tiendaDeMuebles {

  //Creamos el Vector de pedidos...
  private Vector comandes = new Vector();

  // Constructor para declarar que puede ocurrir "RemoteException"
  public tiendaDeMueblesImpl() throws java.rmi.RemoteException {super();}

  //Añadimos el pedido dc en el Vector de pedidos...
  public void comanda(dadesComanda dc) throws java.rmi.RemoteException {
     comandes.add(dc);
  }

  //Retornamos el Vector que contiende los pedidos realizados...
  public Vector llistarComandes() throws java.rmi.RemoteException {
     return comandes;
  }
}


dadesComanda.java


La clase dadesComanda es utilizada para almacenar los datos de un pedido efectuado por el Cliente.

import java.io.*;

//Clase encargada de almacenar los datos del pedido...
class dadesComanda implements Serializable {

        //Datos del pedido...
        int n_taules;
        String model_taula;
        int preu_taula;
        int n_cadires;
        String model_cadira;
        int preu_cadira;
        int n_llums;
        String model_llum;
        int preu_llum;

        //Método para visualizar el pedido...
        public void imprimir() {
         if(n_taules > 0) { //Visualizamos las mesas...
System.out.println(""+n_taules+" taules model "+model_taula+" amb preu");
System.out.println(preu_taula+". Total: "+n_taules*preu_taula+"");
         }
         if(n_cadires > 0) { //Visualizamos las sillas...
System.out.println(""+n_cadires+" taules model "+model_cadira+" amb preu");System.out.println(preu_cadira+". Total: "+n_cadires*preu_cadira+"");
         }
         if(n_llums > 0) { //Visualizamos las luces...
System.out.println(""+n_llums+" llums model "+model_llum+" amb preu");System.out.println(preu_llum+". Total: "+n_llums*preu_llum+"");
         }

//Visualizamos el total...
System.out.println("Preu total: "+(n_taules*preu_taula +
+ n_cadires*preu_cadira + n_llums*preu_llum));
System.out.println();
        }
}


tiendaDeMueblesCliente.java


En este apartado podemos ver el código del Cliente.

El cliente determinará la operación a realizar pasando como parámetro. De este modo el mismo proceso podrá realizar pedidos o listar pedidos.

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
import java.util.Vector;

public class tiendaDeMueblesCliente {

public static void main(String[] args) {

  //Comprobamos si han introducido algún parámetro...
  if (args.length != 1) {
System.out.println("Error de parametros: tiendaDeMuebles comanda|llistar_comandes"); System.exit(1);
  }

  try {

   //Obtener la instancia del servidor...
   tiendaDeMuebles c = (tiendaDeMuebles)Naming.lookup("rmi://localhost:1099/tiendaMuebles");

        if (args[0].equals("comanda")) {


                //Efectuamos un pedido...
                dadesComanda dc = new dadesComanda();
                dc.n_taules = 2;
                dc.model_taula = "A";
                dc.preu_taula = 15000;
                dc.n_cadires = 1;
                dc.model_cadira = "B";
                dc.preu_cadira = 30000;
                dc.n_llums = 4;
                dc.model_llum = "C";
                dc.preu_llum = 1000;
                //Añadimos el pedido...
                c.comanda(dc);
                //Visualizamos el pedido...
                System.out.println("Comanda enviada:");
                dc.imprimir();

        } else if (args[0].equals("llistar_comandes")) {


            //Listar los pedidos realizados...
            //Obtenemos el listado de pedidos...
            Vector v = c.llistarComandes();
            //Recorremos el Vector de pedidos...
            for(int i = 0; i < v.size(); i++) {
                dadesComanda dc = (dadesComanda)v.get(i);
                //Visualizamos el pedido i...
                System.out.println("Comanda numero " + i);
                dc.imprimir();
            }


        } else { //El parametro introducido no es valido..
System.out.println("Error de parametros: tiendaDeMuebles comanda|llistar_comandes");
System.exit(1);
        }
  }

  catch (MalformedURLException murle) {
   System.out.println("MalformedURLException: " + murle);
  }
  catch (RemoteException re) {
   System.out.println("RemoteException: " + re);
  }
  catch (NotBoundException nbe) {
   System.out.println("NotBoundException: " + nbe);
  }
  catch (java.lang.ArithmeticException ae) {
   System.out.println("java.lang.ArithmeticException: " + ae);
  }
}
}


tiendaDeMueblesServidor.java


El Servidor será el encargado de atender todas las solicitudes efectuadas por los diferentes Clientes.

En principio el Cliente y Servidor pueden estar localizados en Host distintos. De hay surge la necesidad de asignarle un nombre al servicio a realizar.

import java.rmi.Naming;

public class tiendaDeMueblesServidor {
  public tiendaDeMueblesServidor() { // El método constructor
   try {
    //Creamos la instancia de tiendaDeMuebles...
    tiendaDeMueblesImpl c = new tiendaDeMueblesImpl();

    //Le asignamos un nombre a la instancia para su uso remoto...
    Naming.rebind("rmi://localhost:1099/tiendaMuebles", c);
   } catch (Exception e) { System.out.println("Problema: " + e); }
  }

  public static void main(String args[]) {
    new tiendaDeMueblesServidor();
  }
}


Volver al Indice Resultados


Hemos conseguido que toda la práctica funcione con completa normalidad.

Para su correcto funcionamiento sera necesario indicar los parámetros de forma correcta. Siendo:


>tiendaDeMuebles comanda (Para ejecutar un nuevo pedido.)
>tiendaDeMuebles llistar_comandes (Para visualizar el listado de pedidos.)


RMI


Ventajas de usar RMI

Permite distribuir una aplicación de forma muy transparente, es decir, sin que el
programador tenga que modificar apenas el código. Además las invocaciones remotas
son más eficientes que las peticiones vía http que se usan con los cgis o los servlets.

Inconvenientes de usar RMI

El paso de parámetros por valor implica tiempo para hacer la serialización, enviar los objetos serializados a través de la red y luego volver a deserializarlos en el destino;
Sobretodo si los parámetros son objetos complejos.

Volver al Indice Conclusiones


Para poder realizar esta práctica hemos recurrido al ejemplo disponible que nos ha facilitado la información necesaria para comprender el funcionamiento del RMI.

Basándonos en la práctica de la sesión 3 hemos utilizado un vector para almacenar el listado de pedidos efectuados.

El primer paso ha sido declarar los métodos que necesitaríamos en nuestra interficie.
Apartir de este punto, hemos empezado la implementación de las clases necesarias.

Como último paso se ha realizado esta documentación apartir de los resultado obtenidos.