lunes, 30 de diciembre de 2013

- EJB 3.x con Servlets 3.0 sin Maven

En este tutorial describiré los pasos necesarios para realizar un proyecto EJB 3 sin la herramienta de gestión y construcción MAVEN, lo cual quiere decir que obtendremos nosotros mismos las librerías necesarias para nuestros proyecto así como configuraremos nuestro entorno de desarrollo para que todos los componentes sean tomados correctamente en nuestra aplicación.

Introducción a EJB 3

Es un API que forma parte del estándar de construcción de aplicaciones JEE.
Los EJB proporcionan un modelo de componentes distribuido estándar del lado del servidor. El objetivo de los EJB es dotar al programador de un modelo que le permita abstraerse de los problemas generales de una aplicación empresarial (concurrencia, transacciones, persistencia, seguridad, etc.) para centrarse en el desarrollo de la lógica de negocio en sí. El hecho de estar basado en componentes permite que éstos sean flexibles y sobre todo reutilizables. Mas información aqui: https://es.wikipedia.org/wiki/Enterprise_JavaBeans



  1. El cliente que puede ser un servlet, cliente local, remoto o inclusive otro EJB se comunica por medio de JNDI para poder comunicarse con un EJB ya sea local o remoto.
  2. EL EJB de session que puede implementar un EJB remoto, local o incluso ambos se encarga de realizar la lógica basada en la petición del cliente comunicándose con la base de datos por medio de JPA para luego devolver la respuesta al cliente.
  3. Estos componentes se deben encontrar dentro de un contenedor de aplicaciones empresariales. Que por ejemplo no puede ser un contenedor WEB como es el tomcat pero si un contenedor empresarial que por ejemplo puede ser JBOSS.
Esto es una descripción resumida. Durante la construcción del proyecto iremos explicando a detalle los tipos de EJB y forma de comunicación que podemos realizar para poder entenderlo a detalle.

Proyecto en EJB 3

  1. Eclipse Kepler
  2. JBoss 7.1.1
  3. MySQL Server 5.0
  4. Mysql-connector-java
Como indiqué anteriormente no explicaré como se realiza la instalación del Eclipse con su respectivo JDK, ni la Base de datos MySQL por lo que se asume que ya tenéis el entorno instalado. Lo unico que explicaré es la instalación del JBoss en eclipse.

Antes que nada crearemos en MySQL nuestra base de datos así como la tabla necesaria para poder trabajar con ella:

CREATE DATABASE BD_TUTORIAL;
USE BD_TUTORIAL;
grant all on BD_TUTORIAL.* to 'admin'@'localhost' identified by 'test';

CREATE TABLE COMPONENTE
(   id        INT PRIMARY KEY AUTO_INCREMENT,
    nombre    VARCHAR(30),
    version   VARCHAR(30),
    tipo      VARCHAR(15),
    extension VARCHAR(30),
    creado    TIMESTAMP DEFAULT NOW()
);
CREATE TABLE usuario
(   id        INT PRIMARY KEY AUTO_INCREMENT,
    nombre    VARCHAR(30),
    clave   VARCHAR(30),
    creado    TIMESTAMP DEFAULT NOW()
);
insert into usuario (nombre, clave) values ('victor', 'elliott');

Luego obtenemos el servidor y nuestro conector a partir de las siguientes URL's:
  1. JBoss 7.1.1
  2. Mysql-connector-java
Una vez hayamos descomprimido el archivo del jboss nos vamos a la carpeta: 
\jboss-as-7.1.1.Final\modules\com y creamos la siguiente estructura de carpetas: mysql\main
al final quedará asi:
\jboss-as-7.1.1.Final\modules\com\mysql\main
dentro de main ponemos el conector: mysql-connector-java-5.1.25
Creamos el fichero xml: module.xml y dentro escribimos y guardamos: 

<?xml version="1.0" encoding="UTF-8"?>

<module xmlns="urn:jboss:module:1.1" name="com.mysql">

    <resources>
        <resource-root path="mysql-connector-java-5.1.25.jar"/>
        <!-- Insert resources here -->
    </resources>
    <dependencies>
    <module name="javax.api"/>
    <module name="javax.transaction.api"/>
    <module name="javax.servlet.api" optional="true"/>
    </dependencies>
</module>

Luego nos vamos a la carpeta: \jboss-as-7.1.1.Final\standalone\configuration y abrimos el archivo: standalone.xml y dentro del tag <datasources> copiamos lo siguiente:


                <datasource jta="false" jndi-name="java:/mysql_ds" pool-name="mysql_ds" enabled="true" use-ccm="false">
                    <connection-url>jdbc:mysql://localhost:3306/BD_TUTORIAL</connection-url>
                    <driver-class>com.mysql.jdbc.Driver</driver-class>
                    <driver>mysql</driver>
                    <security>
                        <user-name>admin</user-name>
                        <password>test</password>
                    </security>
                    <validation>
                        <validate-on-match>false</validate-on-match>
                        <background-validation>false</background-validation>
                    </validation>
                    <statement>
                        <share-prepared-statements>false</share-prepared-statements>
                    </statement>
                </datasource>

Y dentro del tag <drivers> lo siguiente:

<driver name="mysql" module="com.mysql"/>

Guardamos y ya tenemos nuestro Servidor JBoss configurado para poder conectarnos a la Base de datos.
Ahora instalamos el plugin de JBoss en nuestro eclipse: En el menú de eclipse Help -> Eclipse Marketplace en search buscamos JBoss e instalamos JBoss Tools (Kepler). Una vez instalado ya tenemos el JBoss plugin instalado en el Eclipse.

Ahora creamos un proyecto EJB: New -> EJB Project , le ponemos el nombre: ProyectoEJBTutorial-EJB
hacemos click en New Runtime, elegimos JBoss 7.1 Runtime -> Next Le ponemos un nombre adecuado yo le puse: JBoss 7.1 Runtime 1, en Home Directory elegimos la carpeta donde descomprimimos nuestro servidor JBoss en JRE puse jr7 y luego finish. En EJB Module elegimos la 3.1en Configuration lo dejamos a Default Configuration for JBoss 7.1 Runtime 1. Tendríais que tenerlo mas o menos asi:


Ahora nos vamos a la vista del servidor damos click en create new server, elegimos JBoss AS 7.1 en server name le pones el nombre que quieras yo lo deje el que salia por defecto: JBoss 7.1 Runtime 1 Server y en runtime enviroment elegimos el que acabamos de crear JBoss 7.1 Runtime 1. Quedaría asi:


Damos click a Finish y ya tenemos nuestro servidor configurado.
Ahora vamos a nuestro proyecto EJB damos click derecho en ejbModule -> New -> Other -> EJB -> Session Bean (EJB 3.x) -> Next y escribimos lo siguiente:

  1. Java package: com.victor.elliott.humala.logica
  2. Class name: ComponenteSessionBean
  3. State type: Stateless
  4. Hacemos check en Remote: com.victor.elliott.humala.negocio.ComponenteInterfazRemota
  5. Quitamos el check de No-interface View y quedaría asi:


Se nos crearan las siguientes clases:
/ProyectoEJBTutorial-EJB/ejbModule/com/victor/elliott/humala/logica/ComponenteSessionBean.java
/ProyectoEJBTutorial-EJB/ejbModule/com/victor/elliott/humala/negocio/ComponenteInterfazRemota.java

Ahora creamos nuestra entidad Componente:
ejbModule -> New -> Class

  1. Package: com.victor.elliott.humala.entidades
  2. Name: ComponenteEntity

Ahora creamos las clases para el Usuario:

Vamos a nuestro proyecto EJB damos click derecho en ejbModule -> New -> Other -> EJB -> Session Bean (EJB 3.x) -> Next y escribimos lo siguiente:




  1. Java package: com.victor.elliott.humala.logica
  2. Class name: UsuarioSessionBean
  3. State type: Stateless
  4. Hacemos check en Local: com.victor.elliott.humala.negocio.UsuarioInterfazLocal
  5. Quitamos el check de No-interface View y quedaría asi:


Se nos crearan las siguientes clases:
/ProyectoEJBTutorial-EJB/ejbModule/com/victor/elliott/humala/logica/UsuarioSessionBean.java
/ProyectoEJBTutorial-EJB/ejbModule/com/victor/elliott/humala/negocio/UsuarioInterfazLocal.java

Ahora creamos nuestra entidad Usuario:
ejbModule -> New -> Class
  1. Package: com.victor.elliott.humala.entidades
  2. Name: UsuarioEntity
A continuación crearemos un cliente el cual no es necesario para nuestro proyecto pero lo haremos para realizar algunas pruebas y ver que estamos haciendo bien las cosas.
ejbModule -> New -> Class
  1. Package: com.victor.elliott.humala.cliente
  2. Name: ClienteProbador
Por ultimo una clase que nos ayudará a comunicar el cliente con nuestros EJB's a través de JNDI
ejbModule -> New -> Class
  1. Package: com.victor.elliott.humala.clienteutility
  2. Name: JNDILookupClass
Luego insertamos el siguiente código dentro de esa clase:

package com.victor.elliott.humala.clienteutility;
 
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
 
public class JNDILookupClass {
 
    private static Context initialContext;
 
    private static final String PKG_INTERFACES = "org.jboss.ejb.client.naming";
 
    public static Context getInitialContext() throws NamingException {
        if (initialContext == null) {
            Properties properties = new Properties();
            properties.put(Context.URL_PKG_PREFIXES, PKG_INTERFACES);
            properties.put("jboss.naming.client.ejb.context", true);
            initialContext = new InitialContext(properties);
        }
        return initialContext;
    }
}

Aquí lo único que estamos haciendo es poner las propiedades necesarias a un contexto para poder realizar las llamadas JNDI correctamente.

