Arquitectura RMI con Hibernate: Guía práctica de Controllers, DTO y Persistencia en Java

Informática y Telecomunicaciones10,97 KB

Arquitectura RMI con Hibernate en Java

Este documento describe la estructura de una aplicación cliente-servidor desarrollada con Java RMI y Hibernate, incluyendo el patrón Business Delegate, los controladores, los objetos DTO y el mapeo de relaciones de persistencia.

1. Lado del cliente

1.1 Controller

(en cliente) CONTROLLER (los métodos tienen remote y business exception)

  1. Instanciar el Controller.
  2. Crear el BusinessDelegate servidor: en el Controller, dentro de un try, invocar setServidor(new BusinessDelegate()); en los métodos agregar BusinessException y RemoteException.
  3. Ejemplo:
public Integer obtenerCantidadAlumnos() {
    Integer resultado = null;
    try {
        resultado = getServidor().cantidadAlumnos();
    } catch (RemoteException | BusinessException e) {
        e.printStackTrace();
    }
    return resultado;
}

1.2 Business Delegate (en repositorio)

  1. La clase implementa IAppRemote.
  2. Posee un atributo privado IAppRemote businessService.
  3. Constructor que establece la conexión con el servidor mediante Naming.lookup:
public BusinessDelegate() throws BusinessException {
    super();
    try {
        setBusinessService((IAppRemote) Naming.lookup(IAppRemote.URL_SERVICIO));
    } catch (Exception e) {
        throw new BusinessException(e.getMessage());
    }
}
  1. Ejemplo de método delegado:
public Integer cantidadAlumnos() throws RemoteException, BusinessException {
    return getBusinessService().cantidadAlumnos();
}

1.3 BusinessException (en repositorio)

BusinessException extiende de Exception e implementa Serializable. Su constructor recibe un mensaje: BusinessException(String mensaje) { super(mensaje); }.

2. Lado del servidor

2.1 Clase Server

  1. Instancia única de Server.
  2. Atributo privado ObjetoRemoto objetoRemoto.
private Server() {
    iniciar();
}

