UNIVERSITAD DE LAS AMERICAS

Cholula, Puebla

MEXICO

 

SISTEMAS DISTRIBUIDOS - IS 417

PRÁCTICA III

(RMI)

 

INTRODUCCIÓN

 

En esta práctica revisaremos el procedimiento y las consideraciones a realizarse durante la construcción de una aplicación distribuida con Java RMI. Como caso de estudio tomaremos el desarrollo una aplicación simplificada de soporte a un sitio para la venta de artículos basado en un modelo de subastas (como lo hace eBay). El escenario típico de utilización de una aplicación de tal índole es el siguiente:

 

1                   Un usuario (jugando el rol de vendedor) se conecta y ofrece un producto, estableciendo un precio inicial y una fecha y hora límite de subasta.

 

2                   Los compradores potenciales, se conectan como usuarios corrientes, y tienen la posibilidad de visualizar el catálogo de productos disponibles a la compra. El comprador puede entonces seleccionar un producto y realizar una oferta. Cada comprador puede conectarse y ofertar sobre un producto varias veces, mientras el periodo de subasta es aún válido. Notemos que sólo se podrán hacer ofertas que sobrepasen el monto actual (el famoso juego del ¿Quién da más?).

 

3                   Al finalizar el periodo de la subasta, el producto es asignado al mejor postor. El vendedor puede entonces verificar los datos del comprador correspondiente, con los que se procederá a contactarlo y así concluir la venta.

 

Para su operación, tal aplicación debe considerar la administración centralizada de la siguiente información:

 

 

Notemos que analizar tal aplicación sería complejo, por lo que la versión propuesta es considerablemente mas sencilla.

 

 

 

IMPLEMENTACIÓN

 

 

 

Dividimos el codigo entre 10 archivos :

 

Quatro archivos siguiendo el modelo MVC por la aplicación centralizada (que va executarse en cada machinas clientes) :

Por la aplicacion distribuida, solo hemos cambiado el archivo SubastaModelo.

 

SubastaModelo.java

SubastaVista.java

SubastaControlador.java

Principal.java

 

 

Dos clases serializable por manejar los informaciones :

Por la aplicacion distribuida, hemos cambiado estas clases en “serializable”

 

InformacionOferta.java

InformacionProducto.java

 

 

El codigo de communicacion del lado cliente y su interfaz por RMI:

         Estos archivos permiten de construyir un objecto “cliente” que puede estar usado por el servidor por actualizar las vistas, po ejemplo.

 

SubastaClient.java

ClientInterfaz.java

           

 

El codigo del servidor y su interfaz por RMI :

            Servicios del servidor, en la aplicacion centralizada estaba el codigo del modelo.

 

SubastaInterfaz.java

SubastaServeur.java

 

 

 

 

SubastaVista.java

 

Implementacion de la interfaz de usuario (usando SWING).

 

import javax.swing.DefaultComboBoxModel;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JList;

import javax.swing.JScrollPane;

import javax.swing.JTextField;

import javax.swing.ListSelectionModel;

 

import java.awt.Container;

import java.awt.GridLayout;

import java.awt.Dimension;

import java.awt.event.ActionListener;

import javax.swing.event.ListSelectionListener;

 

public class SubastaVista {

    JFrame principal;

    JTextField usuario;

    JTextField producto;

    JTextField precioInicial;

    JTextField monto;

    DefaultComboBoxModel productos;

    JLabel precioActual;

    JList lista;

    JButton conectar;

    JButton salir;

    JButton ponerALaVenta;

    JButton obtenerLista;

    JButton ofrecer;

 

    public SubastaVista() {

        JFrame.setDefaultLookAndFeelDecorated(true);

                Container panel;

 

                principal = new JFrame("Cliente Subasta");

                panel = principal.getContentPane();

                panel.setLayout(new GridLayout(0, 2));

                usuario = new JTextField();

                panel.add(new JLabel("Nombre del usuario"));panel.add(usuario);

 

                conectar = new JButton("Conectar");

                salir = new JButton("Salir");

                panel.add(conectar); panel.add(salir);

 

 

                producto = new JTextField();

                precioInicial = new JTextField();

                panel.add(new JLabel("Producto a ofrecer")); panel.add(producto);

                panel.add(new JLabel("Precio inicial")); panel.add(precioInicial);

                ponerALaVenta = new JButton("Poner a la venta");

                panel.add(ponerALaVenta); panel.add(new JLabel());

 

                productos = new DefaultComboBoxModel();

                lista = new JList(productos); //data has type Object[]

                lista.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

                lista.setLayoutOrientation(JList.VERTICAL);

                JScrollPane listaScroller = new JScrollPane(lista);

                listaScroller.setPreferredSize(new Dimension(250, 80));

                obtenerLista = new JButton("Obtener lista");

                panel.add(obtenerLista); panel.add(listaScroller);

 

                precioActual = new JLabel();

                panel.add(new JLabel("Precio actual")); panel.add(precioActual);

               

                monto = new JTextField();

                ofrecer = new JButton("Ofrecer");

                panel.add(ofrecer); panel.add(monto);

 

                principal.setSize(400, 400);

                principal.setVisible(true);

    }

 