Ahora que ya tenemos nuestras clases necesarias creadas crearemos nuestros ficheros de configuración:
Creamos dentro de la carpeta META-INF -> New -> Other -> XML -> XML File -> persistence.xml
y colocamos el siguiente código:

<?xml version="1.0" encoding="UTF-8"?>  
<persistence version="2.0"  
 xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">  
 <persistence-unit name="ProyectoPersistencia"  
  transaction-type="JTA">  
  <jta-data-source>mysql_ds</jta-data-source>  
  <properties>  
   <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />  
   <property name="hibernate.hbm2ddl.auto" value="validate" />  
  </properties>  
 </persistence-unit>  
</persistence>  

Usamos el tipo de persistencia de Hibernate puesto que actualmente es el proveedor para persistencia en JBoss y la configuración no es nada complicada como pueden ver. Tener en cuenta que estamos usando la conección del driver que definimos algunos pasos atras en el JBoss "mysql_ds"

Ahora vamos a añadir a nuestro proyecto EJB las librerias necesarias para poder ejecutar el cliente y hacer algunas pruebas para esto vamos a crear un fichero de configuración para luego importarlo y evitar buscar los jar necesarios dentro de nuestro servidor de aplicaciones. para esto creamos un fichero en c:\ por ejemplo que se llame: clientelibrerias.userlibraries
y ponemos lo siguiente:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<eclipse-userlibraries version="2">
    <library name="EJBClientLibrerias" systemlibrary="false">
        <archive path="<JBOSS_HOME>/jboss-as-7.1.1.Final/modules/javax/transaction/api/main/jboss-transaction-api_1.1_spec-1.0.0.Final.jar"/>
        <archive path="<JBOSS_HOME>/jboss-as-7.1.1.Final/modules/javax/ejb/api/main/jboss-ejb-api_3.1_spec-1.0.1.Final.jar"/>
        <archive path="<JBOSS_HOME>/jboss-as-7.1.1.Final/modules/org/jboss/ejb-client/main/jboss-ejb-client-1.0.5.Final.jar"/>
        <archive path="<JBOSS_HOME>/jboss-as-7.1.1.Final/modules/org/jboss/marshalling/main/jboss-marshalling-1.3.11.GA.jar"/>
        <archive path="<JBOSS_HOME>/jboss-as-7.1.1.Final/modules/org/jboss/xnio/main/xnio-api-3.0.3.GA.jar"/>
        <archive path="<JBOSS_HOME>/jboss-as-7.1.1.Final/modules/org/jboss/remoting3/main/jboss-remoting-3.2.3.GA.jar"/>
        <archive path="<JBOSS_HOME>/jboss-as-7.1.1.Final/modules/org/jboss/logging/main/jboss-logging-3.1.0.GA.jar"/>
        <archive path="<JBOSS_HOME>/jboss-as-7.1.1.Final/modules/org/jboss/xnio/nio/main/xnio-nio-3.0.3.GA.jar"/>
        <archive path="<JBOSS_HOME>/jboss-as-7.1.1.Final/modules/org/jboss/sasl/main/jboss-sasl-1.0.0.Final.jar"/>
        <archive path="<JBOSS_HOME>/jboss-as-7.1.1.Final/modules/org/jboss/marshalling/river/main/jboss-marshalling-river-1.3.11.GA.jar"/>
    </library>
</eclipse-userlibraries>

Donde reemplazamos <JBOSS_HOME> por la carpeta donde se ha descomprimido el servidor JBoss.
Ahora vamos a nuestro proyecto Click Derecho ejbModule -> Properties -> Java Build Path -> Add Library -> User Library -> Next -> User Libraries -> Import -> Browser -> Elegimos el clientelibrerias.userlibraries que hemos creado y ya estará listo nuestras librerías para el cliente. Finalmente lo seleccionamos para agregarlo al proyecto y Finish.
Luego para tener configurado correctamente al cliente creamos un archivo de propiedades que es necesario cuando creamos un cliente en JBoss:
Click derecho en el proyecto -> New -> Others -> JBoss Tools Web -> Properties File -> Next:

  1. Folder:* /ProyectoEJBTutorial-EJB/ejbModule
  2. Name:* jboss-ejb-client.properties

Y Finish. Dentro del archivo de propiedades ponemos lo siguiente:

remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false

remote.connections=default

remote.connection.default.host=localhost
remote.connection.default.port = 4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false

Ahora ya tenemos todo el entorno EJB listo para empezar a desarrollar. EL entorno de trabajo quedará de la siguiente forma:



Primero que todo configuramos las entidades que serán mapeadas prácticamente como nuestras tablas creadas inicialmente en la Base de datos:
/ProyectoEJBTutorial-EJB/ejbModule/com/victor/elliott/humala/entidades/UsuarioEntity.java

package com.victor.elliott.humala.entidades;

import java.io.Serializable;  

import javax.persistence.*; 


@Entity  
@Table(name = "usuario") 
public class UsuarioEntity implements Serializable{
    private static final long serialVersionUID = 1L;
 
  @Id
  @Column(name="id")
  @GeneratedValue(strategy=GenerationType.IDENTITY)
  private Integer id;
  
  @Column(name="nombre")
  private String nombre;
  
  @Column(name="clave")
  private String clave;

  public Integer getId() {
   return id;
  }

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

  public String getNombre() {
   return nombre;
  }

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

  public String getClave() {
   return clave;
  }

  public void setClave(String clave) {
   this.clave = clave;
  }
  
  public String toString(){
   
   return "Usuario: "+this.nombre;
  }
}

/ProyectoEJBTutorial-EJB/ejbModule/com/victor/elliott/humala/entidades/ComponenteEntity.java

package com.victor.elliott.humala.entidades;

import java.io.Serializable;
import javax.persistence.*;

@Entity
@Table(name="componente")
public class ComponenteEntity implements Serializable{
    private static final long serialVersionUID = 1L;

 
  @Id
  @Column(name="id")
  @GeneratedValue(strategy=GenerationType.IDENTITY)
  private Integer id;
  
  @Column(name="nombre")
  private String nombre;
  
  @Column(name="version")
  private String version;
  
  @Column(name="tipo")
  private String tipo;
  
  @Column(name="extension")
  private String extension;
  
  public Integer getId() {
   return id;
  }
  public void setId(Integer id) {
   this.id = id;
  }
  public String getNombre() {
   return nombre;
  }
  public void setNombre(String nombre) {
   this.nombre = nombre;
  }
  public String getVersion() {
   return version;
  }
  public void setVersion(String version) {
   this.version = version;
  }
  public String getTipo() {
   return tipo;
  }
  public void setTipo(String tipo) {
   this.tipo = tipo;
  }
  public String getExtension() {
   return extension;
  }
  public void setExtension(String extension) {
   this.extension = extension;
  }
  
  public String toString(){
   
   return "Componente: "+this.id+", "+this.nombre+", "+this.version+", "+this.extension;
  }
 }
Si os percatáis ambas entidades implementan Serializable, esto es debido a que son objetos que viajarán via red para ser guardadas en la session Http cuando usemos el cliente servlet (posteriormente).
Ahora ya tenemos mapeadas nuestras tablas con estas dos entidades. Ahora desarrollemos las llamadas respectivas en los sessionBean:

Antes que nada indicar que la diferencia principal entre una interfaz local y remota es que una interfaz local necesita un cliente que tenga el mismo JVM (Java Virtual Machine) y una remota no. Por ejemplo el cliente que vamos a implementar en un momento es standalone lo cual quiere decir que no se va a ejecutar con nuestro proyecto. Este cliente vamos a ejecutar como una aplicación Java que se encuentra fuera del contexto de nuestro proyecto y por lo tanto tiene una diferente JVM por lo que las pruebas solo podremos hacerla con la interfaz remota. (Podéis probar con la local si deseáis pero os saldrá un error de compatibilidad)
Ahora desarrollemos nuestras interfaces y sus respectivas implementaciones.
Primero modifiquemos:

/ProyectoEJBTutorial-EJB/ejbModule/com/victor/elliott/humala/negocio/UsuarioInterfazLocal.java

package com.victor.elliott.humala.negocio;

import javax.ejb.Local;

import com.victor.elliott.humala.entidades.UsuarioEntity;

@Local
public interface UsuarioInterfazLocal {
 public boolean buscarUsuario(UsuarioEntity usuario);
}

Aqui estamos indicando que la clase es una interfaz de tipo Local declarando un método a ser implementado.

/ProyectoEJBTutorial-EJB/ejbModule/com/victor/elliott/humala/logica/UsuarioSessionBean.java

package com.victor.elliott.humala.logica;

import com.victor.elliott.humala.entidades.UsuarioEntity;
import com.victor.elliott.humala.negocio.UsuarioInterfazLocal;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 * Session Bean implementation class UsuarioSessionBean
 */
@Stateless
public class UsuarioSessionBean implements UsuarioInterfazLocal {

 @PersistenceContext  
 private EntityManager entityManager;
 
 @Override
 public boolean buscarUsuario(UsuarioEntity usuario) {
  boolean existe=false;
  String queryString = "select u from UsuarioEntity u where u.nombre = :nombre and u.clave = :clave";
  Query query = this.entityManager.createQuery(queryString);
  query.setParameter("nombre", usuario.getNombre());
        query.setParameter("clave", usuario.getClave());
        existe = !query.getResultList().isEmpty();
  return existe;
 }

}



  1. Aquí creamos nuestra clase UsuarioSessionBean que implementa UsuarioInterfazLocal.
  2. La clase está declarada como Stateless lo cual indica que el estado del SessionBean no estará dedicado a un cliente específico lo cual quiere decir que muchos cliente podrían interactuar con el y modificar su estado y/o datos. Si fuera Statefull indicaría que el estado del sessionBean solo estará reservado para el cliente que lo invoque por tanto no se perdería la data especifica para ese cliente. Y finalmente si se tratará de un Singleton su estado será compartido por toda la aplicación es decir que se instancia una sola vez al sessionBean al inicio de la aplicación y esta instancia perdurará hasta que se apague el servidor.
  3. Creamos nuestro EntityManager que es el encargado de interactuar con la Base de datos a través del Entity UsuarioEntity que definimos anteriormente.
  4. Implementamos el método buscarUsuario que me retornará true en caso que lo encuentre.
  5. Hay que percatarnos que la query se hace contra la entidad y no contra la tabla en si, me refiero que no hacemos "select u from usuario u" si no "select u from UsuarioEntity u".
