Ivy

Ivy: Herramienta para gestión de dependencias más cómoda y fácil que MAVEN. Descargar

Struts Minimal

Pincha aquí para ver como se crea un proyecto Struts con las API´s básicas (está en inglés).

Objeto Criteria de Hibernate

Pincha aquí para ver ejemplos de Criteria.

HQL (Hibernate Query Language)

Pincha aquí para ver las API´s de HQL.

Pincha aquí para ver ejemplos de HQL.

Crear proyecto Servlet con Maven para Eclipse

Antes de comenzar, necesitas tener instalado Maven en tu equipo y el plugin de éste para el Eclipse ( pincha aquí para ver una introducción y vínculos de instalación) . A continuación, sigue los siguientes pasos:
  1. Accede a la consola y nos ubícate en el workspace del Eclipse.

  2. Ejecuta el siguiente comando: mvn archetype:create -DgroupId=nuestroservlet -DartifactId=miproyectoServlet -DarchetypeArtifactId=maven-archetype-webapp . En el parámetro DartifactID se indica el nombre del proyecto. Para Maven, todo proyecto ha de estar engloblado en un grupo, para ello usa el parámetro DgroupId.

  3. El comando anterior creará un nuevo directorio en tu workspace cuyo nombre coincide con el que le hayas puesto a tu proyecto (parámetro DartifactId). Accede a él. Podrás observar, que en él, hay un fichero llamado pom.xml, ¿ Te suena verdad ? :p.

  4. Lanza: mvn -Declipse.workspace="la ruta del workspace" eclipse:add-maven-repo. Cuidado! Lo que esta entrecomillado debes de poner la ruta del workspace. Esto añade una variable nueva (M2_REPO) al Eclipse para sepa donde esta el repositorio (puedes comprobarlo arrancando Eclipse y luego en Windows->Preferences->Classpath Variables).

  5. Si estas ubicado en la raiz del nuevo proyecto, lanza mvn eclipse:eclipse .

  6. Ya puedes cerrar la consola ya que se ha terminado de crear el proyecto Servlet. Arranca eclipse y abre un nuevo proyecto java existente.

  7. Crea tus Source Folder necesarios (por ejemplo: src/main/java , src/main/resources , src/main/webapp y src/test/java). Estos source folder han de tener concordancia con el fichero build.xml.

  8. Edita el fichero pom.xml y añade las dependencias y plugins necesarios para la futura aplicación web. Observa que en él se refleja el grupo y el artificio que le has puesto previamente. Una forma de editar el fichero pom.xml automáticamente, es activar maven en el eclipse (paso 9) y luego boton derecho sobre dicho fichero para añadir las dependencias y plugin. Un ejemplo sería:

    <?xml version="1.0" encoding="UTF-8"?><project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>nuestroservlet</groupId>
    <artifactId>miproyectoServlet</artifactId>
    <packaging>war</packaging>
    <name>miproyectoServlet Maven Webapp</name>
    <version>1.0-SNAPSHOT</version>
    <url>http://maven.apache.org</url>
    <build>
    <finalName>miproyectoServlet</finalName>
    <plugins>
    <!-- Necesario.Indicamos la versión del jre que utilizará
    el plugin maven para el eclipse.-->

    <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
    <source>1.5</source>
    <target>1.5</target>
    </configuration>
    </plugin>
    </plugins>
    </build>
    <dependencies>
    <!-- Necesario, ya que contiene las API de los Servlet.-->
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.4</version>
    <scope>compile</scope>
    </dependency>
    <!-- Necesario si usamos TDD con TestNG en vez de JUnit.-->
    <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>5.1</version>
    <classifier>jdk15</classifier>
    <scope>test</scope>
    </dependency>
    <!--Necesario en caso de que se trabaje con el fichero build.xml
    de ANT. -->

    <dependency>
    <groupId>org.apache.maven</groupId>
    <artifactId>maven-ant-tasks</artifactId>
    <version>2.0.7</version>
    </dependency>
    </dependencies>
    </project>

  9. Activa Maven (boton derecho sobre el proyecto, Maven2->Enable).

  10. Haz un Update Source Folder.

  11. Inserta en la raiz del proyecto el fichero build.xml de ANT. En este haz de poner la ruta del Tomcat. Si no tienes ganas de crearte uno, haz un copy-paste desde otro proyecto (aplicación web) que lo tenga.

  12. DeployWar.

  13. Comprueba en el browser si todo ha salido con éxito (éste ha de mostrar Hello World!, que es el ejemplo que viene por defecto).

  14. A partir de aquí, modifica y crea tus propios servlet modificando previamente el fichero web.xml.

Todo esto ha sido sacado de las siguientes URL´s:

Hibernate con un ejemplo

El framework Hibernate es una herramienta de Mapeo objeto-relacional (ORM) para la plataforma Java ( NHibernate para la plataforma .Net) empleando para ello JPA (Java Persistence API). Esta herramienta nos permite manipular los datos del DBMS operando sobre objetos de nuestra aplicación, siendo éstos persistentes y cumpliendo las características de la OOP.

Para utilizar dicho framework, lo primero que hemos de hacer es descargarnos obviamente las API´s correspondientes ( Descargar núcleo de Hibernate). Los ficheros de configuración estas basados en XML , pero si queremos deshacernos de ello y usar anotaciones, además, hemos de descargarnos la siguiente API: Descargar anotaciones de Hibernate.

Descomprimimos el fichero, y comprobamos que por defecto, este ya trae un ejemplo ya hecho. Lo único que nos interesa son los .jars y los ficheros de configuración.

Creamos un nuevo proyecto java en el eclipse y una vez creado, creamos dos sources folders:
  1. src en donde colocaremos nuestros códigos fuentes.
  2. test para realizar las pruebas, ya que aplicaremos TDD.

A continuación, creamos un nuevo directorio llamado lib, en donde colocaremos nuestras librerías, siendo en este caso los .jars de Hibernate (estos son los contenidos en el directorio lib del paquete extraido y el .jar del directorio raíz de éste). También hemos de incluir obligatoriamente en lib el driver JDBC según la base de datos con la que vayamos a trabajar (MySQL según ejemplo). Opcionalmente, pero recomendable, pondremos las librerías EasyMock, TestNG... Luego refrecamos nuestro proyecto y añadimos todas las librerías al build path.

En cuanto a los ficheros de configuración, copiamos los ficheros hibernate.cfg.xml y log4j.properties ubicados en doc\tutorial\src y lo pondremos en nuestro source folder src. Por mayor comodidad, usaremos ant en nuestro proyecto, así que copiaremos build.xml del directorio doc\tutorial y lo pondremos en el raiz de nuestro proyecto.Configuración de Hibernate (hibernate.cfg.xml) para MySQL :

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

<!-- API´s del driver JDBC-->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>

<!-- URL de la base de datos, junto parámetros correspondientes -->
<property name="connection.url">
jdbc:mysql://localhost/myhibernate?createDatabaseIfNotExist=true
</property>

<!-- Usuario y contraseña de la base de datos -->
<property name="connection.username">root</property>
<property name="connection.password">root</property>

<!-- Carga de transacciones, relacionado con el rendimiento de la BB.DD. -->
<property name="connection.pool_size">1</property>

<!-- Versión de la BB.DD. En este ejemplo,versión 5 de MySQL-->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>

<!-- Gestión automática de las sesiones de Hibernate a través de hilos-->
<property name="current_session_context_class">thread</property>

<!-- Caché de los datos ya extraidos de la BB.DD. -->
<property name="cache.provider_class">
org.hibernate.cache.NoCacheProvider
</property>

<!-- Muestra sentencias SQL por la consola -->
<property name="show_sql">true</property>

<!-- Relacionado con el arranque.
También podría ser create-drop(borra antes el catálogo) -->

<property name="hbm2ddl.auto">create</property>

<!-- Mapeo de objetos persistentes -->
<mapping resource="Ruta/Fichero.hbm.xml"/>