    public void asignarActionListener(ActionListener controlador) {

                conectar.addActionListener(controlador);

                salir.addActionListener(controlador);

                ponerALaVenta.addActionListener(controlador);

                obtenerLista.addActionListener(controlador);

                ofrecer.addActionListener(controlador);

    }

 

    public void asignarListSelectionListener(ListSelectionListener controlador) {

                lista.addListSelectionListener(controlador);

    }

 

    public String getUsuario() {

        return usuario.getText();

    }

 

    public String getProducto() {

        return producto.getText();

    }

 

    public float getPrecioInicial() {

        float resultado = 0.0f;

        try {

            resultado = Float.parseFloat(precioInicial.getText());

        } catch (Exception e) {

            System.out.println("Oops ... problemas con el precio inicial");

        }

        return resultado;

    }

    public void reinicializaListaProductos() {

        productos.removeAllElements();

    }

 

    public void agregaProducto(String prod) {

        productos.addElement(prod);

    }

    public void desplegarPrecio(String precio) {

        precioActual.setText(precio);

    }

 

    public float getMontoOfrecido() {

        float resultado = 0.0f;

        try {

            resultado = Float.parseFloat(monto.getText());

        } catch (Exception e) {

            System.out.println("Oops ... problemas con el monto ofrecido");

        }

        return resultado;

    }

    public String getProductoSeleccionado() {

        return (String)lista.getSelectedValue();

    }

}

 

 

 

 

 

 

 

 

 

SubastaControlador.java

 

 

Implementacion del controlador de la interfaz.

 

 

import java.awt.event.ActionListener;

import java.awt.event.ActionEvent;

 

import java.util.Hashtable;

import java.util.Vector;

import java.util.Enumeration;

 

import javax.swing.JList;

import javax.swing.event.ListSelectionListener;

import javax.swing.event.ListSelectionEvent;

 

public class SubastaControlador implements ActionListener,

                                                                                 ListSelectionListener {

    SubastaVista vista;

    SubastaModelo modelo;

    Hashtable listaConPrecios;

 

    public SubastaControlador(SubastaVista v, SubastaModelo m) {

        vista = v;

        modelo = m;

    }

 

 

    public void actionPerformed(ActionEvent evento) {

        String usuario;

        String producto;

        float monto;

 

                System.out.println("<<"+evento.getActionCommand()+">>");

 

                if (evento.getActionCommand().equals("Salir")) {

                    System.exit(1);

                } else if (evento.getActionCommand().equals("Conectar")) {

            usuario = vista.getUsuario();

            System.out.println("Registrarse como usuario: " + usuario);

            modelo.registraUsuario(usuario);

        } else if (evento.getActionCommand().equals("Poner a la venta")) {

            usuario = vista.getUsuario();

            producto = vista.getProducto();

            monto = vista.getPrecioInicial();

            System.out.println("Haciendo oferta del producto: " + producto);

            modelo.agregaProductoALaVenta(usuario, producto, monto);

        } else if (evento.getActionCommand().equals("Obtener lista")) {

            Vector lista = modelo.obtieneCatalogo();

            Enumeration it;

            InformacionProducto info;

            listaConPrecios = new Hashtable();

            vista.reinicializaListaProductos();

            it = lista.elements();

            while (it.hasMoreElements()) {

                info = (InformacionProducto) it.nextElement();           

                listaConPrecios.put(info.producto,

                                    String.valueOf(info.precioActual));

                vista.agregaProducto(info.producto);

            }

        } else if (evento.getActionCommand().equals("Ofrecer")) {

            producto = vista.getProductoSeleccionado();

            monto = vista.getMontoOfrecido();

            usuario = vista.getUsuario();

            modelo.agregaOferta(usuario, producto, monto);

        }

    }

 

    public void valueChanged(ListSelectionEvent e) {

                if (e.getValueIsAdjusting() == false) {

                    JList lista = (JList)e.getSource();

            String item = (String)lista.getSelectedValue();

            if (item != null) {

                        System.out.println(item);

                String precio = (String)listaConPrecios.get(item);

                vista.desplegarPrecio( precio );

            }

                }

    }

}

 

 

 

 

 

 

 

SubastaModelo.java

 

 

Ahora el modelo de la aplicacion esta solo una interfaz con la clase Cliente

 

 

 

import java.util.Vector;

 

public class SubastaModelo  {

 

                SubastaClient client;

               