Modificamos
/ProyectoEJBTutorial-EJB/ejbModule/com/victor/elliott/humala/negocio/ComponenteInterfazRemota.java

package com.victor.elliott.humala.negocio;

import java.util.List;

import javax.ejb.Remote;

import com.victor.elliott.humala.entidades.ComponenteEntity;

@Remote
public interface ComponenteInterfazRemota {
   public void agregarComponente(ComponenteEntity componente);
   public List<ComponenteEntity> mostrarComponentes();
   public void eliminarComponente(Integer id);
   public void actualizarComponente(ComponenteEntity componente);
   public ComponenteEntity mostrarComponente(Integer id);
   public boolean existeComponente(ComponenteEntity componente);
}

Aqui estamos indicando que la clase es una interfaz de tipo Remota declarando seis métodos a ser implementados.

/ProyectoEJBTutorial-EJB/ejbModule/com/victor/elliott/humala/logica/ComponenteSessionBean.java

package com.victor.elliott.humala.logica;

import java.util.List;

import com.victor.elliott.humala.entidades.ComponenteEntity;
import com.victor.elliott.humala.negocio.ComponenteInterfazRemota;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
/**
 * Session Bean implementation class ComponenteSessionBean
 */
@Stateless
public class ComponenteSessionBean implements ComponenteInterfazRemota {
 
 @PersistenceContext  
 private EntityManager entityManager;
 
 @Override
 public void agregarComponente(ComponenteEntity componente) {
  entityManager.persist(componente);
 }

 @Override
 public List<ComponenteEntity> mostrarComponentes() {
  String queryString = "select c from ComponenteEntity c";
  TypedQuery<ComponenteEntity> query = this.entityManager.createQuery(queryString,ComponenteEntity.class);
  return query.getResultList();
 }

 @Override
 public void eliminarComponente(Integer id) {
  ComponenteEntity entity=entityManager.find(ComponenteEntity.class, id);
  entityManager.remove(entity);
 }

 @Override
 public void actualizarComponente(ComponenteEntity componente) {
  entityManager.merge(componente);
 }

 @Override
 public ComponenteEntity mostrarComponente(Integer id) {
  return entityManager.find(ComponenteEntity.class, id);
 }
 
 public boolean existeComponente(ComponenteEntity componente) {
  boolean existe=false;
  String queryString = "select c from ComponenteEntity c where c.nombre = :nombre";
  Query query = this.entityManager.createQuery(queryString);
  query.setParameter("nombre", componente.getNombre());
        existe = !query.getResultList().isEmpty();
  return existe;
 } 
}
  1. Aquí creamos nuestra clase ComponenteSessionBean que implementa ComponenteInterfazRemota.
  2. La clase está declarada como Stateless lo cual indica que el estado del SessionBean no estará dedicado a un cliente específico lo cual quiere decir que muchos cliente podrían interactuar con el y modificar su estado y/o datos. Si fuera Statefull indicaría que el estado del sessionBean solo estará reservado para el cliente que lo invoque por tanto no se perdería la data especifica para ese cliente. Y finalmente si se tratará de un Singleton su estado será compartido por toda la aplicación es decir que se instancia una sola vez al sessionBean al inicio de la aplicación y esta instancia perdurará hasta que se apague el servidor.
  3. Creamos nuestro EntityManager que es el encargado de interactuar con la Base de datos a través del Entity ComponenteEntity que definimos anteriormente.
  4. Implementamos los métodos agregarComponente, mostrarComponentes, eliminarComponente, actualizarComponente, mostrarComponente, existeComponente que me retornará true en caso que lo encuentre.
  5. Hay que percatarnos que la query se hace contra la entidad y no contra la tabla en si, me refiero que no hacemos "select c from componente c" si no "select c from ComponenteEntity c".
Ahora codificamos a nuestro cliente:

/ProyectoEJBTutorial-EJB/ejbModule/com/victor/elliott/humala/cliente/ClienteProbador.java

package com.victor.elliott.humala.cliente;

import java.util.List;

import javax.naming.Context;
import javax.naming.NamingException;

import com.victor.elliott.humala.clienteutility.JNDILookupClass;
import com.victor.elliott.humala.entidades.ComponenteEntity;
import com.victor.elliott.humala.logica.ComponenteSessionBean;
import com.victor.elliott.humala.negocio.ComponenteInterfazRemota;

public class ClienteProbador {

 public static void main(String[] args) {
  ComponenteInterfazRemota componenteIR=doLookup();
  List<ComponenteEntity> componentesLista;
  ComponenteEntity componente=new ComponenteEntity();
  boolean existe=false;

  componente.setNombre("Eclipse");
  componente.setVersion("4.3.0");
  componente.setTipo("IDE");
  componente.setExtension("exe");
  componenteIR.agregarComponente(componente);//id=1
  componente.setNombre("Hibernate");
  componente.setVersion("4.2.7");
  componente.setTipo("Framework");
  componente.setExtension("zip");
  componenteIR.agregarComponente(componente);//id=2
  componente.setNombre("EJB");
  componente.setVersion("3.1.0");
  componente.setTipo("Framework");
  componente.setExtension("zip");
  componenteIR.agregarComponente(componente);//id=3
  componente.setNombre("MySQL");
  componente.setVersion("5.0");
  componente.setTipo("BD");
  componente.setExtension("msi");
  componenteIR.agregarComponente(componente);//id=4
  componentesLista = componenteIR.mostrarComponentes();
  System.out.println(componentesLista.toString());
  componente.setId(1);
  componente.setNombre("Eclipse");
  componente.setVersion("4.3.1");
  componente.setTipo("IDE");
  componente.setExtension("exe");
  componenteIR.actualizarComponente(componente);
  System.out.println(componenteIR.mostrarComponente(1).toString());
  componenteIR.eliminarComponente(4);
  componentesLista = componenteIR.mostrarComponentes();
  System.out.println(componentesLista.toString());
  componente.setNombre("Eclipse");
  existe=componenteIR.existeComponente(componente);
  System.out.println("Componente Eclipse existe es:"+existe);
  componente.setNombre("MySQL");
  existe=componenteIR.existeComponente(componente);
  System.out.println("Componente MySQL existe es:"+existe);
 }
    private static ComponenteInterfazRemota doLookup() {
        Context context = null;
        ComponenteInterfazRemota cIR = null;
        try {
            // 1. Obtaining Context
            context = JNDILookupClass.getInitialContext();
            // 2. Generate JNDI Lookup name
            String lookupName = getLookupName();
            // 3. Lookup and cast
            System.out.println("EL lookupName es: "+lookupName);
            cIR = (ComponenteInterfazRemota) context.lookup(lookupName);
 
        } catch (NamingException e) {
            e.printStackTrace();
        }
        return cIR;
    }
 
    private static String getLookupName() {
        /*The app name is the EAR name of the deployed EJB without .ear
        suffix. Since we haven't deployed the application as a .ear, the app
        name for us will be an empty string */
        String appName = "";
 
        /* The module name is the JAR name of the deployed EJB without the
        .jar suffix.*/
        String moduleName = "ProyectoEJBTutorial-EJB";
 
        /* AS7 allows each deployment to have an (optional) distinct name.
        This can be an empty string if distinct name is not specified.*/
        String distinctName = "";
 
        // The EJB bean implementation class name
        String beanName = ComponenteSessionBean.class.getSimpleName();
 
        // Fully qualified remote interface name
        final String interfaceName = ComponenteInterfazRemota.class.getName();
 
        // Create a look up string name
        String name = "ejb:" + appName + "/" + moduleName + "/" +
                distinctName    + "/" + beanName + "!" + interfaceName;
        return name;
    } 

}

Que realizará las siguientes tareas:
  1. Crear cuatro componentes en la base de datos con id auto-generables: 1,2,3 y 4 respectivamente.
  2. Mostrar los cuatro componentes mediante una lista.
  3. Modificar el primer componente id=1
  4. Mostrar el primer componente
  5. Eliminar el cuarto componente id=4
  6. Mostrar los 3 componentes de la base de datos que quedan.
  7. Pregunta si existe el componentes Eclipse
  8. Pregunta si exise el componente MySQL
  9. Creamos el método doLookup y getLookupName para invocar a nuestro EJB remotoa través de JNDI. Hay que percatarnos que doLookup  hace la llamada JNDILookupClass para obtener el nombre del contexto con sus respectivas propiedades y getLookupName construye el nombre como será invocado el EJB remoto.
Ahora y tenemos lista nuestra aplicación EJB para poder ser testeada. Antes que nada asegurémonos que tenemos nuestra base de datos vacía para que no haya errores al invocar los métodos. Para esto ejecutemos los siguientes comandos en la Base de datos:

DELETE FROM COMPONENTE;
ALTER TABLE COMPONENTE AUTO_INCREMENT=1;

Ahora Iniciemos el servidor Click derecho en JBoss Runtime Server -> Start
Una vez tengamos el servidor levantado hacemos click derecho -> Add and Remove
seleccionamos nuestra aplicación ProyectoEJBTutorial-EJB y presionamos ADD pafra agregarlo a nuestro servidor y poder deployarlo. Presionamos Finish y tendremos que ver lo siguiente en el log de la consola sin ningún error:

18:55:22,016 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) JNDI bindings for session bean named UsuarioSessionBean in deployment unit deployment "ProyectoEJBTutorial-EJB.jar" are as follows:

 java:global/ProyectoEJBTutorial-EJB/UsuarioSessionBean!com.victor.elliott.humala.negocio.UsuarioInterfazLocal
 java:app/ProyectoEJBTutorial-EJB/UsuarioSessionBean!com.victor.elliott.humala.negocio.UsuarioInterfazLocal
 java:module/UsuarioSessionBean!com.victor.elliott.humala.negocio.UsuarioInterfazLocal
 java:global/ProyectoEJBTutorial-EJB/UsuarioSessionBean
 java:app/ProyectoEJBTutorial-EJB/UsuarioSessionBean
 java:module/UsuarioSessionBean

18:55:22,024 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) JNDI bindings for session bean named ComponenteSessionBean in deployment unit deployment "ProyectoEJBTutorial-EJB.jar" are as follows:

 java:global/ProyectoEJBTutorial-EJB/ComponenteSessionBean!com.victor.elliott.humala.negocio.ComponenteInterfazRemota
 java:app/ProyectoEJBTutorial-EJB/ComponenteSessionBean!com.victor.elliott.humala.negocio.ComponenteInterfazRemota
 java:module/ComponenteSessionBean!com.victor.elliott.humala.negocio.ComponenteInterfazRemota
 java:jboss/exported/ProyectoEJBTutorial-EJB/ComponenteSessionBean!com.victor.elliott.humala.negocio.ComponenteInterfazRemota
 java:global/ProyectoEJBTutorial-EJB/ComponenteSessionBean
 java:app/ProyectoEJBTutorial-EJB/ComponenteSessionBean
 java:module/ComponenteSessionBean

Esto quiere decir que nuestros SessionBean; UsuarioSessionBean y ComponenteSessionBean se han inicializado correctamente. Tenemos que estar atentos a cualquier cambio que hagamos en los EJB tenemos que volver a deployar es decir hacer click derecho en el servidor -> Add and Remove seleccionamos el proyecto y presionamos Remove modificamos nuestro EJB y luego lo volvemos a añadir ADD para que se vuelva a deployar con los cambios realizados. Ojo no es necesario reiniciar ni parar el servidor para esto. Cuando hagamos un cambio a nuestro cliente ClienteProbador no es necesario volver a deployar.

Ahora que ya tenemos nuestro proyecto deployado nos disponemos a ejecutar al cliente:
Click derecho en ClienteProbador -> Run as -> Java Application
y veremos el siguiente log si es que no ocurre ningún error:

EL lookupName es: ejb:/ProyectoEJBTutorial-EJB//ComponenteSessionBean!com.victor.elliott.humala.negocio.ComponenteInterfazRemota
[Componente: 1, Eclipse, 4.3.0, exe, Componente: 2, Hibernate, 4.2.7, zip, Componente: 3, EJB, 3.1.0, zip, Componente: 4, MySQL, 5.0, msi]
Componente: 1, Eclipse, 4.3.1, exe
[Componente: 1, Eclipse, 4.3.1, exe, Componente: 2, Hibernate, 4.2.7, zip, Componente: 3, EJB, 3.1.0, zip]
Componente Eclipse existe es:true
Componente MySQL existe es:false

Lo cual lo podréis corroborar haciendo un select en la base de datos sobre la tabla componente

Ahora comenzamos son la segunda parte del tutorial.

Creamos un proyecto WEB File -> New -> Dynamic Web Project

  1. Project Name: ProjectoEJBTutorial-WEB
  2. Target Runtime: JBoss 7.1 Runtime 1
  3. Dynamic Web Module version: 3.0
  4. Configuration: Default Configuration ....

Asociamos al Proyecto Web el Proyecto EJB que ya creamos en la primera parte.
Click Derecho al proyecto WEB -> Properties -> Java Build Path -> Projects -> Add  Seleccionamos ProyectoEJBTutorial-EJB -> OK -> OK Y ya tenemos nuestro proyecto WEB asociado al EJB

Creamos nuestros servlets:
Click Derecho en el projecto -> New  -> Other -> Web -> Servlet

  1. Source Folder: \ProjectoEJBTutorial-WEB\src
  2. Java Package: com.victor.elliott.humala.servlets
  3. Class Name: UsuarioServlet
  4. SuperClass: javax.servlet.http.HttpServlet



Click Derecho en el projecto -> New  -> Other -> Web -> Servlet

  1. Source Folder: \ProjectoEJBTutorial-WEB\src
  2. Java Package: com.victor.elliott.humala.servlets
  3. Class Name: ComponenteServlet
  4. SuperClass: javax.servlet.http.HttpServlet

Ahora creamos las paginas que necesitamos:
Primero creamos la carpeta jsp dentro de WEB-INF

  1. index.jsp en /ProjectoEJBTutorial-WEB/WebContent
  2. login.jsp en /ProjectoEJBTutorial-WEB/WebContent/WEB-INF/jsp
  3. agregarComponentes.jsp en /ProjectoEJBTutorial-WEB/WebContent/WEB-INF/jsp
  4. mostrarComponentes.jsp en /ProjectoEJBTutorial-WEB/WebContent/WEB-INF/jsp
Finalmente creamos nuestro descriptor de despliegue
  1. web.xml en /ProjectoEJBTutorial-WEB/WebContent/WEB-INF
Al final la estructura del proyecto quedará de la siguiente forma:



Para evitar complejidad en nuestro descriptor de despliegue (web.xml) vamos usar la anotaciones que nos proporciona la versión 3.0 de los servlets y así solo ponemos nuestra página de inicio en el descriptor.

Primero que todo modificamos los servlet:
/ProyectoEJBTutorial-WEB/src/com/victor/elliott/humala/servlets/UsuarioServlet.java

package com.victor.elliott.humala.servlets;

import java.io.IOException;

import javax.ejb.EJB;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.victor.elliott.humala.entidades.UsuarioEntity;
import com.victor.elliott.humala.negocio.UsuarioInterfazLocal;

@WebServlet("/UsuarioServlet")
public class UsuarioServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	 @EJB UsuarioInterfazLocal usuarioLocal;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String forward="";
		forward="/jsp/login.jsp";
		RequestDispatcher rd = request.getRequestDispatcher(forward);
		rd.forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String message="";
		String forward="";
		String nombre=request.getParameter("nombre");
		String clave=request.getParameter("clave");
		UsuarioEntity usuario=new UsuarioEntity();
		usuario.setNombre(nombre);
		usuario.setClave(clave);
		if(datosVacios(usuario)){
			message="El nombre y/o la clave no pueden estar vacios";
			forward="/jsp/login.jsp";
		}
		else{
			if(!existeUsuario(usuario)){
				message="El usuario no pertenece al sistema";
				forward="/jsp/login.jsp";
			}
			else{
				message="Usuario Correcto: "+usuario.getNombre();
				request.setAttribute("accion", "agregarComponente");
				forward="/jsp/agregarComponentes.jsp";
				request.getSession().setAttribute("usuario", usuario);
			}					
		}
		request.setAttribute("message", message); 
		RequestDispatcher rd = request.getRequestDispatcher(forward);
		rd.forward(request, response);		
	}
	
	public boolean existeUsuario(UsuarioEntity usuario){
		
		return usuarioLocal.buscarUsuario(usuario);
	}
	public boolean datosVacios(UsuarioEntity usuario){
		return ("".equals(usuario.getNombre())||"".equals(usuario.getClave()));
	}
}


  1. Todos los import son necesarios para codificar este servlet.
  2. Podemos percatarnos que estamos usando la anotación @WebServlet, esto es para indicar a quienes quieran invocar a este servlet que no es necesario que lo busque en el descriptor de despliegue.
  3. @EJB es una anotacion que nos permitirá obtener la referencia al EJB UsuarioInterfazLocal donde tenéis que recordar que hacemos referencia a la interfaz y no al implementador UsuarioSessionBean.
  4. El método doGet lo usarán todas aquellas llamadas que no se pase un formulario, para este caso especifico nos servirá solo para que el index.jsp nos redirija a nuestra pagina inicial login.jsp
  5. En el método doPost lo usarán todas aquellas llamadas donde se pase un formulario, para este caso nos servirá para pasar los datos del formulario del Login.
  6. Validamos los datos del Login con el método datosVacio() y una vez validado preguntamos si el usuario existe con el método existeUsuario()
  7. El método existeUsuario simplemente pregunta al EJB si el usuario que pasamos como parámetro existe en el sistema.
/ProyectoEJBTutorial-WEB/src/com/victor/elliott/humala/servlets/ComponenteServlet.java

package com.victor.elliott.humala.servlets;

import java.io.IOException;

import javax.ejb.EJB;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.victor.elliott.humala.entidades.ComponenteEntity;
import com.victor.elliott.humala.entidades.UsuarioEntity;
import com.victor.elliott.humala.negocio.ComponenteInterfazRemota;