</session-factory>

</hibernate-configuration>


Si tienes algún problema a la hora de configurar el driver JDBC , tal vez te sirva de ayuda este fichero (No abrir con bloc de notas).

En el fichero log4j.xml, podemos configurar el tipo de salida que muestre por la consola (recordamos que los principales son, de mayor prioridad a la de menos: DEBUG, INFO, WARN y ERROR).

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">

<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%p - %C{1}.%M(%L)%m%n"/>
</layout>

</appender>

<logger name="net.sf.ehcache">
<level value="ERROR"/>
</logger>

<logger name="org.apache">
<level value="WARN"/>
</logger>

<logger name="org.hibernate">
<level value="INFO"/>
</logger>

<!-- Suppress warnings from Commons Validator -->
<logger name="org.apache.commons.validator.ValidatorResources">
<level value="ERROR"/>
</logger>

<!-- Suppress invalid warning messages from JSF -->
<logger name="org.apache.myfaces.shared_impl.renderkit.html">
<level value="ERROR"/>
</logger>

<logger name="nombre.paquete">
<level value="INFO"/>
</logger>

<root>
<level value="WARN"/>
<appender-ref ref="CONSOLE"/>
</root>

</log4j:configuration>


Todo lo comentado, ha sido relacionado con la instalación y configuración de hibernate, ya va siendo hora de ir al grano ....

Toda aplicación, necesita un único objeto perteneciente a la clase SessionFactory, que como su nombre indica se trata de una fábrica de sesiones. Luego, le pediremos sesiones a éste, mediante los cuales, podremos hacer transacciones con la base de datos. Veamos un ejemplo de como se crea :


package es.nuwi.hotel.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {


public static SessionFactory getSessionFactory() {

SessionFactory sessionFactory;
try {

// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration().configure()
.buildSessionFactory();

} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Error al crear la factoría de sesiones." + ex);
throw new ExceptionInInitializerError(ex);
}
return sessionFactory;

}

}

El ejemplo que usaremos tendrá la siguientes asociaciones-relaciones:

Como observamos un hotel va a tener n empleados y n habitaciones. Cada empleado puede trabajar en más de un hotel. Una habitación pertenece a un hotel y suponemos que en una habitacion sólo va a ver un único cliente. El cliente solo podrá alquilar una única habitación. En nuestro ejemplo, usaremos asociaciones bidireccionales en vez de unidireccionales.

Creamos los POJOS, los cuales serán objetos persistentes. Éstos han de llevar obligatoriamente una propiedad de tipo Long :

Fichero Hotel.java :

package es.nuwi.hotel.objpersistentes;

import java.util.HashSet;
import java.util.Set;


public class Hotel {

private Long id;
private String nombreHotel;
private Set<Empleados> empleados=new HashSet<Empleados>();
private Set<Habitacion> habitaciones=new HashSet<Habitacion>();


public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getNombreHotel() {
return nombreHotel;
}

public void setNombreHotel(String nombre) {
this.nombreHotel = nombre;
}

public Set<Empleados> getEmpleados() {
return empleados;
}

public void setEmpleados(Set<Empleados> empleados) {
this.empleados = empleados;
}

public Set<Habitacion> getHabitaciones() {
return habitaciones;
}

public void setHabitaciones(Set<Habitacion> habitaciones) {
this.habitaciones = habitaciones;
}

}

Fichero Empleado.java :

package es.nuwi.hotel.objpersistentes;

import java.util.Set;


public class Empleado {

private Long id;
private String dniEmpleado;
private Set<Hotel> hoteles;


public String getDniEmpleado() {
return dniEmpleado;
}

public void setDniEmpleado(String dniEmpleado) {
this.dniEmpleado = dniEmpleado;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getNombreEmpleado() {
return dniEmpleado;
}

public void setNombreEmpleado(String nombreEmpleado) {
this.dniEmpleado = nombreEmpleado;
}

public Set<Hotel> getHoteles() {
return hoteles;
}

public void setHoteles(Set<Hotel> hoteles) {
this.hoteles = hoteles;
}

}


Fichero Habitacion.java :

package es.nuwi.hotel.objpersistentes;

public class Habitacion {

private Long id;
private Hotel hotel;
private CLiente cliente;


public CLiente getCliente() {
return cliente;
}

public void setCliente(CLiente cliente) {
this.cliente = cliente;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public Hotel getHotel() {
return hotel;
}

public void setHotel(Hotel hotel) {
this.hotel = hotel;
}

}

Fichero Cliente.java :

package es.nuwi.hotel.objpersistentes;

import java.util.Calendar;


public class CLiente {

private Long id;
private String dniCliente;
Calendar fechaAlquiler;
Habitacion habitacion;


public Habitacion getHabitacion() {
return habitacion;

}


public void setHabitacion(Habitacion habitacion) {
this.habitacion = habitacion;

}


public Long getId() {
return id;
}


public void setId(Long id) {
this.id = id;
}


public String getDniCliente() {
return dniCliente;
}


public void setDniCliente(String dniCliente) {
this.dniCliente = dniCliente;
}


public Calendar getFechaAlquiler() {
return fechaAlquiler;
}


public void setFechaAlquiler(Calendar fechaAlquiler) {
this.fechaAlquiler = fechaAlquiler;
}
}

Configuramos las asociaciones antes mencionadas. Para tener una cierta concordancia, los nombres de estos ficheros coinciden con los de la clase y cuya extensión es .xbm.xml, aunque no tiene siempre porque ya que en un mismo fichero pueden asociarse varias clases y en cuanto a la extensión, ésta puede ser cambiada. Para que no de ningún error, la propiedad tipo Long ha de ser la primera :

Fichero Hotel.hbm.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="es.nuwi.hotel.objpersistentes.Hotel" table="Hotel">
<id name="id" column="Hotel_id" unsaved-value="null">
<generator class="native" />
</id>
<property name="nombreHotel" column="nombreHotel" not-null="true"/>

<!-- ONE-TO-MANY -->
<set name="habitaciones" cascade="all" >
<key column="hotel_id"/>
<one-to-many class="es.nuwi.hotel.objpersistentes.Habitacion"/>
</set>

<!-- MANY-TO-MANY. SE CREA UNA TABLA INTERMEDIA -->
<set name="empleados" cascade="all" table="empleados_hoteles">
<key column="Hotel_id"/>
<many-to-many class="es.nuwi.hotel.objpersistentes.Empleado"
column="Empleado_id" />
</set>
</class>
</hibernate-mapping>

Fichero Empleado.hbm.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="es.nuwi.hotel.objpersistentes.Empleado"
table="Empleados">
<id name="id" column="Empleado_id" unsaved-value="null">
<generator class="native" />
</id>
<property name="dniEmpleado" column="dniEmpleado" not-null="true"/>
<!-- MANY-TO-MANY.

SE CREA UNA TABLA INTERMEDIA, ES LA MISMA QUE LA DE ANTES. -->

<set name="hoteles" cascade="all" table="empleados_hoteles">
<key column="Empleado_id"/>
<many-to-many class="es.nuwi.hotel.objpersistentes.Hotel"
column="Hotel_id" />
</set>
</class>
</hibernate-mapping>

Fichero Habitacion.hbm.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="es.nuwi.hotel.objpersistentes.Habitacion"
table="Habitacion">
<id name="id" column="Habitacion_id" unsaved-value="null">
<generator class="native" />
</id>
<!-- MANY-TO-ONE -->
<many-to-one name="hotel" column="hotel_id"
class="es.nuwi.hotel.objpersistentes.Hotel" />
<!-- ONE-TO-ONE -->

<one-to-one name="cliente" property-ref="habitacion" />
</class>
</hibernate-mapping>

Fichero Cliente.hbm.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="es.nuwi.hotel.objpersistentes.Cliente"
table="Clientes">
<id name="id" column="Cliente_id" unsaved-value="null">
<generator class="native" />
</id>
<property name="dniCliente" column="dniCliente" not-null="true" />
<property name="fechaAlquiler" type="java.util.Date"
column="fechaAlquiler" not-null="true" />

<!-- MANY-TO-ONE, AUNQUE REALMENTE VIENE DE UN ONE-TO-ONE -->
<many-to-one name="habitacion" column="HabitacionCliente"
unique="true" not-null="true"/>
</class>
</hibernate-mapping>

Estas configuraciones han sido sacadas de la siguiente URL: http://www.hibernate.org/hib_docs/reference/en/html/associations.html.Veamos el reflejo del ejemplo sobre el DBMS:

  1. Al crear una relación MANY-TO-MANY se ha creado una nueva tabla ( empleados-hoteles ) con dos campos primarios (hotel_id y empleado_id) los cuales son además claves ajenas (foreign key) de las tablas hotel y empleado respectivamente. Recordamos que una clave ajena apunta a los campos primarios de otra tabla.

  2. Al hacer uso de un ONE-TO-MANY y MANY-TO-ONE, de este segundo (many-to-one, es decir, de la tabla habitacion) se crea una columna sienda esta clave ajena de la clave primaria de la primera ( one-to-many, es decir,de la tabla hotel ) .

  3. En cuanto a ONE-TO-ONE , es exactamente igual igual que el anterior, con la única diferencia de que la clave ajena es además unique (no admite valores repetidos para esa columna). Según el ejemplo, se crea un nuevo campo de la tabla cliente la cual referencia a la clave primaria de la tabla habitacion siendo además único para esta columna.

Por último, lo único que nos queda es mapear los objetos persistentes. Para ello, añadimos las siguientes entradas en el fichero hibernate.cfg.xml, siendo estas entradas la ruta más el nombre en la que se encuentran los ficheros .hbm.xml de nuestro proyecto :

<mapping resource="es/nuwi/hotel/objpersistentes/Hotel.hbm.xml"/>
<mapping resource="es/nuwi/hotel/objpersistentes/Empleado.hbm.xml"/>
<mapping resource="es/nuwi/hotel/objpersistentes/Cliente.hbm.xml"/>
<mapping resource="es/ " / " /objpersistentes/Habitacion.hbm.xml"/>

Otra característica de este framework, es que podemos crear un fichero llamado import.sql ( ha de llamarse así obligatoriamente ) el cual contiene sentencias SQL (DDL,LMD,...). Esto es de gran utilidad ya que podemos insertar tuplas en nuestro DBMS y hacer pruebas para ver el funcionamiento de nuestra aplicación. En nuestro ejemplo, insertaremos nuevas tuplas :


insert into Hotel(Hotel_id,nombreHotel) values (1,'Hotel LG')
insert into Hotel(Hotel_id,nombreHotel) values (2,'Hotel Nuwi')

insert into Empleados (Empleado_id,dniEmpleado) values (1,'Mawi')
insert into Empleados (Empleado_id,dniEmpleado) values (2,'Ana')
insert into Empleados (Empleado_id,dniEmpleado) values (3, 'María')

insert into Empleados_Hoteles (Hotel_id,Empleado_id) values (1,1)
insert into Empleados_Hoteles (Hotel_id,Empleado_id) values (1,2)
insert into Empleados_Hoteles (Hotel_id,Empleado_id) values (2,3)

insert into Habitacion (Habitacion_id,Hotel_id) values (1,1)
insert into Habitacion (Habitacion_id,Hotel_id) values (2,1)
insert into Habitacion (Habitacion_id,Hotel_id) values (3,2)

insert into Clientes (Cliente_id,dniCliente,fechaAlquiler,HabitacionCliente) values (1,'28765342H','2008-1-19 11:15',1)
insert into Clientes (Cliente_id,dniCliente,fechaAlquiler,HabitacionCliente) values (2,'49382718L','2008-2-21 14:45',2)
insert into Clientes (Cliente_id,dniCliente,fechaAlquiler,HabitacionCliente) values (3,'27272129P','2008-4-19 19:30',3)

Hibenate soporta 3 tipos de herencia:

  • Tabla para clase padre e hijas (se admiten valores nulos).
  • Tabla por cada subclase (no se admiten valores nulos).
  • Tabla por cada clase concreta (No abstracta), tanto padre como hijas.(no valores nulos).

He aquí un ejemplo del primer caso: La clases Cliente tendrá dos subclases, los que pagen en efectivo, donde guardaremos el importe y los que pagen por tarjeta de crédito, donde guardaremos el número de dicha tarjeta :

Creamos los POJO´s de las dos subclases:

Fichero ClienteEfectivo :

package es.nuwi.hotel.objpersistentes;

public class ClienteEfectivo extends Cliente{
private int cantidadEfectivo;

public int getCantidadEfectivo() {
return cantidadEfectivo;
}

public void setCantidadEfectivo(int efectivo) {
this.cantidadEfectivo = efectivo;
}
}

Fichero ClienteTarjeta:

package es.nuwi.hotel.objpersistentes;

public class ClienteTarjeta extends Cliente{
private String numeroTarjeta;

public String getNumeroTarjeta() {
return numeroTarjeta;
}

public void setNumeroTarjeta(String numeroTarjeta) {
this.numeroTarjeta = numeroTarjeta;
}
}

Modificamos el fichero Cliente.hbm.xml. Para ello, es necesario crear una nueva columna en la tabla Cliente (discriminador tipoCliente, éste no esta reflejado en ningún campo de la clase), situada obligatoriamente como segunda posición para que no de ningún error (recordamos que la primera es el Primary Key de tipo Long). Dicho discriminador ha de ser de tipos String y no puede contener valores nulos. Luego se especifican los nuevos campos de las subclases pudiendo éstos contener valores nulos y el valor del discriminador que van a usar. El fichero quedaría de la siguiente manera :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="es.nuwi.hotel.objpersistentes.Cliente"
table="Clientes">
<id name="id" column="Cliente_id" unsaved-value="null">
<generator class="native" />
</id>
<!-- DISCRIMINADOR-->
<discriminator column="tipocliente" not-null="true" type="string"/>
<!--Resto de propiedades de la clase madre -->
<property name="dniCliente" column="dniCliente" not-null="true"/>
<property name="fechaAlquiler" type="java.util.Date"
column="fechaAlquiler" not-ull="true"/>
<!-- MANY-TO-ONE, AUNQUE REALMENTE VIENE DE UN ONE-TO-ONE -->

<many-to-one name="habitacion" column="HabitacionCliente"
unique="true" not-null="true"/>
<!-- ESPECIFICAMOS LAS SUBCLASES -->
<subclass name="es.nuwi.hotel.objpersistentes.ClienteEfectivo"
discriminator-value="Efectivo">
<property name="cantidadEfectivo" column="cantidadEfectivo"
not-null="false"/>
</subclass>
<subclass name="es.nuwi.hotel.objpersistentes.ClienteTarjeta"
discriminator-value="Tarjeta">
<property name="numeroTarjeta" column="numeroTarjeta"
not-null="false"/>
</subclass>
</class>
</hibernate-mapping>

Como habrás observado, no hemos creado ningún .hbm.xml para cada subclase ya que lo hemos especificado en el de la clase madre. Será este el que esté mapeado en hibernate.cfg.xml.

Si tienes dudas, tal vez este foro te sirva de ayuda.

Tutorial sobre las API´s de reflexión

Pinchá aquí para accer al manual sobre las API´s de reflexión.

SSL bajo Tomcat

Cuando tenga time lo pondré.

Mostrar sentencias SQL de Hibernate por la consola en Spring

Para ver las sentecias SQL que Hibernate ejecuta sobre la BB.DD. por la consola, hemos de añadir la siguiente propiedad <prop key="hibernate.show_sql">true</prop> en el fichero de configuración de Hibernate en Spring (applicationContext-hibernate.xml ), ubicada en la siguiente posición:


<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>

Vínculo Asociaciones-Relaciones en Hibernate (xml)

Pincha aquí para ver la documentación sobre la configuración de relaciones entre entidades, empleando para ello el frameworks Hibernate (configuración basada en xml, no en anotaciones).

Anotaciones @RequestMapping y @RequestParam en Spring MVC y la clase ModelMap

Con la anotación @RequestMapping recogemos la petición del cliente, mientras que con @RequestParam los parámetros ( para evitar posibles errores, los recogemos como String). En este último, además del valor, podemos indicar si es obligatorio o no con el atributo required (por defecto es false). Para devolver el modelo, hacemos uso de la clase ModelMap añadiéndole atributos. Veamos un ejemplo :

@RequestMapping(value="/editalibro.html")
public String dameFormularioEdicionLibro(ModelMap modelo,
@RequestParam(value="idLibro",required=true) String idLibro)
{
// Devolvemos un modelo a la capa vista (.jsp normalmente)
modelo.addAttribute("libro",libroManager.getDetalleLibro(idLibro));
return "edicionLibro"; //Retornamos al browser edicionLibro.jsp
}

Ambas anotaciones y clase, se usan dentro del controlador.

Si indicamos que un parámetro sea requerido y no es puesto en la URL, es lanzada una excepción, la cual deberemos controlar para hacer la vista más agradable al usuario.

Creación Bean de Sesión con Estado (Statefull) en Spring

Antes de todo, recordemos que es un Bean: Se trata de una clase normal y corriente, con sus propiedades y cuyos únicos métodos son getters/setters, teniendo obligatoriamente el contructor por defecto o sin parámetros ( este es creado automáticamente siempre que no se cree o se sobrecarge otro con parámetros, en este último caso, hemos de crearlo nosotros explícitamente).

En nuestro caso, el bean que trataremos cumple todas las características mencionadas arriba, aunque además, puede tener más métodos de los ya mencionados (getters/setters).

Decimos que es de Sesión con Estado ya que guarda informacion relativa de cada usuario, es decir, cada cliente va a tener su propio bean, hayase o no registrado previamente. Un ejemplo de todo esto es cuando el usuario abre nuestra página web desde un browser e ingresa productos al carrito de la compra. Otros ejemplos son: ver las operaciones que ha efectuado el usuario, número de veces que ha refrescado la página (siempre que ésta no esté en caché), saber si se ha registrado un usuario...

Veamos los pasos a seguir, como ejemplo tomaremos el carrito de la compra:
  1. Implementamos el bean:


    package org.appfuse.model;

    import java.util.ArrayList;
    import java.util.List;

    public class CarritoCompra {

    private List<libro> carrito = new ArrayList<libro>();

    public List<libro> getCarrito() {
    return carrito;
    }

    public void setCarrito(List<Libro> carrito) {
    this.carrito = carrito;
    }

    public void añadirLibro(Libro libro) {
    if (!carrito.contains(libro))
    carrito.add(libro);
    }

    public void eliminarLibro(Libro libro) {
    carrito.remove(libro);
    }
    }

  2. Utilizamos la anotación @Autowired para aplicar la inyección de dependencias a nuestra aplicación, ya sea desde un controlador u otra clase. Observa que esto también es aplicable a propiedades declaradas como privadas :



    @Autowired
    private CarritoCompra carritoCompra;

  3. Por último, indicamos al Spring que tenemos un nuevo bean de sessión con estado, por lo que a la declaración típica de bean en el fichero applicationContext.xml le vamos a añadir el valor scope="session", y dentro de ésta <aop:scoped-proxy/>:



    <bean id="carritoCompra" class="org.appfuse.model.CarritoCompra"
    scope="session">
    <aop:scoped-proxy/>
    </bean>

Logging en appfuse (spring)

Para imprimir por consola utilizando el Log de apache, hemos de hacer lo siguiente:

  1. Utilizamos en la clase deseada el siguiente objeto.

    • protected final Log logger = LogFactory.getLog(getClass());

  2. Hay que importar en nuestro archivo las siguientes clases:

    • import org.apache.commons.logging.Log;

    • import org.apache.commons.logging.LogFactory;

  3. Utilizarlo dentro de nuestro código sustituyendo las lineas:

    • System.out.println("mensaje"); por ...

    • logger.debug("userId set to: " + variable o llamada a función); donde el objeto logger nos permite indicar varios niveles de logging, cuya jeraquía de mayor a menor es: DEBUG, INFO, WARN, ERROR.

  4. Configurar el archivo /src/main/resources/log4.xml para indicarle los niveles que queremos imprimir en consola (es posible aplicar a los distintos paquetes de nuestro proyecto un tipo de logging distinto a cada uno) .

Nota: Antes hemos mencionado que existe una jerarquía en los niveles de logging, esto consiste en que si usamos el loggin INFO, se mostrarán también los mensajes de WARN y ERROR, mientras que los de DEBUG no lo harán.

Pienso que esto es sencillo, que no tiene ningún misterio y que no merece la pena poner un ejemplo, así que en caso de duda, hacer un comentario.

Internalización ( i18n ) en AppFuse

Para que nuestra aplicación appfuse pueda utilizarse en varios idiomas, tenemos que definir las posibles claves en forma de clave/valor del fichero messages.properties ubicado en /src/main/resources/

Ejemplo=> webapp.clave=Estamos aprendiendo Internalización.

Cada idioma nuevo deberá tener un messages.properties diferente, de forma que si tenemos idioma inglés deberemos tener messages_en.properties, y en español messages_es.properties. En caso de que haya sublenguajes, éstos irán en mayúsculas, veamos un ejemplo con Perú: messages_es_PE.properties .

Después, desde nuestro jsp podemos referenciar dicha clave con el objeto message, es decir ( <fmt:message key="webapp.clave"></fmt:message> ), y según la configuración del navegador de usuario que consulte la aplicación ( por ejemplo, en firefox es Herramientas=> Opciones=> Avanzado=> General=> Idiomas=>Elegir ) obtendrá el idioma correspondiente.

Todo esto funcionará si nuestro framework está bien configurado, es decir, si el archivo /src/main/webapp/WEB-INF/dispatcher-servlet.xml ha declarado el bean: bean id = "messageSource" class = "org.springframework.context.support. ResourceBundleMessageSource" con el basename = messages .
En caso de que no hayamos declarado un idioma para nuestra aplicación, por defecto pillará messages.properties .

Si quisieramos tener en nuestra web los típicos botoncitos o iconos para cambiar explícitamente el lenguaje a usar, aplicamos JSTL jugando con ello gracias a un parámetro (idioma según nuestro ejemplo) y cuyo ámbito va a ser de sesión. He aquí las líneas que debemos agregar a nuestro .jsp :


<c:if test="${param['idioma']!=null}">
<fmt:setLocale value="${param['idioma']}" scope="session"/>
</c:if>

Ejemplo AppFuse Light 1.8.1 con un DBMS

Cuando tenga time , subiré el ejemplo.

Instalación AppFuse-Light 1.8

Antes de comenzar, ten instalado una base de datos MySQL, Tomcat, Maven y Ant. A continuación, sigue los siguientes pasos:

  1. Descomprime dicho archivo en workspace del eclipse.

  2. Abre la consola y desplázate hacia el directorio descomprimido situado en el workspace.

  3. Opcional: En caso de que trabajes con un repositorio local u otro remoto, edita el archivo /pom.xml de Maven y sustituiye http://download.java.net/maven/2 por href=http://...

  4. Ejecuta ant new ( cuando solicite el nombre aplicación inserta el deseado).

  5. Desciende un nivel, verás que hay un directorio con el nombre que le hayas puesto a tu proyecto, accede a él. El otro, el archivo .zip descomprimido, lo dejaremos por si necesitamos crear nuevos proyectos.

  6. Para generar el proyecto de eclipse, utilizamos Maven:

    • mvn eclipse:eclipse . Esto sirve para que prepare el entorno, como por ejemplo el .proyect, el .classpath , ...
    • mvn eclipse:eclipse -DdownloadSources=true . Se descargarán las librerías necesarias para el proyecto.
    • mvn -Declipse.workspace="La ruta de tu workspace" eclipse:add-maven-repo . Esta línea añade una variable nueva (M2_REPO) al Eclipse.

  7. Crea en de eclipse un nuevo proyecto java existente.

  8. Preparar el despliegue de la aplicación con el tomcat de nuestro equipo y la conexion a datos (mysql):
    • Edita /build.xml propiedad server.home y pon la dirección del Tomcat.
    • Edita src/main/resources/jdbc.properties y ponle el nombre de usuario y contraseña de la base de datos MySQL.
  9. Utiliza el archivo ant (build.xml) del proyecto para construir, desplegar ... En especial, utiliza un DeployWar.

*** Todo esto esta sacado de la siguiente URL: https://appfuse-light.dev.java.net/

Creación proyecto Spring MVC Basic. Gracias Maven!

Antes de seguir leyendo este artículo, debes tener instalado MySQL en tu computadora. Una vez que ya lo tengas instalado, sigue los siguientes pasos:
  1. Abre la consola ( Desde Windows: Inicio->Ejecutar->Escribimos "cmd"), y una vez abierta la ventana desplázate hacia el directorio del workspace del Eclipse.

  2. Ejecuta el siguiente comando para que Maven se descargue las librerías necesarias de Spring MVC Basic en el repositorio local que tengas puesto en el fichero de configuración settings.xml de este (el valor del atributo DartifactID puedes cambiarlo, es el nombre que le darás a tu proyecto):

    mvn archetype:create
    -DarchetypeGroupId=org.appfuse.archetypes
    -DarchetypeArtifactId=appfuse-basic-spring
    -DremoteRepositories=http://static.appfuse.org/releases
    -DarchetypeVersion=2.0.1
    -DgroupId=com.mycompany.app
    -DartifactId=SpringMVCBasic


  3. El comando anterior creará un nuevo directorio en tu workspace cuyo nombre coincide con el que le hayas puesto a tu proyecto. Accede a él. Podrás observar, que en él, hay un fichero llamado pom.xml, ¿ Te suena verdad ? :p.

  4. Poner al final del fichero pom.xml del proyecto el nombre de usuario y la contraseña de la base de datos MySQL. Servirá para más adelante (paso 7 en concreto).

  5. Ahora, ejecuta lo siguiente para que se generen los ficheros del proyecto ( .project, .classpath ... ), los ficheros de configuración y se descarguen las herramientas para la creación del proyecto (ten paciencia, es una de las claves del buen programador): mvn eclipse:eclipse .

  6. A continuación, lanza mvn -Declipse.workspace="la ruta del workspace" eclipse:add-maven-repo. Cuidado! Lo que esta entrecomillado debes de poner la ruta del workspace. Esto añade una variable nueva (M2_REPO) al Eclipse para sepa donde esta el repositorio.

  7. Lanza: mvn install . Se descargaran todas las dependencias asociadas al proyecto y lo dejará preparado. Si te da algún error, relacionado con el Tomcat, como me pasó a mí, descárgatelo desde aquí (Apache Tomcat version 6.0.14). Asegúrate que la versión a descargar coincide con la que te ha dado el error. Una vez descargado, copia el .zip en C:\Documents and Settings\[NombreUsuario]\Configuración local\Temp\cargo\installs.

  8. Para hacer un war, deploy y ver su funcionamiento, haz un mvn jetty:run-war. También se descargarán más librerías. Jetty es un servidor (como el tomcat) incorporado en el proyecto. Pincha aquí para ver si todo a sido correcto.
  9. Agrega en el Eclipse el proyecto java existente.

  10. Por último, y por mayor comodidad, instálate el plugin Eclipse. Pincha aquí para ver la guía de instalación u aquí para ver una demo de su funcionamiento.

Todo esto esta sacado de la siguiente URL: http://appfuse.org/display/APF/Home . Espero que le haya sido de ayuda! :)

SVN vs VCS

Subverion( SVN) y Concurrent Versions System (CVS) son sistemas de control de versiones basadas en la arquitectura cliente-servidor.

Diferencia: En SVN, todos los archivos tienen el mismo número de revisión, mientras que con VCS eso no ocurre (cada archivo tiene su propio número de revisión independiente).

Cada proyecto se almacena en un repositorio, que no es más que un directorio especial del disco duro donde se almacenan los ficheros del proyecto.

¿ Cómo crear un repositorio SVN en Google y utilizarlo con Eclipse ? Para ello, hemos de seguir los siguientes pasos:
  1. Entrar en la dirección http://code.google.com/hosting/ .
  2. Click en new proyect.
  3. Rellenar todos los campos que nos pide el formulario de proyecto nuevo.
  4. Click en ficha source y desde el apartado command-line access copiamos la dirección https. Ejemplo: https://nombreDeNuestroProyecto.googlecode.com/svn/trunk/ .
  5. Hacemos click en googlecode.com password y obtendremos nuestro password.
  6. Desde eclipse:

  • Menu window>show view>other>svn repository.
  • En la ventana de svn repository botón derecho del ratón y seleccionar nuevo repositorio location.
  • Url=https://nombreDeNuestroProyecto.googlecode.com/svn/trunk/ .
  • Usuario=cuentaUsuarioGMAIL (no incluir @gmail.com, solo nombreUsuario).
  • Clave=la generada anteriormente en googlecode.com password.
  • Para conectar nuestro código con subversion, botón derecho sobre la carpeta de proyecto a Controlar->Team->Share Project e indicamos la url de antes.

Principales operaciones de SVN:

  • Cada vez que queramos subir nuesrtro código al subversion:
    botón derecho->team->commit
  • Cuando queramos bajarnos los archivos o modificaciones del subversion a nuestro equipo(debe haber variado el número de revisión):
    botón derecho->team->update
  • Cuando queremos bajarnos los archivos, haya habido o no alguna modificación, es decir, haya o no variado el número de revisión:
    botón derecho->team->revert

JBoss Seam. Primeros pasos

JBosS SEAM es un framework para desarrollar aplicaciones J2EE sobre el servidor de aplicaciones JBOSS. Más adelante pondré los pasos a seguir.

Apache MAVEN

Apache Maven es una herramienta cuya funcionalidad es parecida a la de Ant, permite compilar, realizar distribuciones,... pero con gran la diferencia que trata de forma automática las dependencias del proyecto, es decir, se encarga de gestionar las dependencias de las librerías. Esto último es de gran importancia ya que libera al programar de buscar las dependencias asociadas al proyecto. Por fín!!, se acabaron las comeduras de tarro que alguna u otra vez nos habrán dado. Maven trata los proyectos como objetos gracias a un fichero xml llamado POM.xml(Project Object Model).

Objetivos Maven:
  • Repositorio local: Por defecto en window esta ubicado en: C:\Documents and Settings\[NombreUsuario]\.m2 . Puede cambiarse en el fichero settings.xml del direcotorio config.

  • Generacion automática de proyectos: Struts, Spring,...
  • Despliegue de proyectos de forma automática : Actualiza los source folder, es decir, se encarga de las dependencias de las librerías antes mencionadas.

Otra característica de Maven, es que se puede lanzar desde la consola.

Pincha aquí para tener instalado Maven en 5 minutos.
Pincha aquí para ver una demo de la instalación del plugin en el Eclipse.
Pincha aquí para ver una demo de su funcionamiento.
Pincha aquí para ver una guía de Maven en español.

Nota: EL fichero POM.xml siempre ha de estar en la raíz del proyecto.

MVC (Modelo Vista Controlador )

El patrón modelo vista controlador ( MVC en adelante ) es una arquitectura de software donde separa 3 componentes distintos en una aplicación: los datos, la interfaz de usuario, y la lógica de negocio(control).
  1. Modelo: Representa la parte fuerte de la aplicación, es decir, todo aquello con lo que el sistema opera. Se encarga de ejecutar o de llevar a cabo los servicios o eventos dictados por el controlador e interactuar si es necesario con la bases de datos (capa de datos) aplicando para ello persistencia.