                public SubastaModelo() {

                               try {

                                               client = new SubastaClient();

                               }

                               catch(java.rmi.RemoteException e) {

                System.err.println(" l'objet distant a déclenché l'erreur "+e);

                }

               

    }

 

    public boolean registraUsuario(String nombre) {

                               return client.registraUsuario(nombre);

                }

 

    public boolean agregaProductoALaVenta(String vendedor, String producto,

                                          float precioInicial) {

                               return client.agregaProductoALaVenta(vendedor,producto,precioInicial);

    }

 

    public boolean agregaOferta(String comprador, String producto,

                                float monto) {             

                    return client.agregaOferta(comprador,producto,monto);

    }

 

    public Vector obtieneCatalogo() {

                    return client.obtieneCatalogo();

    }

   

}

 

 

 

 

 

 

 

InformacionOferta.java

 

Clase serializable para administrar las ofertas.

 

 

public class InformacionOferta implements java.io.Serializable{

    String comprador;

    String producto;

    float monto;

    public InformacionOferta(String c, String p, float m) {

        comprador = c;

        producto = p;

        monto = m;

   }

}

 

 

 

 

 

 

 

InformacionProducto.java

 

Clase serializable para administrar los productos.

 

 

public class InformacionProducto implements java.io.Serializable{

    String vendedor;

    String producto;

    float precioInicial;

    float precioActual;

 

    public InformacionProducto(String v, String p, float pi) {

        vendedor = v;

        producto = p;

        precioInicial = pi;

        precioActual = pi;

    }

    public boolean actualizaPrecio(float monto) {

        if (monto > precioActual) {

            precioActual = monto;

            return true;

        } else

            return false;

    }

    public String getNombreProducto() {

        return producto;

    }

    public float getPrecioActual() {

        return precioActual;

    }

}

 

 

 

 

 

 

 

 

Principal.java

 

Programa principal

 

 

public class Principal {

    public static void main(String args[]) {

        SubastaVista vista;

        SubastaControlador controlador;

        SubastaModelo modelo;

 

        vista = new SubastaVista();

        modelo = new SubastaModelo();

        controlador = new SubastaControlador(vista, modelo);

        vista.asignarActionListener(controlador);

        vista.asignarListSelectionListener(controlador);

    }

}

 

 

 

 

 

 

 

 

ClientInterfaz.java

 

Interfaz que permite a el servidor de actualizar los clientes

 

 

import java.rmi.*;

 

public interface ClientInterfaz extends Remote{

   public void refreshClient() throws RemoteException;

}

 

 

 

 

 

 

 

SubastaClient.java

 

Implementacion del cliente, comunicacion con el servidor.

 

 

import java.rmi.*;

import java.rmi.server.UnicastRemoteObject;

import java.util.Vector;

 

 

public class SubastaClient extends UnicastRemoteObject implements ClientInterfaz, java.io.Serializable {

               

    private SubastaInterfaz obj;        

    

    public SubastaClient() throws RemoteException{

                try {

               System.setSecurityManager(new RMISecurityManager());

                                obj = (SubastaInterfaz) Naming.lookup("IS417/SubastaServeur");

                } 

               

                catch(Exception e) {

         System.err.println(" l'objet distant a déclenché l'erreur "+e);

                }

                }

               

                 public boolean registraUsuario(String nombre) {

                                boolean result=false;

                    try {

                                result=obj.registraUsuario(nombre,this);

                               

                }

                catch(RemoteException e) {

                                         System.err.println(" l'objet distant a déclenché l'erreur "+e);

                }

                   return result;

    }

   

   

    public boolean agregaProductoALaVenta(String vendedor, String producto,

                                          float precioInicial) {

                    boolean result=false;

                    try {

                                result=obj.agregaProductoALaVenta(vendedor,producto,precioInicial);

                }

                catch(RemoteException e) {

                                         System.err.println(" l'objet distant a déclenché l'erreur "+e);

                }

                return result;

    }

 

   

    public boolean agregaOferta(String comprador, String producto,

                                float monto) {

                                                

                    boolean result=false;

                    try {

                                return obj.agregaOferta(comprador,producto,monto);

                }

                catch(RemoteException e) {

                                         System.err.println(" l'objet distant a déclenché l'erreur "+e);

                }

                return result;

    }

 

   

    public Vector obtieneCatalogo() {

                    Vector result=null;

                    try {

                                result=obj.obtieneCatalogo();

                }

                catch(RemoteException e) {

                                         System.err.println(" l'objet distant a déclenché l'erreur "+e);

                }

                return result;

 

    }

   

    //Remote procedures

    public void refreshClient() throws RemoteException{     

      System.out.println("REFRESH");

   }

 

 }

 

 

 

 

 

 

 

 

 

SubastaInterfaz.java

 