@WebServlet("/ComponenteServlet")
public class ComponenteServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	@EJB ComponenteInterfazRemota componenteRemoto;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		UsuarioEntity usuario=(UsuarioEntity)request.getSession().getAttribute("usuario");
		String message="";
		String forward="";
		String accion=request.getParameter("accion");
		if("verListaComponentes".equals(accion)){
			request.setAttribute("listaComponentes", componenteRemoto.mostrarComponentes());
			forward="/jsp/mostrarComponentes.jsp";
		}
		else if("volverAgregarComponente".equals(accion)){
			request.setAttribute("accion", "agregarComponente");
			forward="/jsp/agregarComponentes.jsp";
		}
		else if("volverModificarComponente".equals(accion)){
			Integer id=Integer.parseInt(request.getParameter("id"));
			ComponenteEntity componenteModificar=componenteRemoto.mostrarComponente(id);
			request.setAttribute("nombre", componenteModificar.getNombre());
			request.setAttribute("tipo", componenteModificar.getTipo());
			request.setAttribute("version", componenteModificar.getVersion());
			request.setAttribute("extension", componenteModificar.getExtension());
			request.setAttribute("id", componenteModificar.getId());
			request.setAttribute("accion", "modificarComponente");
			forward="/jsp/agregarComponentes.jsp";
		}
		else if("eliminarComponente".equals(accion)){
			Integer id=Integer.parseInt(request.getParameter("id"));
			componenteRemoto.eliminarComponente(id);
			request.setAttribute("listaComponentes", componenteRemoto.mostrarComponentes());
			forward="/jsp/mostrarComponentes.jsp";			
		}
		message="Usuario Correcto: "+usuario.getNombre();
		request.setAttribute("message", message);
		RequestDispatcher rd = request.getRequestDispatcher(forward);
		rd.forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		UsuarioEntity usuario=(UsuarioEntity)request.getSession().getAttribute("usuario");
		String message="";
		String messageError="";
		String forward="";
		String nombre=request.getParameter("nombre");
		String version=request.getParameter("version");
		String tipo=request.getParameter("tipo");
		String extension=request.getParameter("extension");
		String accion=request.getParameter("accion");
		ComponenteEntity componente=new ComponenteEntity();
		componente.setNombre(nombre);
		componente.setVersion(version);
		componente.setTipo(tipo);
		componente.setExtension(extension);
		
		if("Agregar".equals(accion)){
			accion="agregarComponente";
			if(datosVacios(componente)){				
				messageError="Ningun dato del componente puede estar vacío";
				forward="/jsp/agregarComponentes.jsp";
			}
			else{
				if(existeComponente(componente)){
					messageError="El componente: "+componente.getNombre()+" ya existe en el sistema";
					forward="/jsp/agregarComponentes.jsp";
				}
				else{
					componenteRemoto.agregarComponente(componente);
					request.setAttribute("listaComponentes", componenteRemoto.mostrarComponentes());
					forward="/jsp/mostrarComponentes.jsp";
				}					
			}
		}
		else if("Modificar".equals(accion)){
			accion="modificarComponente";
			if(datosVacios(componente)){
				messageError="Ningun dato del componente puede estar vacío";
				forward="/jsp/agregarComponentes.jsp";
			}
			else{
				Integer id=Integer.parseInt(request.getParameter("id"));
				componente.setId(id);
				componenteRemoto.actualizarComponente(componente);
				request.setAttribute("listaComponentes", componenteRemoto.mostrarComponentes());
				forward="/jsp/mostrarComponentes.jsp";
				
			}			
		}
		message="Usuario Correcto: "+usuario.getNombre();
		request.setAttribute("accion", accion);
		request.setAttribute("message", message);
		request.setAttribute("messageError", messageError);
		RequestDispatcher rd = request.getRequestDispatcher(forward);
		rd.forward(request, response);
	}

	public boolean datosVacios(ComponenteEntity componente){
		return ("".equals(componente.getNombre())||"".equals(componente.getVersion())||"".equals(componente.getTipo())||"".equals(componente.getExtension()));
	}
	public boolean existeComponente(ComponenteEntity componente){
		return componenteRemoto.existeComponente(componente);
	}
}

  1. Todos los import son necesarios para codificar este servlet.
  2. Podemos percatarnos que estamos usando la anotación @WebServlet, esto es para indicar a quienes quieran invocar a este servlet que no es necesario que lo busque en el descriptor de despliegue.
  3. @EJB es una anotacion que nos permitirá obtener la referencia al EJB ComponenteInterfazRemota donde tenéis que recordar que hacemos referencia a la interfaz y no al implementador ComponenteSessionBean.
  4. El método doGet lo usarán todas aquellas llamadas que no se pase un formulario, para este caso especifico nos servirá para las siguientes acciones:  verListaComponentes, volverAgregarComponente, volverModificarComponente y eliminarComponente
  5. En el método doPost lo usarán todas aquellas llamadas donde se pase un formulario, para este caso nos servirá para pasar las siguientes acciones: Agregar y Modificar a un componente.
  6. Validamos en ambos casos los datos del Componente con el método datosVacio().
  7. El método existeComponente simplemente pregunta al EJB si el componente que pasamos como parámetro existe en el sistema.
Finalmente modificamos nuestro descriptor de despliegue (web.xml) para indicar que la pagina principal es el index.jsp

/ProyectoEJBTutorial-WEB/WebContent/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>  
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
id="WebApp_ID" version="2.5">  
  <display-name>ProyectoEJBTutorial-WEB</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

Ahora que ya tenemos listo nuestro proyecto WEB si queréis podéis probar en deployarlo haciendo RUN con el servidor JBOSS pero darán algunos problemas de error con los EJB ya que las anotaciones @EJB solo sirven siempre y cuando se encuentren dentro de un proyecto de empresa (Enterprise Application Project). Para esto crearemos nuestro proyecto que contendra el proyecto EJB y el proyecto WEB.
File -> New -> Enterprise Application Project
  1. Project Name: ProyectoEJBTutorial-Enterprise
  2. Target runtime: JBoss 7.1 Runtime
  3. EAR version: 6.0
  4. Configuration: Default
Tal como podemos ver en la imagen:


Damos Next y en la siguiente pantalla seleccionamos nuestros proyectos ProyectoEJBTutorial-EJB y ProyectoEJBTutorial-WEB y damos click en Finish.
Ahora ya estamos listos para deployar nuestro proyecto. Vamos al servidor: click derecho -> Add and Remove -> Nos aseguramos que los proyectos EJB no WEB se encuentren agregados y agregamos el proyecto ProyectoEJBTutorial-Enterprise y Finish.
Si hemos hecho todo bien no debería salir ningun error en el log de la consola solo que se han generado correctamente nuestros EJB:

17:38:26,555 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) JNDI bindings for session bean named UsuarioSessionBean in deployment unit subdeployment "ProyectoEJBTutorial-EJB.jar" of deployment "ProyectoEJBTutorial-Enterprise.ear" are as follows:

	java:global/ProyectoEJBTutorial-Enterprise/ProyectoEJBTutorial-EJB/UsuarioSessionBean!com.victor.elliott.humala.negocio.UsuarioInterfazLocal
	java:app/ProyectoEJBTutorial-EJB/UsuarioSessionBean!com.victor.elliott.humala.negocio.UsuarioInterfazLocal
	java:module/UsuarioSessionBean!com.victor.elliott.humala.negocio.UsuarioInterfazLocal
	java:global/ProyectoEJBTutorial-Enterprise/ProyectoEJBTutorial-EJB/UsuarioSessionBean
	java:app/ProyectoEJBTutorial-EJB/UsuarioSessionBean
	java:module/UsuarioSessionBean

17:38:26,564 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) JNDI bindings for session bean named ComponenteSessionBean in deployment unit subdeployment "ProyectoEJBTutorial-EJB.jar" of deployment "ProyectoEJBTutorial-Enterprise.ear" are as follows:

	java:global/ProyectoEJBTutorial-Enterprise/ProyectoEJBTutorial-EJB/ComponenteSessionBean!com.victor.elliott.humala.negocio.ComponenteInterfazRemota
	java:app/ProyectoEJBTutorial-EJB/ComponenteSessionBean!com.victor.elliott.humala.negocio.ComponenteInterfazRemota
	java:module/ComponenteSessionBean!com.victor.elliott.humala.negocio.ComponenteInterfazRemota
	java:jboss/exported/ProyectoEJBTutorial-Enterprise/ProyectoEJBTutorial-EJB/ComponenteSessionBean!com.victor.elliott.humala.negocio.ComponenteInterfazRemota
	java:global/ProyectoEJBTutorial-Enterprise/ProyectoEJBTutorial-EJB/ComponenteSessionBean
	java:app/ProyectoEJBTutorial-EJB/ComponenteSessionBean
	java:module/ComponenteSessionBean

Finalmente hacemos click derecho en ProyectoEJBTutorial-Enterprise -> Run As -> Run on server y veremos las siguientes pantallas:




Y una vez agregado varios componentes al sistema tendremos el resultado respectivo:



Finalmente podemos exportar nuestro proyecto como un EAR para independizarnos del eclipse y poderlo deployar a traves del ear. Click derecho sobre ProyectoEJBTutorial-Enterprise -> export -> EAR File le indicamos el destino y se habrá creado ProyectoEJBTutorial-Enterprise.ear

El código delos proyectos os lo podéis bajar de los siguientes links

lunes, 23 de diciembre de 2013

- Struts 2 con anotaciones sin Maven

En este tutorial describiré los pasos necesarios para realizar un proyecto Struts 2 con anotaciones sin la herramienta de gestión y construcción MAVEN, lo cual quiere decir que obtendremos nosotros mismos las librerías necesarias para nuestros proyecto así como configuraremos nuestro entorno de desarrollo para que todos los componentes sean tomadas correctamente en nuestra aplicación. Ademas usaremos anotaciones lo cual quiere decir que no configuraremos el comportamiento de nuestra aplicación a través del fichero struts.xml.

Introducción a Struts 2

Es un framework en JAVA que se usa para realizar proyectos MVC que básicamente es un patrón de arquitectura Modelo - Vista - Controlador cuyos componentes están definidos de la siguiente manera:

Figura 1.1 – P.S Imagen copiada de  : javatutoriales


  1. Inicialmente nuestra página realiza la petición HTTP a nuestro Filter Dispatcher.
  2. El Filter Dispatcher envía los datos a los interceptores para que estos puedan realizar las respectivas validaciones con respecto a la data que estamos enviando.
  3. Los interceptores una vez que hayan validado la información de la data enviada procederán a invocar al Action.
  4. Se invoca al Action respectivo según la configuración que en el Filter Dispatcher el cual se encargará de realizar la lógica respectiva ya sea de procesar una información y/o devolver algún dato necesario.
  5. Una vez terminado el trabajo del Action devolverá la información requerida al result para que posteriormente el Filter Dispatcher sepa cual será el siguiente paso ya sea un jsp o otro Action.
  6. Los resultados serán validados por los interceptores.
  7. Los interceptores envían el resultado al Filter Dispatcher.
  8. El Filter Dispatcher envía el resultado ya sea vía WEB para que el usuario lo visualice o lo redirigirá a otra Acción.
Para este proyecto vamos a usar anotaciones lo cual quiere decir que no crearemos el fichero struts.xml y la configuración de los action las realizaremos dentro de cada acción (método). Esto nos lo permite la librería struts2-convention-plugin. donde se encuentras los componentes que necesitamos para hacerlo. Con respecto a su uso, es de diferentes gustos, personalmente me agrada mas puesto que me confundo menos al crear una nueva acción y ya lo puedo configurar dentro de su propio método, sin embargo algunos veteranos de struts no están muy de acuerdo, es simplemente cuestión de gustos. 


Proyecto en Struts 2
  1. Eclipse Kepler
  2. Apache Tomcat 7.0
  3. Librerías Struts 2
Como indiqué anteriormente no explicaré como se realiza la instalación del Eclipse con su respectivo JDK ni el Tomcat por lo que se asume que ya tenéis el entorno instalado.

Primero que todo creamos un proyecto WEB en el eclipse: File -> New -> Dynamic Web Project
y el siguiente nombre al proyecto ProyectoStruts2AnotacionesTutorial y a continuación Finish para crear el proyecto tal como podemos verlo en la imagen:


A continuación creamos en /ProyectoStruts2AnotacionesTutorial/src los siguientes paquetes:
  1. com.victor.elliott.humala.action
  2. com.victor.elliott.humala.formulario
  3. com.victor.elliott.humala.dao
Luego creamos las siguientes clases en los paquetes respectivos
  1. com.victor.elliott.humala.action->  UsuarioAction.java
  2. com.victor.elliott.humala.action  ->  ComponenteAction.java
  3. com.victor.elliott.humala.formulario -> UsuarioForm.java
  4. com.victor.elliott.humala.formulario -> ComponenteForm.java
  5. com.victor.elliott.humala.dao-> ComponenteDAO.java
  6. com.victor.elliott.humala.dao-> ComponenteDAOImpl.java
Una vez creadas las clases creamos las paginas y xml's respectivos.
  1. Creamos primero que todo la carpeta jsp en /ProyectoStruts2AnotacionesTutorial/WebContent/
  2. Creamos index.jsp en /ProyectoStruts2AnotacionesTutorial/WebContent
  3. Creamos login.jsp en /ProyectoStruts2AnotacionesTutorial/WebContent/jsp
  4. Creamos agregarComponentes.jsp en /ProyectoStruts2AnotacionesTutorial/WebContent/jsp
  5. Creamos mostrarComponentes.jsp en /ProyectoStruts2AnotacionesTutorial/WebContent/jsp
  6. Creamos web.xml en /ProyectoStruts2AnotacionesTutorial/WebContent/WEB-INF
Una vez creadas nuestras clases, paginas y componentes que usaremos, la estructura de proyecto debe de quedar de la siguiente manera:



Ahora que ya tenemos casi todos los elementos necesarios para empezar a desarrollar nuestro proyecto haremos la configuración con Struts2 para empezar a usar el framework sin errores y para esto primero bajemos las librerías necesarias que os la podéis descargar desde el siguiente link:
  1. Librerías Struts 2
Una vez descargado lo descomprimimos y lo añadiremos a nuestro proyecto de la siguiente manera:
Click derecho en ProyectoStruts2AnotacionesTutorial-> Properties -> Java Build Path -> Libraries -> Add Library -> User Library -> Next -> User Libraries -> New  y a continuación escriben Struts2 y OK que sera el nombre de la librería, inmediatamente sin salir de la ventana presionamos Add External JARs vamos a la carpeta donde descomprimimos las librerías, seleccionamos todos los jars presionamos Abrir y finalmente OK. Saliendo de esa ventana pondremos Finish y ya tendremos nuestras librerías de Struts2 agregadas al proyecto tal como se muestra:




Por ultimo tendremos que hacer que las librerías tengan efecto inmediato en todas las clases de nuestro proyecto y que no haya problemas de compilación ni de ejecución:
Click derecho en ProyectoStruts2AnotacionesTutorial -> Deployment Assembly -> Add seleccionamos la librería Struts 2 y OK y quedará tal como se muestra en la imagen.



Ahora si podemos empezar a codificar nuestro proyecto. Primero que todo modificamos com.victor.elliott.humala.formulario.UsuarioForm que básicamente contendrá los atributos nombre y clave sus getter y setter respectivos y dos constructores.

package com.victor.elliott.humala.formulario;

public class UsuarioForm{

 private String nombre;
 private String clave;
 
 
 public UsuarioForm(){
  this.nombre = "";
  this.clave = "";
 }
 public UsuarioForm(String nombre, String clave){
  this.nombre = nombre;
  this.clave = clave;
 }
 public String getNombre() {
  return nombre;
 }
 public void setNombre(String nombre) {
  this.nombre = nombre;
 }
 public String getClave() {
  return clave;
 }
 public void setClave(String clave) {
  this.clave = clave;
 }
}

Ahora modificamos com.victor.elliott.humala.action.UsuarioAction de la siguiente manera:

package com.victor.elliott.humala.action;

import com.victor.elliott.humala.formulario.UsuarioForm;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;

public class UsuarioAction extends ActionSupport{
  
 private static final long serialVersionUID = 1L;
  //Con esto indicamos que nuestro Usuario y clave seran Usuario y Clave respectivamente
     private static UsuarioForm usuario = new UsuarioForm("Victor","Elliott");
     private UsuarioForm usuarioForm;
     //private static ComponenteForm componenteForm = new ComponenteForm();     

  @Action( value="LOGIN", results= {
     @Result(name=SUCCESS, type="dispatcher", location="/jsp/login.jsp") } )
  public String inicializarUsuario() {
   
   //usuarioForm=new UsuarioForm();
      System.out.println("Si hemos llegado aqui quiere decir que la pagina index.jsp ha invocado a este metodo inicializarUsuario");
      addActionMessage("Ingrese Usuario");
      return SUCCESS;
     }
 
     @Action( value="verificarUsuarioAccion", results= {
        @Result(name=SUCCESS, type="dispatcher", location="/jsp/agregarComponentes.jsp"), 
        @Result(name=ERROR, type="dispatcher", location="/jsp/login.jsp") } )    
     public String verificarUsuario() {
         String mensaje=null;
      System.out.println("Si hemos llegado aqui quiere decir que la pagina login.jsp ha invocado a este metodo verificarUsuario");
      if("".equals(usuarioForm.getNombre())||"".equals(usuarioForm.getClave())){
        System.out.println("Se coloco el usuario y clave vacios");
        mensaje="Debe de llenar los campos de Usuario y Clave";
        addActionError(mensaje);
        return ERROR;
      }
      else if(usuario.getNombre().equals(UsuarioAction.usuario.getNombre())&&usuarioForm.getClave().equals(UsuarioAction.usuario.getClave())){
       System.out.println("Se coloco al usuario y clave correctamente y va a la pagina de agregarComponentes");
       addActionMessage("Usuario Correcto: "+usuarioForm.getNombre());
       return SUCCESS;
      }
      else{
       System.out.println("Se coloco al usuario y clave incorrectamente y regresamos a la pagina de login con el mensaje de Usuario Incorrecto");
       mensaje="Usuario Incorrecto";
       addActionError(mensaje);
       return ERROR;
      }
     }

     public UsuarioForm getUsuarioForm() {
   return usuarioForm;
  }

  public void setUsuarioForm(UsuarioForm usuarioForm) {
   this.usuarioForm = usuarioForm;
  }

}
Ahora describo rápidamente el action:
  1. Todos los import son importantes puesto que son las librerías de Struts 2 que necesitamos para desarrollarlo. 
  2. Definimos el atributo UsuarioForm usuario para que guarde el usuario y clave a validar en el login.
  3. Definimos el atributo UsuarioForm usuarioForm con sus respectivos getter y setter para obtener el formulario del usuario desde la página de login.
  4. Aquí están las anotaciones y vamos a indicar que el método (inicializarUsuario) que vamos a definir en el siguiente punto se trata de un una acción (@Action) que la podremos invocar desde un jsp u otra acción a partir de su alias (LOGIN) y los posibles resultados de esta acción en este caso solo sera un (SUCCESS) que me envía a la página login.jsp.
  5. Definimos el método inicializarUsuario que será invocado desde el Filter Dispatcher donde devolveremos el único mensaje de texto que me pida ingresar los datos del usuario y el result será SUCCESS. El Filter Dispatcher a partir de este resultado me enviará a la pagina de login respectiva.
  6. Definimos anotaciones y vamos a indicar que el método (verificarUsuario) que vamos a definir en el siguiente punto se trata de un una acción (@Action) que la podremos invocar desde un jsp u otra acción a partir de su alias (verificarUsuarioAccion) y los posibles resultados de esta acción serán (SUCCESS) que me envía a la página agregarComponentes.jsp, (ERROR) que me envía a la página login.jsp. 
  7. Definimos el método verificarUsuario que será invocado desde el Filter Dispatcher donde validaremos que los datos obtenidos del formulario UsuarioForm usuarioForm son correctos a partir de UsuarioForm usuario.En caso de que los datos estén vacios o no coincidan con el usuario devolvere el mensaje addActionError respectivo y retornare el result como ERROR. Caso contrario devolveré el mesaje de éxito addActionMessage y retornaré el result como SUCCESS. El Filter Dispatcher a partir de este resultado me enviará a la pagina respectiva.