  2. Vista: Interfaz que percibe el usuario, mediante el cual interactua.


  3. Controlador (Interceptor): Se situa entre los dos anteriores, recibe las peticiones por parte del usuario e inicializa los servicios o eventos correspondientes a dicha petición. Devuelve un modelo a la capa de vista (.jsp,...).

He aquí un pequeño esquema del patrón MVC:

Java Bean

Un Bean es una clase (sin nada en especial) compuesta por propiedades y métodos getters y setters además de tener un constructor público sin parámetros.

Ejemplo de un Bean:



package es.nuwi.ejemplo.bean


public class EjemploBean{


private char caracter;


public char getCaracter(){
return caracter;
}


public void getCaracter(char caracter){
this.caracter=caracter;
}
}

Anotaciones

Una anotación en Java es una forma de añadir metadatos al código fuente en tiempo de ejecución jugando con ellas las API´s de reflexión ( java.lang.reflect ). Estas son fundamentales para los EJB3 ya que con ellas indicamos el tipo de bean, forma de persistencia,..., recordamos que un EJB3 es un "POJO + @ (anotación)". Otra características de las anotaciones es que posibilita el control sobre los aspectos de la programación orientada a Aspectos (AOP), como ejemplo la seguridad.

Para que una anotación sea detectable en tiempo de ejecución se ha de hacer uso de la siguinete anotación: @Retention(value=RetentionPolicy.RUNTIME).

Las anotaciones pueden aplicarse tanto a clases como a propiedades, métodos...

Las Anotaciones son declaradas igual que las interfaces con la única excepción de que lleva precedico el caracter @. Veamos un ejemplo :


//Creamos una clase tipo enumerado.


package es.ejemplo.anotacion;


public enum TipoUsuario {
cliente,administrador
}

//Creamos una anotación.


package es.ejemplo.anotacion;


import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;


/*La linea siguiente es obligatoria para que sea detectable en tiempo de ejecución.*/
@Retention(value=RetentionPolicy.RUNTIME)
public @interface AnotacionUsuario {
TipoUsuario tipo(); //Se trata de un atributo de la anotación.
}

//Aplicamos la anotación a una clase de ejemplo.


package es.ejemplo.anotacion;


@AnotacionUsuario(tipo=TipoUsuario.cliente)
public class ExisteAnotacion {

//Propiedades y métodos a implementar...
}

//Comprobamos que realmente existe la anotación.


package es.ejemplo.anotacion;


import org.testng.annotations.Test;


public class TestAnotacion{


@Test
public void pruebaExisteAnotacion(){
if (ExisteAnotacion.class.isAnnotationPresent
(AnotacionUsuario.class))
assert(true);
else
assert(false);
}
}

POJO

Llamamos Plain Old Java Object a una clase normal y corriente, con sus propiedades y métodos (getters, setters,...), ligándola a un determinado entorno de ejecución o contenedor y siendo independiente del framework ya que no recibe ninguna intrusión por parte de éste en forma de implementación de interfaces o extensiones de clases. En los EJB<3, las entidades y sesiones beans debían obligatoriamente implementar ciertas interfaces y heredar clases proveídas por el framework, cosa que no pasa con la version 3. Siempre ha de llevar implementado el constructor por defecto (aunque no haga nada) en caso de que necesitemos otros (constructores con parámetros).

Veamos un ejemplo:


package es.nuwi.ejemplo.pojo


impor java.io.*;


public class EjemploPojo{


private String saludo="Hola,esto es un ejemplo de POJO.";


public void saludaAlLector(){
System.out.println(saludo);
}
}

Caja blanca vs Caja negra

Llamamos caja blanca de un sistema (aplicación entera) o módulo (parte del sistema) cuando conocemos su funcionamiento interno, es decir, sabemos como es generada la salida a partir de las entradas . Un ejemplo de caja blanca es EasyMock. En cambio, si se habla de caja negra, solo conocemos sus entradas y la salida correspondiente, no la forma de generar el resultado. Ejemplos de cajas negra son TestNG o JUnit .

Apache ANT

Apache Ant es una herramienta hecha en java encargada de llevar acabo todas aquellas tareas repetitivas, como por ejemplo, el compilado, clean,build... La mayor ventaja de esta herramienta es la portabilidad, es decir, no es necesario conocer los comandos del sistema operativo (crear directorios, borrar ficheros,...) con el que se este trabajando para la ejecución de las tareas antes mencionadas. Como habrás observado, garantiza que el "IDE sea multi-plataforma"(el plugin Ant viene integrado en el ECLIPSE por defecto ).

Para llevar la ejecución de dichas tareas, Ant se basa en un fichero xml, llamado por defecto "build.xml", (puede comprobarse desde la pestaña Window->Preferences->Ant en el Eclipse). Dicho fichero contendrá el nombre del proyecto y una serie de objetivos (target o tareas a realizar). Puede darse el caso en que un objetivo dependa de otros antes de ejecutarse, para ello se utiliza el atributo "depends" siendo su valor el nombre de la tarea previa.

Otra característica de Ant, es que éste puede ser lanzado desde la consola.

He aquí un ejemplo de la wiki, ya que me parece muy básico y a la vez sencillo:


<?xml version="1.0"?>
<project name="Hello" default="compile">
<target name="clean" description="borrar archivos temporales">
<delete dir="classes"/>
</target>
<target name="compile"
description="compilar el código java a un archivo class">
<mkdir dir="classes"/>
<javac srcdir="." destdir="classes"/>
</target>
<target name="jar" depends="compile"
description="crear un archivo Jar para la aplicación">
<jar destfile="hello.jar">
<fileset dir="classes" includes="**/*.class"/>
<manifest>
<attribute name="Main-Class" value="HelloProgram"/>
</manifest>
</jar>
</target>
</project>

Pincha aquí para descargar Apache Ant. Si te lo has descargado, pon una variable en el sistema llamada ANT_HOME cuyo contenido sea la ruta en donde hayas descomprimido el fichero antes mencionado, y a continuación añade a la variable PATH %ANT_HOME%/bin .

Pincha aquí para ver el manual de Apache Ant ( esta en inglés).

Refactorización

La refactorización es una técnica para reestructurar un código fuente, alterando su estructura interna sin cambiar su comportamiento externo, es decir, aquellos cambios son reflejados automáticamente donde estos aparezcan.

Para ver un ejemplo de refactorización, pincha en el siguiente enlace:
EJEMPLO REFACTORIZACIÓN. Para conseguir una visión óptima, aumentar la calidad de imagen (botón derecho sobre el flash).

También se llama refactorización a la creación automática de aquellos elementos mencionados y no creados previamente ( esto es de gran utilidad cuando aplicamos TDD, ya que las clases, interfaces, variables, ... son mencionadas en la zona de pruebas (test) y luego son creados automáticamente en el source correspondiente (src) . Para aplicar esto, CTRL+SPACE en el IDE ECLIPSE.

Servidor de Aplicaciones

Un Servidor de aplicaciones (S.A.), es un dispositivo software, que como todo servidor, proporciona unos recursos o servicios a las aplicaciones cliente, diferenciándose del resto en que integra 3 contenedores: Contenedor Web (Servlet, JSP,...), Contenedor EJB y Contenedor o Gestión de la Persistencia, es decir, permite implementar diferentes capas en la aplicación, como: la interfaz de usuario, la lógica de negocio (la gestión de sesiones de usuario,...) o el acceso a bases de datos local o remoto, todo ello de un forma centralizada y disminuyendo así la complejidad en el desarrollo de aplicaciones siempre que se haga un buen diseño (Ingeniería del SoftWare).


Los servidores de aplicaciones son aplicables todas las plataformas software, aunque hoy día se ha convertido un sinónimo de la plataforma J2EE.

Otra característica y obvia antes mencionada implícitamente, es la portabilidad de Java (multi-plataforma) ya que permite que los servidores de aplicaciones J2EE se encuentren disponibles en una gran variedad de Sistemas Operativos (Windows, Linux,...).

Servidores de Aplicaciones más conocidos:

  1. S.A. privativos : WebSphere (IBM), WebLogic (BEA), Oracle Aplication Server (Oracle Corporation).
  2. S.A. Libres : JOnAS y JBOSS (nuestro caso).

He aquí un pequeño esquema de un S.A. :

Pincha aquí para ver las características de la plataforma J2EE en una ventana aparte.

Interceptores / Controladores

Llamamos interceptor o controlador aquel elemento u objeto que conecta la capa vistas con la capa del modelo ( patrón MVC, hay una entrada en este blog ). El usuario, cuando realiza una petición (c. vistas), no habla directamente con la lógica del negocio ( c. modelo) , sino a través de un intermediario, siendo éste el interceptor. Cuando el interceptor recibe la petición por parte del usuario, pone en funcionamiento el servicio correspondiente, siendo éstos ocultos e invisibles para el ususario, por tanto, podríamos llamarlo también como el gestor de eventos (handler). También se encarga de controlar los diversos aspectos (AOP, hay una entrada en este blog) que maneja el sistema. Puede darse el caso de que haya más de un controlador en nuestra aplicación.

Programación Orientada a Objetos (POO)

La Programación Orientada a Objetos ( POO u OOP en adelante ) es uno de los paradigmas de la programación. Parte de la programación estructurada (a la que engloba), con la gran diferencia de que nos permite modelar problemas no estructurados. La OOP no sustituye a ninguna metodología ni lenguaje de programación anterior, es decir, todos los programas que se realizan en POO se pueden realizar igualmente mediante programación estructurada, aunque si cabe destacar que con dicho paradigma el desarrollo de muchas herramientas es bastante más sencillo, como son las interfaces gráficas de usuario ( Windows, X-Window,...).


El uso de la OOP hoy día es muy variado, aplícandose tanto en Sistemas Operativos (S.O.), Inteligencia Artificial (I.A.),"Aplicaciones Empresariales",SBGDOO (no muy utilizado ya que hay muchos problemas)...

Principales características de la OOP:

A) Clase: Es el núcleo de la POO. Se define como un nuevo tipo de dato que se utiliza para crear objetos de ese tipo.
B) Metaclases: Son clases cuyos ejemplos son a su vez clases. "Java" tiene esta carácterística pero no es aplicable a todos los lenguajes OOP, como pasa con C++.
C) Objetos: Un objeto es una instancia o ejemplo de una clase. En "java", estos son creados con el operador new (es creado en tiempo de ejecución como es obvio). Cada objeto tiene un estado definido por sus atributos (salvo los objetos stateless ya que estos no tienen propiedades) y un comportamiento (definido por sus métodos).
D) Identidad: Aquella propiedad que distingue al objeto de los demás (salvo objetos stateless).
E) Abstraccion: Capacidad de conceptualizar el problema en forma de clases (tipos) y variables pertenecientes a estos tipos (instancias). Hacemos clasificaciones jerárquicas.
F) Encapsulación: Capacidad de aunar dentro de una clase las propiedades y métodos para trabajar con sus datos internos. Con esta capacidad, conseguimos reutilización.
G) Herencia: Capacidad de derivar de una clase genérica, clases diferentes que hereden las propiedades y métodos de su clase antecesora.La herencia nos da reusabilidad de código.En "Java", no existe herencia múltiple, siempre herencia simple.
H) Polimorfismo: Capacidad para que varias clases derivadas de una antecesora utilicen el mismo método de forma diferente. Otra aplicación sería jugar con los comportamientos de los objetos. El polimorfismo es coseguido graciasa la herencia y a la ligadura dinámica. Una de las ventajas del polimorfismo es que se puede hacer uso de una solicitud de una operación sin conocer el método que debe ser llamado. Aquí podemos hacer uso de las interfaces, donde decimos el comportamiento que va a tener un objeto en un instante dado.
I) Persistencia: Es la propiedad por la cual la existencia de un objeto transciende tanto en el tiempo como en el espacio.
j) Otros conceptos son: Modularidad, tipificado,...