Interfaz de los servicios del servidor

 

 

import java.rmi.*;

import java.util.Vector;

 

public interface SubastaInterfaz extends Remote {

   public boolean registraUsuario(String nombre, ClientInterfaz client) throws RemoteException;

   public boolean agregaProductoALaVenta(String vendedor, String producto,

                                                                                                                                                             float precioInicial)  throws RemoteException;

   public boolean agregaOferta(String comprador, String producto, float monto)  throws RemoteException;

   public Vector obtieneCatalogo()  throws RemoteException;

  

}

 

 

 

 

 

 

 

SubastaServeur.java

 

Implementacion de los servicios del servidor

 

import java.rmi.*;

import java.net.*;

import java.rmi.server.UnicastRemoteObject;

import java.util.Hashtable;

import java.util.Vector;

 

public class SubastaServeur extends UnicastRemoteObject implements SubastaInterfaz, java.io.Serializable {

 

    Hashtable usuarios;

    Hashtable productos;

    Hashtable ofertas;

    Vector clientes;

 

    private void refreshAllClients() {

                                for (int i=0; i<clientes.size();i++)

                                {

         ClientInterfaz client=(ClientInterfaz)(clientes.elementAt(i));

         try{

           client.refreshClient();

         }catch(Exception ex){

            System.out.println("Exception declenchee par RefreshALlClients");

            ex.printStackTrace();     

         }//fin catch

      }//fin for

                      

    }

   

    public SubastaServeur() throws RemoteException {

   // permet la communication par protocole TCP

        usuarios = new Hashtable();

        clientes = new Vector();

        productos = new Hashtable();

        ofertas = new Hashtable();

   }

 

  

   public boolean registraUsuario(String nombre,ClientInterfaz client) throws RemoteException {

        if (!usuarios.containsKey(nombre)) {

            System.out.println("Agregando un nuevo usuario: " + nombre);

            usuarios.put(nombre, nombre);

            clientes.addElement(client);

            return true;

        } else

            return false;

    }

 

    public boolean agregaProductoALaVenta(String vendedor, String producto,

                                          float precioInicial)  throws RemoteException {

          if(!usuarios.containsKey(vendedor)) {

                          System.out.println("Received request from unknown user "+vendedor+", ignoring it !");

                          return false;

                               }

                else {

                      if (!productos.containsKey(producto)) {

            System.out.println("User "+ vendedor +" agregando un nuevo producto: " + producto);

            productos.put(producto,

                          new InformacionProducto(vendedor, producto, precioInicial));

             refreshAllClients();

            return true;

        } else

            return false;

     }

    }

 

    public boolean agregaOferta(String comprador, String producto,

                                float monto)  throws RemoteException {

        if (productos.containsKey(producto)) {

            InformacionProducto infoProd;

            infoProd = (InformacionProducto) productos.get(producto);

            if (infoProd.actualizaPrecio(monto)) {

                ofertas.put(producto + comprador,

                            new InformacionOferta(comprador, producto, monto));

                refreshAllClients();

                return true;

            } else

                return false;

        } else

            return false;

    }

 

    public Vector obtieneCatalogo()  throws RemoteException {

                               Vector resultado;

                               resultado = new Vector(productos.values());

                               return resultado;

    }

   

   

   

    public static void main(String[] args) {

 

      try {

         SubastaInterfaz obj= new SubastaServeur();

        System.setSecurityManager(new RMISecurityManager());

         Naming.rebind("IS417/SubastaServeur",obj);

         System.out.println("le serveur est pret.");

      }

 

      // on récupère les RemoteException

      catch(RemoteException re){

         System.out.println("exception dans SubastaServeur.main:"+ re);

      }

 

      // on récupère les MalformedURLException

      catch(MalformedURLException e ){

         System.out.println("MalformedURLException:"+ e);

      }

 

   }

 

}

 

 

 

 

 

 

BUILD.BAT

 

Compilacion y generacion de los talones

 

del *.class

javac *.java

rmic SubastaServeur

rmic SubastaClient

echo [DONE]

 

 

 

 

Despues la complacion tenemos dos archivos mas : SubastaServeur_Stub.class y SubastaClient_Stub.class que son los interfazes bajo-nivel de rmi.

 

Ahora podemos executar la aplicacion (en tres ventanas diferentes) :

Ø      rmiregistry

Ø      java SubastaServeur

Ø      java Principal

 

El programa y las fuentes estan disponibles aqui

 

 

 

SECURITY

 

         We had added a SecurityManager before the bind and the lookup, so RMI can manage securized operations.

System.setSecurityManager(new RMISecurityManager());

 

For more informations, see : http://www.javaworld.com/javaworld/jw-11-1997/jw-11-hood.html

 

 

Pierre Derrier    #203293

pierre.derrier@laposte.net

 

(return to home lab)