Ahora modificamos nuestros jsp:
/ProyectoStruts2AnotacionesTutorial/WebContent/index.jsp:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
    <META HTTP-EQUIV="Refresh" CONTENT="0;URL=LOGIN.action">
</head>
<body>
<p>El proyecto se esta cargando, espere un segundo</p>
</body>
</html>

Donde básicamente redireccionamos esta página a través la etiqueta META al action respectivo que será recibido por el Filter Dispatcher.

/ProyectoStruts2AnotacionesTutorial/WebContent/jsp/login.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@taglib uri="/struts-tags" prefix="s"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Proyecto Struts 2 Tutorial by Victor Elliott Humala</title>
</head>
<body>
<s:if test="hasActionErrors()">
   <div class="errors">
      <s:actionerror/>
   </div>
</s:if>
  
<s:form id="login" method="post" action="verificarUsuarioAccion">
  <s:textfield  name="usuarioForm.nombre" label="Nombre"/>
  <s:textfield  name="usuarioForm.clave" label="Clave"/>
  <s:submit id="submit" value="Login" />
</s:form>

</body>
</html>


  1. Declaramos la librería para nuestros tags de struts "struts-tags"
  2. Preguntamos si exísten errores hasActionErrors y si es asi mostramos el mensaje de error actionerror que definimos en el action respectivo.
  3. Finalmente agregamos un form para que puedas llenarse los datos necesarios del usuario (usuarioForm) y al hacer submit vaya al action respectivo verificarUsuarioAction que lo recibirá el Filter Dispatcher.

/ProyectoStruts2AnotacionesTutorial/WebContent/jsp/agregarComponentes.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@taglib uri="/struts-tags" prefix="s"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Agregar Componentes</title>
</head>
<body>
<s:if test="hasActionMessages()">
   <div class="welcome">
      <s:actionmessage />
   </div>
</s:if>
</body>
</html>


  1. En esta página por ahora solo mostraremos la bienvenida al usuario donde al hacer hasActionMessage preguntamos si existe algun mensaje de exito recibido y si es así el caso mostramos el mensaje actionmessage.
Ahora modifiquemos nuestros ficheros de configuración xml:

/ProyectoStruts2AnotacionesTutorial/WebContent/WEB-INF/web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>ProyectoStruts2AnotacionesTutorial</display-name>
  <filter>
  <filter-name>struts2</filter-name>
  <filter-class>
   org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>
</web-app>

Con esto estamos indicandole a nuestro descriptor de despliegue que vamos a trabajar con el framework de struts2.



Ahora ya estamos listos para ejecutar nuestro proyecto en el servidor Tomcat, antes de ello verificar que no haya ningún error de compilación y una vez ejecutado en el servidor ningún error de ejecución. Si todo esta bien podrán visualizar las siguientes páginas:



Ahora continuo con la segunda parte del tutorial.

Una vez que ya tenemos el login realizado, nos disponemos a crear una lista de componentes que cargaremos una a una para luego poder verlas todas juntas.

Modificamos:

/ProyectoStruts2AnotacionesTutorial/src/com/victor/elliott/humala/dao/ComponenteDAO.java

package com.victor.elliott.humala.dao;

import com.victor.elliott.humala.formulario.ComponenteForm;
import java.util.List;

public interface ComponenteDAO {
 public void addComponente(ComponenteForm componente);
 public List<ComponenteForm> getComponente();
}

Aqui simplemente estamos creando un DAO de tipo Interface donde solo declaramos dos métodos addComponente para agregar el componente y getComponente para recuperar todos los componentes.
Ahora creamos su implementación respectiva modificando:

/ProyectoStruts/src/com/victor/elliott/humala/dao/ComponenteDAOImpl.java

package com.victor.elliott.humala.dao;

import java.util.ArrayList;
import java.util.List;
import com.victor.elliott.humala.formulario.ComponenteForm;

public class ComponenteDAOImpl implements ComponenteDAO {
 private static List<ComponenteForm> listaComponentes=new ArrayList<ComponenteForm>();
 @Override
 public void addComponente(ComponenteForm componente) {
  listaComponentes.add(componente);
 }

 @Override
 public List<ComponenteForm> getComponente() {
  return listaComponentes;
 }
}

De esta forma implementamos los métodos de la interface primero declarando un atributo estático List<ComponenteForm> listaComponentes que me guardará todos los datos que ingrese en mi lista y no se perderá y luego con los metodos addComponente agrego un componente a la lista y con getComponente recupero toda la lista estática.
En consiguiente modificamos la clase:

/ProyectoStruts2AnotacionesTutorial/src/com/victor/elliott/humala/formulario/ComponenteForm.java

package com.victor.elliott.humala.formulario;

public class ComponenteForm {
 private String nombre;
 private String version;
 private String tipo;
 private String extension;
 
 public String getNombre() {
  return nombre;
 }
 public void setNombre(String nombre) {
  this.nombre = nombre;
 }
 public String getVersion() {
  return version;
 }
 public void setVersion(String version) {
  this.version = version;
 }
 public String getTipo() {
  return tipo;
 }
 public void setTipo(String tipo) {
  this.tipo = tipo;
 }
 public String getExtension() {
  return extension;
 }
 public void setExtension(String extension) {
  this.extension = extension;
 }

}
Clase que contiene todos los datos que deseo guardar de un componente. Finalmente modifico los action:

/ProyectoStruts2AnotacionesTutorial/src/com/victor/elliott/humala/action/UsuarioAction.java

package com.victor.elliott.humala.action;

import com.victor.elliott.humala.formulario.UsuarioForm;

import java.util.Map;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.interceptor.SessionAware;
import com.opensymphony.xwork2.ActionSupport;

public class UsuarioAction extends ActionSupport implements SessionAware{
  
 private static final long serialVersionUID = 1L;
  //Con esto indicamos que nuestro Usuario y clave seran Usuario y Clave respectivamente
     private static UsuarioForm usuario = new UsuarioForm("Victor","Elliott");
     private UsuarioForm usuarioForm;
     private Map<String, Object> sesion;
     //private static ComponenteForm componenteForm = new ComponenteForm();     

      @Action( value="LOGIN", results= {
        @Result(name=SUCCESS, type="dispatcher", location="/jsp/login.jsp") } )
  public String inicializarUsuario() {
   
   //usuarioForm=new UsuarioForm();
      System.out.println("Si hemos llegado aqui quiere decir que la pagina index.jsp ha invocado a este metodo inicializarUsuario");
      addActionMessage("Ingrese Usuario");
      return SUCCESS;
     }
      @Action( value="verificarUsuarioAccion", results= {
        @Result(name=SUCCESS, type="dispatcher", location="/jsp/agregarComponentes.jsp"), 
        @Result(name=ERROR, type="dispatcher", location="/jsp/login.jsp") } )     
     public String verificarUsuario() {
         String mensaje=null;
      System.out.println("Si hemos llegado aqui quiere decir que la pagina login.jsp ha invocado a este metodo verificarUsuario");
      if("".equals(usuarioForm.getNombre())||"".equals(usuarioForm.getClave())){
        System.out.println("Se coloco el usuario y clave vacios");
        mensaje="Debe de llenar los campos de Usuario y Clave";
        addActionError(mensaje);
        return ERROR;
      }
      else if(usuario.getNombre().equals(UsuarioAction.usuario.getNombre())&&usuarioForm.getClave().equals(UsuarioAction.usuario.getClave())){
       System.out.println("Se coloco al usuario y clave correctamente y va a la pagina de agregarComponentes");
       sesion.put("usuarioForm", usuarioForm);
       addActionMessage("Usuario Correcto: "+usuarioForm.getNombre());
       return SUCCESS;
      }
      else{
       System.out.println("Se coloco al usuario y clave incorrectamente y regresamos a la pagina de login con el mensaje de Usuario Incorrecto");
       mensaje="Usuario Incorrecto";
       addActionError(mensaje);
       return ERROR;
      }
     }

  public Map<String, Object> getSession() {
   return sesion;
  }

  public void setSession(Map<String, Object> sesion) {
   this.sesion = sesion;
  }

     public UsuarioForm getUsuarioForm() {
   return usuarioForm;
  }

  public void setUsuarioForm(UsuarioForm usuarioForm) {
   this.usuarioForm = usuarioForm;
  }

}

  1. Todos los import son importantes puesto que son las librerías de Struts 2 que necesitamos para desarrollarlo. 
  2. Implementamos la clase SessionAware donde sobrescribiremos su método setSession(Map<String, Object> sesion). Esta implementación nos sirve para poder guardar el usuarioForm en la sesion y no perderla cuando cambiemos de paginas haciendo request. 
  3. Definimos el atributo UsuarioForm usuario para que guarde el usuario y clave a validar en el login.
  4. Definimos el atributo UsuarioForm usuarioForm con sus respectivos getter y setter para obtener el formulario del usuario desde la página de login.
  5. Definimos el atributo Map<String, Object> sesion donde pondremos los datos que necesitemos para que se guarde en la sesion.
  6. Aquí están las anotaciones y vamos a indicar que el método (inicializarUsuario) que vamos a definir en el siguiente punto se trata de un una acción (@Action) que la podremos invocar desde un jsp u otra acción a partir de su alias (LOGIN) y los posibles resultados de esta acción en este caso solo sera un (SUCCESS) que me envía a la página login.jsp.
  7. Definimos el método inicializarUsuario que será invocado desde el Filter Dispatcher donde devolveremos el único mensaje de texto que me pida ingresar los datos del usuario y el result será SUCCESS. El Filter Dispatcher a partir de este resultado me enviará a la pagina de login respectiva.
  8. Definimos anotaciones y vamos a indicar que el método (verificarUsuario) que vamos a definir en el siguiente punto se trata de un una acción (@Action) que la podremos invocar desde un jsp u otra acción a partir de su alias (verificarUsuarioAccion) y los posibles resultados de esta acción serán (SUCCESS) que me envía a la página agregarComponentes.jsp, (ERROR) que me envía a la página login.jsp. 
  9. Definimos el método verificarUsuario que será invocado desde el Filter Dispatcher donde validaremos que los datos obtenidos del formulario UsuarioForm usuarioForm son correctos a partir de UsuarioForm usuario.En caso de que los datos estén vacios o no coincidan con el usuario devolvere el mensaje addActionError respectivo y retornare el result como ERROR. Caso contrario devolveré el mesaje de éxito addActionMessage y retornaré el result como SUCCESS. El Filter Dispatcher a partir de este resultado me enviará a la pagina respectiva. Como poderis apreciar en el caso de SUCCESS estamos guardando el formulario del usuario ingresado sesion.put("usuarioForm", usuarioForm); ya que nos interesa su información una vez ingrese al login.