Ventajas que proporciona la OOP frente a otros lenguajes de programación:

A) Uniformidad: La representación de los objetos lleva implícita tanto el análisis como el diseño y codificación de los mismos.
B) Comprensión: Los datos que componen los objetos y los procedimientos que los manipulan, están agrupados en clases, que se corresponden con las estructuras de información que el programa trata.
C) Flexibilidad: Al relacionar los métodos y propiedades, cualquier cambio que se realice sobre ellos quedará reflejado automáticamente en cualquier lugar donde estos datos aparezcan.
D) Reutilización: La noción de objeto permite que programas que traten las mismas estructuras de datos reutilicen las definiciones de objetos empleadas en otros programas e incluso los métodos que los manipulan. De esta forma, el desarrollo de un programa puede llegar a ser una simple combinación de objetos ya definidos donde éstos están relacionados de una manera particular.
En la programación OOP, los componentes (objetos) se conocen, cosa que no pasa con la AOP.

Desarrollo guiado por pruebas (TDD)

El Test-Driven Development ( TDD en adelante ) es una técnica que involucra dos partes en el siguiente orden:

  1. Escribir primero las pruebas (Test First Development), es decir, usando para ello los framework JUNIT o TESTNG (de este último hay una entrada en el blog).

  2. Refactorización. Ya comentado en otra entrada del blog.

Aplicando TDD sobre la aplicación, conseguimos un software seguro y fiable.

Programación Orientada a aspectos (POA)

Con la Programación Orientada a aspectos ( POA o AOP en adelante ) conseguimos que los distintos componentes ( modulos ) que componen la aplicación sean independientes unos de otros, aplicando para ello las API´s de reflexión (java.lang.reflect). Un ejemplo típico y bastante claro ( dado en clase ) es el aspecto de la seguridad, en donde vimos que según el tipo de usuario (despues de hacer login) podía hacer unas operaciones u otras (otro ejemplo podría ser salida por la consola,...) . Con la AOP conseguimos una separación de las funcionalidades del sistema, por un lado las comunes de la aplicación y por otro lado las propias de cada módulo.

En la programación AOP, los distintos componentes no se conocen, cosa que no pasa con la OOP.

La versión EJB2 usa ficheros XML para basarse en POA, mientras que EJB3 se basa en anotaciones· Con las anotaciones queda más claro para el programador, ya que la información relativa a aspectos/interceptores queda en el mismo fichero java, en vez de utilizar otro fichero (XML) situado en otro directorio de la aplicación.

Enterprise JavaBeans v.3 (EJB3)

Los EJB forman parte del API del J2EE desarrollado por Sun Microsystems y se centran en lógica de negocio (recordamos que en las aplicaciones cliente servidor basadas en sistemas distribuidos existen 3 capas : presentación (se encarga de la visualización), lógica de negocio(su nombre lo indica todo) y de datos(se encarga del almacenamiento de datos:SGBD)). Una vez comprendido lo anterior (arquitecturas multicapas), ahora, podemos definir lo que es un EJB: Modelo de componenetes distribuido estándar del lado del servidor. Los EJB´s se encuentran ubicados dentro del contenedor EJB del servidor de aplicaciones,en nuestro caso JBOSS AS.

Historia de los EJB:

EJB 1.0: La especificación original .
EJB 1.1: La primera incluida dentro de J2EE
EJB 2.0: Incluida en J2EE 1.3, añadía las interfaces Locales y los Message-Driven beans.
EJB 2.1: Incluida en la última revisión de J2EE, la 1.4.


