No es un bug, es una característica no documentada

30/1/16

Procesos y servicios. RMI (I)

En RMI intervienen dos progamas java que están ejecutándose en el mismo o distintos ordenadores.

Uno de ellos, llamado servidor, “publica” algunos de los objetos/clases que tiene instanciadas, es decir, los pone visibles desde la red, de forma que otros programas java puedan llamar a sus métodos.

El otro programa, llamado cliente, localiza en el servidor el objeto publicado y llama a sus métodos. Estos métodos se ejecutan en el programa servidor y devuelven un resultado (por el return habitual) que recoge el cliente en su ordenador.

El cliente se queda “colgado” en la llamada hasta que el servidor termina de ejecutar el código y devuelve un resultado.


Los objetos que comparten el servidor se conocen como objetos remotos.



a)      Se crea una interface (remota) con los métodos que queremos que se publiquen, es decir, los métodos que queremso que pueda llamar el cliente
·         Esta interface debe heredar de la interface Remote.
·         Todos los métodos de ésta interface deben lanzar una RemoteException.
b)      Se implementa la interface remota creando una clase que herede de UnicastREmoteObjet con un constructor que lance una RemoteException.

public class ObjetoRemoto extends java.rmi.server.UnicastRemoteObject implements InterfaceRemota{
      public ObjetoRemoto() throws java.rmi.RemoteException{super();}
      public int suma(int a, int b){
            return a + b;
      }
}

c)       Se compila de forma habitual
d)      Al fichero .class se le pasa el comando rmic (está en $JAVA_HOME/bin) para generar el objeto stub.

rmic paquete.ObjetoRemoto

e)      Se inicia el servicio de registro RMI. Antes de lanzar nuestro servidor, debemos lanzar un programa llamado rmiregistry que también viene con java (está en $JAVA_HOME/bin). Este programa es el que realmente sabe todos los objetos que se publican en este ordenador. La llamada Naming.rebind() en realidad coneca con rmiregistry en este ordenador y le avisa que ObjetoRemoto debe publicarse al exterior.
Rmiregistry necesita encontrar la clase ObjetoRemoto_Stub.class, así que en el servidor debemos fijar la propiedad java.rmi.server.codebase con el path, en formato url, desde el que rmiregistry puede acceder a esta clase.

System.setProperty("java.rmi.server.codebase", "file:/un_path/");

f)       Se lanza el servidor
g)      En el cliente. Se escribe la clase cliente

InterfaceRemota objetoRemoto = (InterfaceRemota)Naming.lookup("//IP_del_Servidor/ObjetoRemoto");
System.out.println("2 + 3 = ");
System.out.println(objetoRemoto.suma(2, 3));

h)      Se compila de forma habitual. Para compilar necesitaremos el fichero InterfaceRemota.class
i)        Se lanza el cliente. Si no hemos puesto RMISecurityManager, necesitaremos los ficheros InterfaceRemota.class y ObjetoRemoto_Stub.class para ejecutar.

Arrancar un RMISecurityManager y escribir un fichero java.policy de permisos es peligroso por lo siguiente:
  • Si no instalamos el RMISecurityManager, tenemos una seguridad por defecto bastante restrictiva. Si no sabemos, es mejor dejar la de defecto.
  • Si instalamos el RMISecurityManager, estamos habilitando una cosa llamada carga dinámica de clases. La carga dinámica de clases consiste en que un cliente pueda enviarnos una clase hecha por él y que no esté en el servidor. Esa clase puede tener código malicioso.
  • Si instalamos el RMiSecurityManager, las clases tanto del servidor como las cargadas dinámicamente de los clientes, tienen permiso para hacer aquellas cosas que se les permite en el fichero java.policy. Es decir, el fichero java.policy dice si una clase concreta tiene o no permisos para escribir o leer en disco duro, establecer sockets, etc. En muchos tutoriales, para evitar problemas en el ejemplo y no extenderse en explicaciones, ponen el fichero java.policy con todos los permisos para todo el mundo. Cualquier clase que venga de un cliente podría borrarnos el disco duro.
  • Por ello se aconseja no poner RMISecurityManager, salvo que se necesite carga dinámica de clases. En ese caso, no dejar el fichero java.policy con todos los permisos para todo el mundo.