public void iniciar() {
    try {
        this.setObjetoRemoto(new ObjetoRemoto());
        LocateRegistry.createRegistry(IAppRemote.PORT_SERVICIO);
        Naming.bind(IAppRemote.URL_SERVICIO, getObjetoRemoto());
        System.out.println("Fíjate en: " + IAppRemote.URL_SERVICIO + " puerto: " + IAppRemote.PORT_SERVICIO);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

2.2 ServerMain (carpeta main del servidor)

public class ServerMain {
    public static void main(String[] args) {
        Server.getInstancia();
    }
}

2.3 DTO

Los DTO deben ser serializables y contener únicamente los atributos que se van a mostrar, con sus respectivos get y set.

2.4 DAO

Se instancia y contiene únicamente los métodos de acceso a datos. Flujo de datos: Base de datos → Entity → DAO → Objeto de negocio → Controller → DTO.

Session session = HibernateUtil.getSessionFactory().openSession();
Query query = session.createQuery("FROM AlumnoEntity a WHERE a.idAlumno = :id");
query.setParameter("id", id);
// query.list() o query.uniqueResult()

2.5 Interfaz IAppRemote (repositorio)

IAppRemote extiende Remote, IAlumnoRemote, etc.

private static final String URL_SERVICIO = "localhost/parcial";
private static final Integer PORT_SERVICIO = 1099;

ClienteDTO altaCliente(ClienteDTO cliente) throws RemoteException, BusinessException;
ClienteDTO modificacionCliente(ClienteDTO cliente) throws RemoteException, BusinessException;

2.6 ObjetoRemoto (carpeta RMI)

ObjetoRemoto extiende UnicastRemoteObject e implementa IAppRemote.

public class ObjetoRemoto extends UnicastRemoteObject implements IAppRemote {
    public ObjetoRemoto() throws RemoteException {
        super();
    }

    public Integer cantidadAlumnos() {
        return AlumnoController.getInstancia().cantidadAlumno();
    }

    public List obtenerAlumnosXnota(Integer nota) {
        return AlumnoController.getInstancia().alumnosPorNota(nota);
    }
}

2.7 Controller en el servidor

Posee una instancia del controlador y recibe objetos de negocio, devolviendo DTO.

public AlumnoDTO obtenerAlumnoPorId(Integer id) {
    Alumno alumnoObjetoNegocio = AlumnoDao.getInstancia().obtenerAlumnoPorId1(id);
    return alumnoObjetoNegocio.crearDto();
}

public List alumnosPorNota(Integer nota) {
    List listaA = AlumnoDao2.getInstancia().obtenerAlumnosPorNotas(nota);
    List listaAdto = null;
    if (!listaA.isEmpty()) {
        for (Alumno a : listaA) {
            listaAdto.add(a.crearDto());
        }
        return listaAdto;
    } else {
        return null;
    }
}

Los métodos de creación de DTO se ubican en la clase de negocio (por ejemplo, Alumno).

public AlumnoDTO crearDto() {
    AlumnoDTO dto = new AlumnoDTO();
    return dto;
}

public AlumnoDTO toDto() {
    AlumnoDTO dto = new AlumnoDTO();
    return dto;
}

2.8 Conversión de Entity a objeto de negocio

public Auto(AutoEntity entity) {
    if (entity != null) {
        setNumeroAuto(entity.getNumeroAuto());
        setChasis(new Chasis(entity.getChasis()));
        setMotor(new Motor(entity.getMotor()));
        setEscuderia(new Escuderia(entity.getEscuderia()));
    }
}

Del mismo modo, los objetos de negocio deben tener un constructor que reciba su DTO, por ejemplo public Alumno(AlumnoDTO alumno), asignando setNombre(alumno.getNombre()) y setEstado(alumno.getEstado()), y lo mismo para la entidad AlumnoEntity.

3. Persistencia con Hibernate / JPA

3.1 OneToOne

Unidireccional: @OneToOne y @JoinColumn(name="numeroMotor"), donde numeroMotor es el nombre de la columna en la tabla que referencia a motor.

Bidireccional: igual que lo anterior, y en la otra clase se agrega @OneToOne(mappedBy="nombreDeLaClaseEnLaOtra").

3.2 ManyToOne (unidireccional o bidireccional)

@ManyToOne
@JoinColumn(name="ID_otra_clase")
private Departamento departamento;

3.3 OneToMany (bidireccional con ManyToOne)

@OneToMany(mappedBy="departamento")
private List personas;

3.4 ManyToMany

No existe @JoinColumn. Ejemplo sin tabla intermedia explícita: en la clase Empleado se define @ManyToMany private Collection projects;, y en la clase Proyecto, @ManyToMany(mappedBy="projects") private Collection employees;.

Con tabla intermedia explícita:

@ManyToMany
@JoinTable(name="aditivacion",
    joinColumns=@JoinColumn(name="identificadorProducto"),
    inverseJoinColumns=@JoinColumn(name="identificadorAditivo"))
private List aditivos;
  • aditivacion: nombre de la tabla intermedia en la BD.
  • identificadorProducto: columna del id de producto en la tabla intermedia.
  • identificadorAditivo: columna del id de aditivo en la tabla intermedia.

3.5 Clave compuesta con entidad asociativa

AEntity

@OneToMany(cascade=CascadeType.ALL, mappedBy="key.entidadA")
private List listaAB;

BEntity

@OneToMany(cascade=CascadeType.ALL, mappedBy="key.entidadB")
private List listaAB;

ABEntity

@EmbeddedId
private ABEntityKey key;

ABEntityKey

@Embeddable
public class ABEntityKey implements Serializable {
    @ManyToOne(cascade=CascadeType.ALL, optional=false)
    private AEntity entidadA;

    @ManyToOne(cascade=CascadeType.ALL, optional=false)
    private BEntity entidadB;
}

4. HQL (Hibernate Query Language)

  • Producto cartesiano: FROM Usuario u, Permiso p WHERE u.id = 1
  • Inner join: FROM Usuario u INNER JOIN u.permisos AS p WITH p.estatus = 1
  • Selección de relación: SELECT dir FROM Usuario AS u INNER JOIN u.direccion AS dir
  • Conteo: SELECT COUNT(*) FROM Ciclo
  • Filtro por nombre: SELECT c.nombre FROM Ciclo c WHERE nombre = 'Desarrollo de aplicaciones Web'
  • Filtro por fecha: SELECT tb FROM TiposBasicos tb WHERE dateDate = '2012-07-25'
  • Rango: SELECT tb FROM TiposBasicos tb WHERE inte BETWEEN 1 AND 10
  • Valores nulos: SELECT tb FROM TiposBasicos tb WHERE dataDate IS NULL
  • Subconsulta: SELECT c.nombre, c.horas FROM Ciclo c WHERE c.horas > (SELECT AVG(c2.horas) FROM Ciclo c2)

5. Configuración de Hibernate

hibernate.connection.driver_class=net.sourceforge.jtds.jdbc.Driver
hibernate.connection.url=jdbc:jtds:sqlserver://bd;databaseName=ParcialAD_22
hibernate.connection.username=ParcialAD_22
hibernate.connection.password=ParcialAD_22
hibernate.connection.pool_size=1
hibernate.dialect=org.hibernate.dialect.SQLServerDialect
hibernate.show_sql=false
hibernate.format_sql=true
hibernate.hbm2ddl.auto=validate
hibernate.transaction.flush_before_completion=true
hibernate.transaction.auto_close_session=true

6. Clase HibernateUtil

public class HibernateUtil {
    private static HibernateUtil instancia;
    private SessionFactory sessionFactory;

    private HibernateUtil() {
        iniciar();
    }

    private void iniciar() {
        try {
            AnnotationConfiguration config = new AnnotationConfiguration();
            config.addAnnotatedClass(MarcaEntity.class);
            config.addAnnotatedClass(EscuderiaEntity.class);
            sessionFactory = config.buildSessionFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static HibernateUtil getInstancia() {
        if (instancia == null) {
            instancia = new HibernateUtil();
        }
        return instancia;
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

7. Resumen del flujo

Los controllers (por ejemplo, AlumnoController) son clases con instancia única. Sus métodos reciben objetos de negocio y devuelven DTO.

Descargar

PDF Word HTML