/ProyectoStruts2AnotacionesTutorial/src/com/victor/elliott/humala/action/ComponenteAction.java

package com.victor.elliott.humala.action;


import java.util.List;
import java.util.Map;

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.victor.elliott.humala.formulario.ComponenteForm;
import com.victor.elliott.humala.formulario.UsuarioForm;
import com.victor.elliott.humala.dao.ComponenteDAO;
import com.victor.elliott.humala.dao.ComponenteDAOImpl;



public class ComponenteAction extends ActionSupport{
 private static final long serialVersionUID = 1L;
 private ComponenteDAO componenteDAO= new ComponenteDAOImpl();
 private ComponenteForm componenteForm;
 private List<ComponenteForm> componenteLista;
 
 String mensaje=null;
 
 @Action( value="agregarComponentesAccion", results= {
   @Result(name=SUCCESS, type="dispatcher", location="/jsp/mostrarComponentes.jsp"), 
   @Result(name=ERROR, type="dispatcher", location="/jsp/agregarComponentes.jsp") } )
 public String agregarComponentes() {
  ActionContext contexto = ActionContext.getContext();
  Map<String, Object> sesion = contexto.getSession();
  UsuarioForm usuarioForm=(UsuarioForm) sesion.get("usuarioForm");
  System.out.println("Ingreso a guardar componente");
     if("".equals(componenteForm.getNombre())||"".equals(componenteForm.getTipo())||"".equals(componenteForm.getVersion())||
       "".equals(componenteForm.getExtension())){
      System.out.println("Faltan datos al componente");
      mensaje="Faltan datos al componente";
      addActionMessage("Usuario Correcto: "+usuarioForm.getNombre());
      addActionError(mensaje);
      return ERROR;
     }
     else{
   componenteDAO.addComponente(componenteForm);
   System.out.println("Componente guardado");
   componenteLista=componenteDAO.getComponente();
   return SUCCESS;
     }
 }
 
 @Action( value="volverComponenteAccion", results= {
   @Result(name=SUCCESS, type="dispatcher", location="/jsp/agregarComponentes.jsp")})
 public String volverComponente() {
  ActionContext contexto = ActionContext.getContext();
  Map<String, Object> sesion = contexto.getSession();
  UsuarioForm usuarioForm=(UsuarioForm) sesion.get("usuarioForm");
  addActionMessage("Usuario Correcto: "+usuarioForm.getNombre());
  return SUCCESS;
 }

 public ComponenteForm getComponenteForm() {
  return componenteForm;
 }

 public List<ComponenteForm> getComponenteLista() {
  return componenteLista;
 }

 public void setComponenteLista(List<ComponenteForm> componenteLista) {
  this.componenteLista = componenteLista;
 }

 public void setComponenteForm(ComponenteForm componenteForm) {
  this.componenteForm = componenteForm;
 }
 
}

  1. Todos los import son importantes puesto que son las librerías de Struts 2 que necesitamos para desarrollarlo. 
  2. Definimos el atributo ComponenteDAO componenteDAO para obtener los datos de los componentes ingresados o insertar uno nuevo.
  3. ComponenteForm componenteForm con sus respectivos getter y setter para obtener los datos de un componente ingresado, realizar sus validaciones e ingresarlo a nuestra lista de componentes a traves de componenteDAO
  4. List<ComponenteForm> componenteLista para obtener nuestra lista de componentes cuando queramos consultarlo en el jsp mostrarComponentes.jsp.
  5. Definimos anotaciones y vamos a indicar que el método (agregarComponentes) que vamos a definir en el siguiente punto se trata de un una acción (@Action) que la podremos invocar desde un jsp u otra acción a partir de su alias (agregarComponentesAccion) y los posibles resultados de esta acción serán (SUCCESS) que me envía a la página mostrarComponentes.jsp, (ERROR) que me envía a la página agregarComponentes.jsp. 
  6. Definimos el método agregarComponentes que será invocado desde el Filter Dispatcher donde validaremos que los datos obtenidos del formulario ComponenteForm componenteForm son correctos.En caso de que los datos estén mal ingresados devolvere el mensaje addActionError respectivo, addActionMessage para indicar el usuario logueado y retornare el result como ERROR. Caso contrario guardaré el componente en mi lista estática a través de componenteDAO.addComponente(componenteForm); una vez guardado obtendré la lista completa con  componenteLista=componenteDAO.getComponente(); y retornaré el result como SUCCESS. El Filter Dispatcher a partir de este resultado me enviará a la pagina respectiva.
  7. Definimos anotaciones y vamos a indicar que el método (volverComponente) que vamos a definir en el siguiente punto se trata de un una acción (@Action) que la podremos invocar desde un jsp u otra acción a partir de su alias (volverComponenteAccion) y los posibles resultados de esta acción en este caso solo sera un (SUCCESS) que me envía a la página agregarComponentes.jsp.
  8. Definimos el método volverComponente que será invocado desde el Filter Dispatcher donde simplemente recuperamos los datos del usuario obteniendo primero que todo el contexto ActionContext.getContext() y recuperando los datos de la sesion contexto.getSession() y lo añadimos al mensaje a mostrar en el jsp de agregar componente addActionMessage. Hay que percatarse de que en este caso siempre el resultado será SUCCESS por que no hay otra opción ya que en esta página no se hace nada, solo se visualiza.
Ahora modificamos los jsp:

/ProyectoStruts2AnotacionesTutorial/WebContent/jsp/agregarComponentes.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@taglib uri="/struts-tags" prefix="s"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Agregar Componentes</title>
</head>
<body>
<s:property value="usuarioForm.nombre"/>
<s:if test="hasActionMessages()">
   <div class="welcome">
      <s:actionmessage />
   </div>
</s:if>
<s:if test="hasActionErrors()">
   <div class="errors">
      <s:actionerror/>
   </div>
</s:if>
</body>
<h4>Agregar Componente</h4>
<s:form id="agregar" method="post" action="agregarComponentesAccion">
 <s:textfield  name="componenteForm.nombre" label="Nombre"/>
 <s:textfield  name="componenteForm.version" label="Version"/>
 <s:textfield  name="componenteForm.tipo" label="Tipo"/>
 <s:textfield  name="componenteForm.extension" label="Extension"/>
 <!--<s:hidden name="usuarioForm"/>-->
 <s:submit id="submit" value="Registrar" />
</s:form>
</html>

  1. En esta página mostraremos la bienvenida al usuario donde al hacer hasActionMessage preguntamos si existe algun mensaje de exito recibido y si es así el caso mostramos el mensaje actionmessage.
  2. Verificamos si existe algún mensaje de error hasActionErrors y si se diera el caso mostramos el caso respectivo de error.
  3. Finalmente agregamos un form para que puedas llenarse los datos necesarios del componente a registrar (componenteForm) y al hacer submit vaya al action respectivo agregarComponentesAccion que lo recibirá el Filter Dispatcher.
/ProyectoStruts2AnotacionesTutorial/WebContent/jsp/mostrarComponentes.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@taglib uri="/struts-tags" prefix="s"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<s:hidden name="usuarioForm"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Lista de Componentes</title>
</head>
<body>
<center>
<br><br><br><br><br><br>
<div style="color: teal;font-size: 30px">Lista de Componentes 2</div>
<br><br>
<table border="1" bgcolor="black" width="600px">
    <tr style="background-color: teal;color: white;text-align: center;" height="40px">
        <th><s:text name="Nombre"/></th>
        <th><s:text name="Version"/></th>
        <th><s:text name="Tipo"/></th>
        <th><s:text name="Extensión"/></th>
    </tr>
    <s:iterator value="componenteLista" status="status">
        <tr style="background-color:white;color: black;text-align: center;" height="30px" >
            <td class="nowrap"><s:property value="nombre"/></td>
            <td class="nowrap"><s:property value="version"/></td>
            <td class="nowrap"><s:property value="tipo"/></td>
            <td class="nowrap"><s:property value="extension"/></td>
        </tr>    
  </s:iterator>
</table>
<br>
<a href="volverComponenteAccion" >Agrega un nuevo componente</a>
</center>
</body>
</html>


  1. Nos recorremos la lista componenteLista y pintamos los datos respectivos
  2. Creamos una referencia para poder volver al Action volverComponenteAccion.
Recordar que para este caso de struts2 con anotaciones no necesitamos crear struts.xml.
Si has compilado todo bien y no hay problemas de ejecución te deberían salir las siguientes páginas después del Login y después de haber agregado varios componentes.



El código del proyecto os lo podéis bajar del siguiente link

ProyectoStruts2AnotacionesTutorial