Procesos y servicios. Programación de sockets (III)

Puedes leer las dos entradas anteriores pulsando en (I) o (II)

ObjectInputStream & ObjectOutputStream

Las clases ObjectInputStream y ObjectOutputStream nos permiten enviar objetos a través de sockets TCP.

ObjectOutputStream outObjeto = new ObjectOutputStream(socket.getOutoutStream());
ObjectInputStream inObjeto = new ObjectInputStream(socket.getInputStream());

Utilizaremos los métodos readObject() para leer el objeto del stream y writeObject() para escribir el objeto al stream.

Serialización

Para que un programa java pueda convertir un objeto en un montón de bytes y pueda luego recuperarlo, el objeto necesita ser Serializable. Al poder convertir el objeto a bytes, ese objeto se puede enviar a través de red, guardarlo en un fichero, y después reconstruirlo al otro lado de la red, leerlo del fichero…

Para que un objeto sea serializable basta con que implemente la interfaz Serialzable. Como la interfaz Serializable no tiene métodos, es muy sencillo implementarla, basta con un implements Serializable y nada más.

Si dentro de la clase hay atributos que son otras clases, éstos a su vez también deben ser Serializables. Con los tipos de java (String, Integer, etc.) no hay problema porque lo son. Si ponemos como atributo nuestras propias clases, éstas a su vez deben implementar Serializable.

Ejemplo

En el siguiente ejemplo vamos a ver como el programa servidor crea un objeto Persona, dándole valores y se lo envía al programa cliente, el programa cliente realiza los cambios oportunos en el objeto y se lo devuelve modificado al servidor.

ARCHIVO SERVIDOROBJETO.JAVA

import java.io.*;
import java.net.*;

public class ServidorObjeto {
     
      public static void main(String[] arg) throws IOException, ClassNotFoundException {
           
            int numeroPuerto = 6000;// Puerto
            ServerSocket servidor = new ServerSocket(numeroPuerto);
            System.out.println("Esperando al cliente.....");
            Socket cliente = servidor.accept();
           
            // Se prepara un flujo de salida para objetos
            ObjectOutputStream outObjeto = new ObjectOutputStream( cliente.getOutputStream());
           
            // Se prepara un objeto y se envía
            Persona per = new Persona("Juan", 20);
            outObjeto.writeObject(per);
           
            //enviando objeto
            System.out.println("Envio: " + per.getNombre() +"*"+ per.getEdad());
           
            // Se obtiene un stream para leer objetos
            ObjectInputStream inObjeto = new ObjectInputStream( cliente.getInputStream());
            Persona dato = (Persona) inObjeto.readObject();
            System.out.println("Recibo: " + dato.getNombre() + "*" + dato.getEdad());
           
            // CERRAR STREAMS Y SOCKETS
            outObjeto.close();
            inObjeto.close();
            cliente.close();   
            servidor.close();
           
      }// Fin de main
     
}// Fin de ServidorObjeto

ARCHIVO CLIENTEOBJETO.JAVA

import java.io.*;
import java.net.*;

public class ClienteObjeto {
     