Hasta ahora, el manejo y configuración de los EJB´s se basaba en ficheros XML, sin embargo, la última versión,(EJB 3.0) se caracteriza porque permite el manejo con anotaciones. EJB3 está incluida en JEE5.0. En realidad, un EJB3 es un POJO ( para comprender su significado, buscar dicha entrada en este blog) más anotaciones (tales como @Entity,@StateFull,...)(También hay una entrada en este blog sobre las anotaciones). Al ser POJO, cada objeto ha de llevar el constructor por defecto, siendo éste implícitamente ( es insertado automáticamente) o explícitamente ( en caso de que necesitemos constructores con parámetros).

A continuación, veamos el proceso de creación de un EJB:
Hay 3 tipos de EJB:

A) EJB de entidad (Entity EJBs): No explicado todavía.


B) EJB de sesión (Session EJBs): Gestionan el flujo de la información en el servidor. Generalmente sirven a los clientes como una fachada de los servicios proporcionados por otros componentes disponibles en el servidor. Hay dos tipos de EJB de entidad:
  1. Con estado (StateFul). Los beans de sesión con estado son objetos distribuidos que poseen un estado. El estado no es persistente, pero el acceso al bean se limita a un solo cliente. Para la creación de un EJB statefull se usan llamadas RMI.


  2. Sin estado (StateLess). Los beans de sesión sin estado son objetos distribuidos que carecen de estado asociado ( carecen de atributos o propiedades ) permitiendo por tanto que se los acceda concurrentemente. No se garantiza que los contenidos de las variables de instancia se conserven entre llamadas al método, es decir, el componente (objeto) no está asociado al usuario (sólo es creada una única instancia como máximo). Un objetos Stateless también puede usarse para modificar alguna propiedad de un objeto StateFull. Para la creación de un EJB stateless se usa pooling web services.

En el caso de JBOSS SEAM, este distingue 3 tipos de EJB de sesión con estado:

  • Objeto Página: Guarda información mientras la página este activa. Se destruye cuando pasa un cierto tiempo o cuando el usuario a cambiado de página web.

  • Objeto evento: Ocurre cuando el cliente modifica o actualiza algo en la ventana del navegador.

  • Objeto conversación(Task): El cliente pone a próposito que inicie un servicio para conseguir su objetivo.

C) EJB dirigidos por mensaje (Message-driven EJBs(MDB)): : No explicado todavía.

Servicios que nos proporcionan los EJB
A) Messaging (Se trata de una comunicacion asíncrona).
B) Inyección de dependencias.
C) Pooling.
D) Thread-safely.
E) Mantenimiento del estado.
F) AOP-Interceptores. De esto se habla en otra entrada.
G) RMI (Remote Invocation Method).
H) Web Services.
I) Transacciones.
J) Seguridad (gracias a las anotaciones).

He aquí un esquema y su relación con las aplicaciones J2EE:


Java 2 Enterprise Edition (J2EE)

Se trata de una plataforma de desarrollo para aplicaciones empresariales multicapa desarrollado por Sun Microsystems. Se basa en componentes modulares y estandarizados ejecutándose sobre un servidor de aplicaciones (por ejemplo JBOSS AS), proveyendo un completo cojunto de servicios a estos componentes, y manejando muchos de las funciones de la aplicación de forma automática, sin necesidad de una programación compleja. Java EE incluye varias especificaciones de API, tales como JDBC,RMI,e-mail,JMS,Servicios web,JSP,Servlet,EJB,XML...

Las características del J2EE, son las siguientes: Alto rendimiento, aplicaciones distribuidas y multiusuario, escalable, testeable, gestión del estado, persistencia (ya definido), transacciones, seguridad (gracias a las anotaciones) e interceptores .

Para desarrollar nuestras aplicaciones empresariales con J2EE usaremos el IDE ECLIPSE versión EUROPA (3.3) , el cual ya tiene integrado el JDT (Java Development Tools).

La última versión del J2EE sacado por Sun es conocida como JEE 5.0.

TestNG

TestNG es un framework que permite realizar pruebas unitarias, funcionales, de integracion,... en aplicaciones java, es decir, comprueba que el comportamiento de los objetos sea el deseado. Esta basado en Junit, pero a diferencia de éste, TestNG añade nuevas funcionalidades (por ejemplo @DataProvider, @BeforeMethod,@BeforeClass,...). Como se habrás observado, nuestro framework se basado en anotaciones, al igual que Junit 4.0 (antes de dicha versión, se hacía heredando de la clase TestCase). Para evaluar aquellos métodos usamos la anotación @Test.

Veamos un ejemplo muy sencillo :


package es.cea.utilidades;

import org.testng.annotations.Test;


public class TestNG {

@Test
public void pruebaDevuelveValor(){

AlmacenaValor miValor=new AlmacenaValor(2);
assert (miValor.dameValor()==1):
"Lo que devuelve el objeto (miValor), es distinto de 2";
}
}

class AlmacenaValor{

int valor;
AlmacenaValor(int valor){
this.valor=valor;
}
int dameValor(){

return valor;
}
}

Como habreis comprobado en vuestro IDE ECLIPSE, el resultado ha fallado dado que hemos almacenado el valor 2 como parámetro en el constructor y lo estamos comparando con el valor 1.

La anotación @DataProvider consiste en evaluar un mismo método de forma iterativa, veamos un ejemplo para que se comprenda mejor:


package es.cea.utilidades;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class TestNG {

@DataProvider(name="pruebaConEstosValores")
public Object[][]teDoyValores(){
return new Object[][]{{1},{2},{3}};
}

@Test(dataProvider="pruebaConEstosValores")
public void pruebaDevuelveValor(int pruebaEntero){

AlmacenaValor miValor=new AlmacenaValor(2);
assert (miValor.dameValor()==pruebaEntero):
"Lo que devuelve el objeto (miValor), es distinto de 2";
}
}

class AlmacenaValor{
int valor;
AlmacenaValor(int valor)
{
this.valor=valor;
}
int dameValor(){
return valor;
}
}

En este ejemplo, cuando el valor del parámetro (pruebaEntero) valga 1 y 3, el test no tendrá éxito, mientras que para el otro caso (valga 2) si lo tendrá.

Como ya se mencionó antes, existen otras anotaciones de utilidad, como @BeforeClass, @BeforeMethod,...

Otra característica es el uso de una suite (fichero basado en xml). Esto es de gran utilidad ya que ejecuta a la vez todos aquellos métodos que tengan la anotación @Test del paquete indicado, en vez de ir uno por uno. He aquí un ejemplo:

Fichero testng.xml (puede llamarse como uno quiera):

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="Suite1" verbose="1" >
<test name="Regression1" >
<packages>
<package name="nombre.paquete.*" />
</packages>
</test>
</suite>

En una misma suite, puede indicarse más de un paquete.

EasyMock

Se trata de un framework para el Eclipse, el cual aisla los detalles de implementación gracias a una interfaz. El uso de dicho framework, lo aplicamos en la zona de pruebas (test).


package es.nuwi;


import org.easymock.EasyMock;
import org.testng.annotations.Test;


public class EjemploEasyMock {


@Test
public void pruebaLlamadaServicio(){


//Creamos el objeto,el cual realizará la llamada.
Controlador controlador = new Controlador();


//Aquí creamos la interfaz del servicio.
InterfazServicio servicioInterfaz=
EasyMock.createMockInterfazServicio.class);


//Reseteamos.
EasyMock.reset(servicioInterfaz);


//Indicamos que llamada esperamos y que es lo que devolvemos.
EasyMock.expect(servicioInterfaz.dameServicio()).andReturn(true);


//Esperamos la llamada.
EasyMock.replay(servicioInterfaz );


/*El objeto controlador ha de tener obligatoriamente
una referencia para realizar la llamada.*/
controlador.servicioInterfaz=servicioInterfaz;


/*dameServicio es un método del objeto controlador.
En dicho método se realizará la llamada.*/
controlador.dameServicio();


//Comprobamos que se ha realizado la llamada.
EasyMock.verify(servicioInterfaz);
}
}