      public static void main(String[] arg) throws IOException, ClassNotFoundException {
           
            String Host = "localhost";
            int Puerto = 6000;//puerto remoto
            System.out.println("PROGRAMA CLIENTE INICIADO....");
            Socket cliente = new Socket(Host, Puerto);
                 
            //Flujo de entrada para objetos
            ObjectInputStream perEnt = new ObjectInputStream(cliente.getInputStream());
           
            //Se recibe un objeto
            Persona dato = (Persona) perEnt.readObject();
           
            //recibo objeto
            System.out.println("Recibo: " + dato.getNombre() + "*" + dato.getEdad());
           
            //Modifico el objeto
            dato.setNombre("Juan Ramos");
            dato.setEdad(22);
           
            //FLUJO DE salida para objetos
            ObjectOutputStream perSal = new ObjectOutputStream( cliente.getOutputStream());
           
            // Se envía el objeto
            perSal.writeObject(dato);
            System.out.println("Envio: " + dato.getNombre() + "*" + dato.getEdad());
           
            // CERRAR STREAMS Y SOCKETS
            perEnt.close();
            perSal.close();
            cliente.close();
           
      }// Fin de main
     
}// Fin de ClienteObjeto

ARCHIVO PERSONA.JAVA

import java.io.Serializable;

@SuppressWarnings("serial")
public class Persona implements Serializable {
     
      String nombre;
      int edad;
     
      public Persona(String nombre, int edad) {
            super();
            this.nombre = nombre;
            this.edad = edad;
      }
      public Persona() { super(); }
     
      public String getNombre() {  return nombre; }
      public void setNombre(String nombre) { this.nombre = nombre; }
      public int getEdad() { return edad; }
      public void setEdad(int edad) {this.edad = edad; }

}// Fin de Persona

Envío de objetos a través de Sockets UDP

Utilizaremos las clases ByteArrayOutputStream y ByteARrayInputStream. Se necesita convertir el objeto a un array de bytes.

Persona persona = new Persona("Maria", 22);

// Convertimos objeto a bytes
ByteArrayOutputStream bs = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bs);

// Escribir objeto a bytes
out.writeObject(persona);

// Cerrar stream
out.close();

// Objeto en bytes
byte[] bytes = bs.toByteArray();

Para convertir los bytes recibidos por el datagrama en un objeto Persona escribimos:

// Recibo datagrama
byte[] recibidos = new byte[1024];
DatagramPacket paqRecibido = new DatagramPacket(recibidos, recibidos.length);
socket.receive(paqRecibido); // recibo el datagrama

// Convertirmos bytes a objetos
ByteArrayInputStream bais = new ByteArrayInputStream(recibidos);
ObjectInputStream in = new ObjectInputStream(bais);

// Obtengo objeto
Persona persona = (Persona)in.readObject();


in.close(); // Cerrar stream

26/1/16

Instalación y configuración de Hibernate en Eclipse

21:10 Posted by Inazio Claver , 29 comments
Hibernate es una herramienta de mapeo objeto – relacional de software libre para la plataforma Java (y para .Net también pero llamándose NHibernate).

Hibernate nos facilita el mapeo de atributos entre una base de datos relacional tradicional, como puede ser una basada en MySQL por ejemplo, y el modelo de objetos de una aplicación, mediante archivos XML o anotaciones en los beans de las entidades que permiten establecer estas relaciones.

Es decir, busca solucionar el problema de la diferencia entre los dos modelos de datos que coexisten en una aplicación: El que usa la memoria del ordenador, que estará orientado a objetos, y el usado en las bases de datos, modelo relacional.
Se “monta” una capa intermedia que permite manipular la información de la base de datos operando sobre objetos, con todas las características que tiene la programación orientada a objetos.

Convertirá los datos en tipos utilizados por Java y definidos por SQL, generará las sentencias SQL liberando al desarrollador de su manejo manual y mantendrá la portabilidad entre todos los motores de bases de datos, eso sí, con el coste de incrementar (ligeramente) el tiempo de ejecución.

21/1/16

Procesos y servicios. Programación de Sockets (II)

Puedes leer la entrada anterior pulsando en (I)

Conexión de múltiples clientes. Hilos

Un único servidor con la clase ServerSocket e invocar al método accept() para esperar las peticiones de conexión de los clientes.

Cuando un cliente se conecta, el método accept() devuelve un objeto Socket, éste se usará para crear un hilo cuya misión es atender a este cliente.

Después se vuelve a invocar a accept() para esperar a un nuevo cliente; habitualmente la espera de conexiones se hace dentro de un bucle infinito.

Archivo Servidor.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Servidor {
     
      public static void main(String args[]) throws IOException {
           
            ServerSocket servidor;
            servidor = new ServerSocket(6000);   
            System.out.println("Servidor iniciado...");
            while (true) {
                  Socket cliente = new Socket();
                  cliente=servidor.accept();//esperando cliente
                  HiloServidor hilo = new HiloServidor(cliente);
                  hilo.start(); //Se atiende al cliente
                 
            }// Fin de while
      }// Fin de main
}// Fin de Servidor

Clases para Sockets UDP

Los Sockets UDP son más simples y eficientes que los TCP pero no está garantizada la entrega de paquetes.

No es necesario establecer una “conexión” entre cliente y servidor, como en el caso de TCP.

Los datagramas deben contener explícitamente la dirección IP y el puerto de destino.


El paquete del datagrama está formado por los siguientes campos:

20/1/16

Procesos y servicios. Programación de Sockets (I)

¿Qué son los sockets?

Los protocolos TCP y UDP utilizan la abstracción de sockets para proporcionar los puntos extremos de la comunicación entre aplicaciones o procesos.

Para los procesos receptores de mensajes, su conector debe tener asociado dos campos:
  • La dirección IP del host en el que la aplicación está corriendo.
  • El puerto local a través del cual la aplicación se comunica y que identifica el proceso.



Procesos y servicios. Programación en red

TCP/IP

Nivel de Transporte


TCP: Protocolo basado en la conexión, garantiza que los datos enviados desde un extremo de la conexión llegan al otro extremo y en el mismo orden en que fueron enviados. De lo contrario, se notifica un error.

UDP: No está basado en la conexión como TCP. Envía paquetes de datos independientes, denominados datagramas, de una aplicación a otra; el orden de entrega no es importante y no se garantiza la recepción de los paquetes enviados.

19/1/16

Programación multimedia. Intents implícitos

Cuando queremos interactuar con nuestro dispositivo Android desde una aplicación programada por nosotros, le deberemos indicar dos cosas:
  • Como queremos que se comporte nuestra aplicación (puede ser usando una funcionalidad del sistema que integremos en nuestra app, como ya vimos anteriormente al programar el navegador web), o la segunda opción, es decir que desde nuestra aplicación se ejecute algún proceso del sistema operativo independiente de nuestra app, como podría ser abrir la cámara de fotos, la aplicación de Gmail…
  • Los permisos que debemos atribuirle al Manifest para poder hacer uso de ese recurso del sistema.

En esta sección nos centraremos en la opción de lanzar recursos del sistema operativo desde nuestra app, a través de intents implícitos.

Para explicarlo en mejor detalle, vamos a realizar paso a paso el siguiente ejercicio:

Ejercicio: Realiza un proyecto de una aplicación semejante a la de la siguiente imagen



16/1/16

Programación multimedia. Configurar GenyMotion para Android Studio

A estas alturas, a no ser que tengamos un pepino de ordenador, nos habremos dado cuenta de que el emulador de smartphones de Android Studio va bastante lento, tarda en cargarse…

Por eso quiero hablaros de GenyMotion, un excelente emulador de Android que permitirá testear las aplicaciones y que es muy superior (es mi opinión) al que trae integrado por defecto Android Studio.

GenyMotion es una máquina virtual creada desde VirtualBox, que nos permitirá emular varios dispositivos que ya están preconfigurados y deberemos descargar, o modificar para poder crearnos el nuestro propio.

Lo primero es descargarnos la versión gratuíta del software desde la página oficial https://www.genymotion.com/#!/ (previa creación de una cuenta) y lo instalamos.


Abrimos el panel de control de la aplicación y pulsar sobre el botón de + para añadir un nuevo dispositivo Smartphone.