16 mayo, 2015

Métodos por defecto en Interfaces de Java 8

En Java 8 se ha introducido un nuevo cambio al uso de interfaces, desde esta versión es posible implementar métodos por defecto en una interface.


public interface Herramienta {
 default public void ajustar(){
  System.out.println("Ajustando herramienta desde interface");
 } 
}


public class HerramientaImpl implements Herramienta {
 public void limpiar(){
  System.out.println("Limpiando herramienta");
 }
}


public class TestHerramienta {
 public static void main(String[] args) {
  HerramientaImpl herramientaImpl= new HerramientaImpl();
  herramientaImpl.ajustar();
 }
}
Un problema de ambiguedad se podría producir cuando una clase implementa dos o mas interfaces que tienen metodos por defecto con el mismo nombre:
public interface HerramientaElectrica{
 default public void ajustar(){
  System.out.println("Ajustando herramienta desde HerramientaElectrica ");
 }
}

public interface HerramientaManual {
 default public void ajustar(){
  System.out.println("Ajustando herramienta desde HerramientaManual ");
 }
}

public class HerramientaImpl implements HerramientaElectrica,HerramientaManual {
 
}

La solución al problema se encuentra en definir una implementación al método por defecto:


public class HerramientaImpl implements HerramientaElectrica,HerramientaManual {
 @Override
 public void ajustar() {
 }
}
Para invocar una implementación del método por defecto lo hacemos sobreescribiendo en nuestra clase
public class HerramientaImpl implements HerramientaElectrica,HerramientaManual {
 @Override
 public void ajustar() {
  HerramientaElectrica.super.ajustar();
 }
}

31 julio, 2014

Compresión de archivos en linux

Usando la linea de comandos podemos comprimir y descomprimir:
Archivos .tar.gz:
Comprimir: tar -czvf empaquetado.tar.gz /carpeta/a/empaquetar/
Descomprimir: tar -xzvf archivo.tar.gz
Archivos .tar:
Empaquetar: tar -cvf paquete.tar /dir/a/comprimir/
Desempaquetar: tar -xvf paquete.tar
Archivos .gz:
Comprimir: gzip -9 archivo.java
Descomprimir: gzip -d archivo.java.gz
Archivos .zip:
Comprimir: zip archivo.zip carpeta
Descomprimir: unzip archivo.zip

16 julio, 2014

Alfresco JavaScript API

Una API (Application Programming Interface) es una interface implementada y ofrecida por un programa de software que habilita a otras aplicaciones para interactuar con esta, o habilitar a los desarrolladores para escribir otras aplicaciones sobre esta. Una API puede ser expuesta en muchas formas diferentes, tales como clases de modelo interno e implementación-uso con el cual tu puedes escribir tu programa, o como diferentes servicios, por ejemplo, servicios web (web services). Como un desarrollador de soluciones de un Enterprise framework, tu necesitas ser competente sobre las APIs ofrecidas y expuestas por el framework.

Alfresco, como cualquier otro framework, expone un numero de APIs incluyendo Alfresco SDK (software development kit) un conjunto de herramientas de desarrollo que permiten la creacion de una aplicacion para un paquete de software exacto o framework y JavaScript API.

La JavaScript API es un unico modelo para escribir programas y servicios usando JavaScript. La API habilita a desarrolladores para escribir scripts que pueden acceder, modificar, o crear varios objetos del repositorio de Alfresco tales como usuarios, nodos, grupos, tags, categorias, etc.

JavaScript APIs disponibles

Alfresco JavaScript API expone todos los objetos importantes del repositorio como objetos JavaScript que pueden ser usados en un archivo de Script. La API sigue el modelo de programacion orientada a objetos para los bien conocidos conceptos de Alfresco como Nodos, Propiedades, Asociaciones, y Aspectos.

La JavaScript API es capaz de realizar varias funciones esenciales para el desarrollador del script, tales como:

  • Create Node, Update Node: Puedes crear, actualizar nodos o actualizar archivos usando estos.
  • Check In, Check Out: Puedes programaticamente revisar y escribir contenido.
  • Access Rights Management Permissioning: Puedes manejar los aspectos de seguridad del contenido.
  • Transformation: Puedes transformar tu contenido usando esto. Por ejemplo puedes generar una version PDF de tu documento MS-Office
  • Tagging: La Tagging API te ayudara a etiquetar tus contenidos.
  • Classifying: Puedes categorizar o clasificar tu contenido usando esto.
  • People: Usando estas APIs, puedes manipular todas las operaciones relacionadas con usuarios y grupos en tu script; tales como crear un nuevo usuario, cambiar el password de un usuario, etc.
  • Searching: Uno de los mas importantes y poderosas APIs expuestas. Puedes buscar tu contenido usando estas APIs. Puedes realizar busquedas basadas en Lucene o XPath usando estas APIs
  • Workflow: Puedes manejar las tareas y flujos de trabajo en tu sistema usando estas APIs y servicios.
  • Thumbnail: Expone APIs para manejar las operaciones de thumbnail varios items de contenido.
  • Node operations: Puedes usar estas API para realizar varias funciones relacionadas con nodos tales como manejar propiedades, manejar aspectos, copiar, borrar, mover, etc.
Asi, como vemos, bastante mas cosas pueden realizarse en un archivo JavaScript usando estas APIs.

El modelo de JavaScript API

Alfresco provee un numero de objetos en la JavaScript API - estos son mas usualmente llamados Root Scope Objects. Estos objetos son el punto de entrada en el repositorio. Cada uno de los objetos de nivel de raiz referencia a una entidad particular o punto funcional en el repositorio. Por ejemplo, userhome referencia al nodo del espacio home del usuario actual. Cada uno de estos objetos presenta un numero de propiedades y funcionalidades, asi habilitando al escritor de script para implementar muchos requerimientos diferentes. Por ejemplo, la sentencia userhome.name retornará el nombre de la carpeta root del usuario actual.

Algunos objetos de raiz importantes y mas frecuentemente usados son:
  • Companyhome: Retorna el objeto de nodo de company home
  • Userhome: Retorna el nodo de carpeta home del usuario actual
  • Person: Representa el objeto de persona del usuario actual
  • Space: El objeto de espacio actual
  • Document: Retorna el documento seleccionado actualmente
  • Search: Ofrece APIs totalmente funcionales para busquedas
  • People: Encapsula todas las funcionalidades relacionadas a usuarios, grupos, roles, permisos, etc.
  • Sites: Expone las funcionalidades de sevicio de sitio
  • Actions: Provee metodos de invocacion para registrar acciones
  • Workflow: Manipula todas las funcionalidades relacionadas con implementacion de flujos de trabajo con el repositorio
Entre estos objetos, companyhome, userhome, person, space, y document, representan objetos de nodo de Alfresco y permiten acceder a las propiedades y aspectos del objeto de nodo correspondiente. Cada uno de los objetos de nodo provee un numero de APIs las cuales son denominadas ScriptNode API.

Las otras - search, people, sites, workflow, y actions- exponen muchos metodos que podrian ayudar a implementar requerimientos especificos de negocio. Por ejemplo, si tu quieres escribir un script que busque algunos documentos y contenidos, podrias usar la API search. Si quieres crear un nuevo usuario - la API people, te ayudará-

12 julio, 2014

Template Models en FreeMarker y Alfresco

Alfresco ofrece un modelo por defecto que expone un numero de objetos de raiz (root objects) que estan disponibles en un archivo de template. Este trabaja como los objetos de raiz disponibles en archivos JavaScript en Alfresco.

Puedes usar estos objetos de nivel de raiz en tus templates de FreeMarker en Alfresco e implementar varias vistas o archivos de salida.

Algunos de estos objetos de nivel de raiz son:
  • companyhome: El nodo de plantilla de Company Home
  • userhome: El nodo de plantilla del espacio home del usuario actual
  • person: El nodo de plantilla del usuario actual
  • document: El nodo de plantilla del documento actual sobre el cual el template está corriendo
  • space: El nodo de plantilla del espacio actual sobre el cual el template está corriendo
  • session: Provee un ticket de la sesión actual como el valor de session.ticket
  • url: Renderiza el context path actual del servidor web de Alfresco como url.context
  • workflow: Ofrece varias funcionalidades relacionadas con los flujos de trabajo
Estos objetos vienen con todas las propiedades que puedes usar en los archivos de template.

Cada uno de los nodos de plantilla brindan acceso a los conceptos comunes de Alfresco, tales como propiedades, asociaciones, y aspectos - estos son conocidos como Template API (similar a la JavaScript API).
  • properties: Provee el arreglo de propiedades del nodo; por ejemplo, document.properties.name
  • children: Brinda un arreglo de nodos hijos del nodo del espacio actual
    • url, downloadUrl,displayPath, qnamePath
    • isContainer, isDocument, isCategory, isLocked
    • mimetype, size, type, typeShort
    • permissions, inheritsPermissions, hasPermission
    • childByNamePath, childByXPath
    • versionHistory
El Template API ofrece una API de versiones que incluye propiedades como:
  • id, nodeRef, name
  • createdDate, creator, versionLabel, description, url
  • assignedTasks, pooledTasks, completedTasks
  • getTaskById

OJO: Se observan las similaridades entre los objetos de las API expuestas en JavaScript API y Template API, pero es importante notar que estas dos son diferentes. Si una sintaxis o propiedad trabaja bien en una de estas APIs, esto no garantiza que funcionará de la misma manera en otra la otra.

Antes de comenzar a escribir tus propias plantillas con FreeMarker, necesitas entender la sintaxis de FreeMarker. El manual de FreeMarker tiene documentación bien organizada para ayudar a entender esto. Por favor dale un vistazo http://freemarker.org/docs/

FreeMarker ofrece un rico conjunto de funciones incorporadas que puedes utilizar en tus plantillas - para ver la lista de funciones integradas de FreeMarker, consulta en http://freemarker.org/docs/ref_builtins.html

Es tambien importante familiarizarnos con algunos directivas estandares de programación - para ver la lista de directivas disponibles de FreeMarker, por favor mira http://freemarker.org/docs/ref_directives.html


24 junio, 2014

Como preparar el Sprint Backlog

El Sprint Backlog una lista de actividades que se deben realizar durante un Sprint, para completar las características seleccionadas deseables del producto, estas actividades se obtienen desglosando los items del Product Backlog en actividades o tareas.

Así mientras el Product Backlog se enfoca en el "QUÉ", el Sprint Backlog se enfoca en el "CÓMO".

Los miembros del Equipo deben analizar las historias de usuario en cuestión, identificando y previendo las actividades necesarias a realizar para completar las historias o para que se transformen en una característica funcional.

Una historia de usuario en el Product Backlog:
Como Supervisor puedo seleccionar un archivo desde el escritorio para adjuntar a una solicitud comercial.
Varias actividades en el Sprint Backlog:
  • Diseñar y Codificar la interfaz gráfica de usuario
  • Codificar Método para Adjuntar Archivo a la solicitud
  • Integrar interfaz gráfica a la aplicación de Solicitudes comerciales

Un ejemplo de la relación entre Product Backlog y Sprint Backlog


Product Backlog
(QUÉ)
Sprint Backlog
(CÓMO)
  • Historia 1
  • Actividad 1
  • Actividad 2
  • Actividad 3
  • Historia 2
  • Actividad 4
  • Actividad 5
  • Actividad 6
  • Actividad 7
  • Actividad 8
  • Historia 3
  • Actividad 7
  • Actividad 8

28 mayo, 2014

Como escribir historias de usuario

Qué son las historias de usuario

Las historias de usuario son una representación simple y breve de las funcionalidades o características deseadas en nuestro sistema o producto. Representan los requisitos del sistema como los vería un usuario del sistema y normalmente se escriben en tarjetas de papel tipo kardex como si los hubiera escrito el mismo usuario (aunque no es obligación escribirlas en papel y para algunos equipos de trabajo será mas conveniente usar alguna aplicación que las gestione)
Algunos ejemplos de historias de usuario pueden ser:

"Como Administrador puedo asignar roles a los usuarios para controlar el acceso a las aplicaciones"

"Como Supervisor quiero seleccionar un archivo desde el escritorio para adjuntar a una solicitud"

"Como vendedor puedo iniciar un pedido de ventas"


Cómo escribir historias

Con el fin de obtener historias bien redactadas y que sean eficaces, las historias de usuario deben ser expresadas de forma muy breve, que no superen las tres lineas de texto, y ademas deben seguir una estructura definida:

"Como <rol o usuario> puedo/quiero <hacer algo> para/por qué <algo>"

Como se observa arriba, esta estructura se forma de tres partes:
  1. Como <rol o usuario>: Identifica al usuario, tipo de usuario o rol que hace uso de la funcionalidad o característica.
  2. Puedo/Quiero <hacer algo>: Describe breve mente la funcionalidad o característica como lo ve el usuario.
  3. Para/Por qué <algo>: Es opcional para algunas historias y describe el motivo de hacer uso de la funcionalidad o característica.

Obtener historias desde casos de uso

Idealmente las historias de usuario se pueden obtener desde los casos de uso, donde cada ovalo que representa un caso se profundizará en una historia de usuario.
Por ejemplo en un diagrama donde existen los casos "asignar roles a los usuarios", "seleccionar un archivo desde el escritorio", "iniciar un pedido de ventas" y se relacionan con actores Administrador, Supervisor o Vendedor, podemos extraer rápidamente las historias.


26 mayo, 2014

Introducción a Scrum

Que es Scrum?

Scrum es un marco de referencia o marco de trabajo para manejar procesos, y se puede aplicar en muchas actividades que van mas allá del desarrollo de software
En nuestro caso, enfocados en el desarrollo de software, podemos definir Scrum como una forma ágil de manejar proyectos de software.

Desarrollo Scrum: En que consiste?

  • Progreso del proyecto mediante una serie de Sprints
  • Reuniones de planeacion (Planning meetings)
  • Scrum diario (Daily Scrum)
  • Reuniones diarias (Daily Stand Up Meetings)
  • Revision del Sprint (Sprint Reviews)
Scrum consiste en hacer progresar el proyecto mediante una serie de Iteraciones de desarrollo llamadas Sprints, los cuales pueden tener una duración de entre 2 a 4 semanas, dando preferencia a los periodos mas cortos de tiempo.

Al comienzo de cada Sprint, se realizan reuniones de planeación llamadas Planning Meetings, en las cuales se seleccionan los objetivos de mayor prioridad al momento de comenzar el nuevo Sprint y se dividen en tareas mas pequeñas que ayudan a completar cada objetivo. Al final de cada Sprint se debe tener un producto o sistema en un estado potencialmente entregable.

Cada día en el Sprint es el Scrum Diario, una pequeña iteración de desarrollo llamada Daily Scrum y al comienzo de cada una de estas iteraciones diarias se realiza una reunión breve, llamada Daily Stand Up Meeting, la cual se debe realizar de preferencia todos los días a la misma hora, estando los asistentes de pie y con una duración máxima de 15 minutos (para favorecer la brevedad y comunicación temprana).

En la reunión diaria pueden participar Desarrolladores, Scrum Master, Product Owner y algún invitado especial importante para el progreso del proyecto, pero solo los participantes comprometidos con el desarrollo pueden hablar. En esta reunión los comprometidos deben responder 3 preguntas:
  1. ¿Que has hecho desde ayer?
  2. ¿Tienes algún problema que te impida continuar adelante?
  3. ¿Que piensas hacer hoy?
Al finalizar el Sprint de 2 o 4 semanas, el equipo de trabajo se reúne para hacer una revisión retrospectiva donde se evalúan los avances y se piensa en que se puede mejorar para la siguiente iteración.

Proceso Scrum: Artefactos principales

El proceso Scrum involucra un conjunto de artefactos principales:
  1. El producto mismo
  2. Product Backlog
  3. Sprint Backlog
  4. Sprint Burn Down Chart
  5. Release Burn Down Chart
El producto mismo obviamente es la razón de ser del proceso, es un artefacto y es por supuesto el más importante. El resultado de cada iteración es un incremento de este producto.

El segundo artefacto es el Product Backlog, que es una lista de funcionalidades o características deseables del producto. En palabras simples es la lista de todas las historias de usuarios que forman el todo del producto deseado.

El Sprint Backlog es una lista de todas las tareas que se deben realizar para completar las funcionalidades o historias de usuario seleccionadas para cada Sprint o iteración.

Para medir el progreso del Proceso Scrum existen dos artefactos, el Sprint Burn Down Chart y el Release Burn Down Chart, estos artefactos son básicamente unos gráficos que se van actualizando cada dia del proceso con la estimación de horas restantes de desarrollo, cada miembro del equipo puede estimar y re-estimar el tiempo para la tarea que realiza actualmente, así a medida que se progresa en el desarrollo de una tarea, esta estimación es cada vez menor, lo que va produciendo un gráfico con valores descendientes en el tiempo.

Proyecto Ágil Scrum: Roles principales

En Scrum existen tres roles principales
  1. Scrum Master
  2. Product Owner
  3. Scrum Team
El Scrum Master es el coach del Scrum Team, es el arbitro que vela por que se cumplan las reglas de Scrum y es quien ayuda los practicantes de Scrum a obtener su máximo nivel de rendimiento. 
A diferencia de otros métodos de gestión de proyecto, en Scrum no existe el Project Manager o Jefe de Proyecto y el Scrum Master no provee dirección diaria al equipo ni asigna tareas de forma individual. El Scrum Master protege al equipo de las distracciones externas y le ayuda a mantenerse enfocado en su objetivo y ser mejor cada vez.

El Product Owner trabaja para dirigir al Scrum Team hacia la meta correcta, creando una visión convincente del producto y transmitiendola al equipo mediante el Product Backlog. El Product Owner es el responsable de priorizar el backlog durante el desarrollo Scrum, a medida que se aprende del sistema que se está construyendo.

El ultimo rol es el Scrum Team, es el equipo de desarrollo, el automóvil que está listo para partir en la dirección que sea puesto, el Product Owner es el conductor del automóvil que se asegura de siempre ir en la dirección correcta, y el Scrum Master es el mecánico que mantiene el auto en buen estado para su mejor rendimiento.

En Scrum, a diferencia de otros métodos de gestión de proyectos, el Team es visto como un todo, un grupo sin jerarquías como Jefe de proyecto, Desarrollador Senior o Junior, etc., mas bien pone énfasis sobre las personas y sus habilidades, talentos y aptitudes, siendo todos los actores comprometidos con el resultado.

10 mayo, 2014

Principios del Manifiesto Agil

Estos son los principios del manifiesto agil:

Nuestra mayor prioridad es satisfacer al cliente mediante la entrega temprana y continua de software con valor.

Aceptamos que los requisitos cambien, incluso en etapas tardías del desarrollo. Los procesos Ágiles aprovechan el cambio para proporcionar ventaja competitiva al cliente.

Entregamos software funcional frecuentemente, entre dos semanas y dos meses, con preferencia al periodo de tiempo más corto posible.

Los responsables de negocio y los desarrolladores trabajamos juntos de forma cotidiana durante todo el proyecto.

Los proyectos se desarrollan en torno a individuos motivados. Hay que darles el entorno y el apoyo que necesitan, y confiarles la ejecución del trabajo.

El método más eficiente y efectivo de comunicar información al equipo de desarrollo y entre sus miembros es la conversación cara a cara.

El software funcionando es la medida principal de progreso.

Los procesos Ágiles promueven el desarrollo sostenible. Los promotores, desarrolladores y usuarios debemos ser capaces de mantener un ritmo constante de forma indefinida.

La atención continua a la excelencia técnica y al buen diseño mejora la Agilidad.

La simplicidad, o el arte de maximizar la cantidad de trabajo no realizado, es esencial.

Las mejores arquitecturas, requisitos y diseños emergen de equipos auto-organizados.

A intervalos regulares el equipo reflexiona sobre cómo ser más efectivo para a continuación ajustar y perfeccionar su comportamiento en consecuencia.

Extraido de la funete original:

28 abril, 2014

Git: Comandos frecuentes

En esta oportunidad he querido documentar esta pequeña lista de comandos mas frecuentes de Git. Como se ve mas abajo son simples combinaciones que de seguro con un poco de tiempo terminan por memorizarse y ya su uso se hace casi por inercia, de cualquier forma aquí va un torpedo que nunca esta demás...

Inicializando el repositorio (es el directorio /.git en nuestro proyecto)

$ git init

Chequeando el estatus

$ git status

Añadiendo cambios (al área de staging)

$ git add <archivo>

Guardando los cambios

$ git commit -m "algún mensaje o historia"

Viendo el historial

$ git log

Añadiendo el repositorio remoto

$ git remote add origin <url_del_git>
ejemplo...
$ git remote add origin http://github.com/miproyecto.git

Empujando al repositorio remoto

$ git push -u origin master

Jalando del repositorio remoto

$ git pull origin master

Viendo las diferencias desde el ultimo commit

$ git diff HEAD

Viendo las diferencias en staged (staged = archivos listos para el commit)

primero se agregan los archivos...
$ git add <archivo>
luego viendo las diferencias...
$ git diff --staged

Reseteando al stage (reset)

$ git reset <archivos>

Des-haciendo

$ git checkout --<archivo>
ejemplo...
$ git checkout --persona.java

Ramificando (Branching out)

$ git branch <nombre_rama>
ejemplo...
$ git branch autenticacion-de-usuarios

Cambiando de rama

$ git checkout <nombre_rama>
ejemplo...
$ git checkout mantencion-personas

Borrando archivos

$ git rm '*.txt'
luego hacer commit...
$ git commit -m "borrando todos los txt"
y el checkout...
$ git checkout master

Mezclando las ramas

$ git merge <nombre_rama>

Borrando una rama

$ git branch -d <nombre_rama>

03 noviembre, 2013

Spring Web Service Cliente usando JAX-WS y JAXB

En un post anterior vimos como crear servicios web con Spring-WS, en esta ocación vamos a crear un cliente que consume ese servicio, usando Spring, JAX-WS y JAXB.
Spring-WS provee una API para Web service del lado del cliente que nos da acceso conducido por XML y tambien nos permite en la capa de servicios tratar directamente con objetos Java mediante el uso de marshallers y unmarshallers.
El paquete org.springframework.ws.client.core provee las funcionalidades del nucleo para usar la API mencionada. Esta contiene las clases template que simplifican el uso de Web services, para ver mas información de webServiceTemplate puedes leer la documentacion de Spring

1. Creando la estructura de la aplicación

Al final nuestra aplicación tendrá la siguiente estructura, donde las clases contenidas en el paquete com.codelious.clientejaxb.generados serán generadas automaticamente por la herramienta wsimport.

2. Incluyendo las dependencias

El archivo pom.xml de este proyecto incluye las siguientes dependencias.
<dependencies>
 <!-- Spring -->
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>3.1.1.RELEASE</version>
  <exclusions>
   <!-- Exclude Commons Logging in favor of SLF4j -->
   <exclusion>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    </exclusion>
  </exclusions>
 </dependency>
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>3.1.1.RELEASE</version>
 </dependency>
   
 <!-- AspectJ -->
 <dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.6.10</version>
 </dependency> 
 
 <!-- Logging -->
 <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.6.6</version>
 </dependency>
 <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>jcl-over-slf4j</artifactId>
  <version>1.6.6</version>
 </dependency>
 <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.6.6</version>
 </dependency>
 <dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.15</version>
  <exclusions>
   <exclusion>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
   </exclusion>
   <exclusion>
    <groupId>javax.jms</groupId>
    <artifactId>jms</artifactId>
   </exclusion>
   <exclusion>
    <groupId>com.sun.jdmk</groupId>
    <artifactId>jmxtools</artifactId>
   </exclusion>
   <exclusion>
    <groupId>com.sun.jmx</groupId>
    <artifactId>jmxri</artifactId>
   </exclusion>
  </exclusions>
  <scope>runtime</scope>
 </dependency>

 <!-- @Inject -->
 <dependency>
  <groupId>javax.inject</groupId>
  <artifactId>javax.inject</artifactId>
  <version>1</version>
 </dependency>
   
 <!-- Servlet -->
 <dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
  <scope>provided</scope>
 </dependency>
 <dependency>
  <groupId>javax.servlet.jsp</groupId>
  <artifactId>jsp-api</artifactId>
  <version>2.1</version>
  <scope>provided</scope>
 </dependency>
 <dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
 </dependency>

 <!-- Test -->
 <dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.7</version>
  <scope>test</scope>
 </dependency>
 <dependency>
  <groupId>org.springframework.ws</groupId>
  <artifactId>spring-ws-core</artifactId>
  <version>2.1.4.RELEASE</version>
 </dependency>
 <dependency>
  <groupId>jdom</groupId>
  <artifactId>jdom</artifactId>
  <version>1.1</version>
 </dependency>
 <dependency>
  <groupId>jaxen</groupId>
  <artifactId>jaxen</artifactId>
  <version>1.1.4</version>
 </dependency>
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>3.1.1.RELEASE</version>
 </dependency>
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>3.1.1.RELEASE</version>
 </dependency>
  <dependency>
  <groupId>commons-httpclient</groupId>
  <artifactId>commons-httpclient</artifactId>
  <version>3.1</version>
  <type>jar</type>
  <scope>compile</scope>
    </dependency>
</dependencies>

3. Generando los artefactos JAX-WS

Para generar los artefactos JAX-WS automaticamente debemos conocer la url del WSDL que en nuestro caso es http://localhost:18080/MiWS/services/saludar.wsdl y utilizaremos la herramienta wsimport que debería estar incluida en la instalacion de java, por tanto en una consola de comandos escribimos...

wsimport -d midirectorio -keep http://localhost:18080/MiWS/services/saludar.wsdl

Con lo anterior se generarán automaticamente varios archivos en el directorio indicado, de los cuales debemos copiar solo los .java a nuestro paquete com.codelious.clientejaxb.generados
  • ObjectFactory.java
  • package-info.java
  • Saludar.java
  • SaludarService.java
  • SaludoRequest.java
  • SaludoResponse.java
Una vez copiados los archivos anteriores, debemos asegurarnos de que hagan referencia al paquete correcto de nuestro proyecto, por ejemplo package com.codelious.clientejaxb.generados; dado que por lo general la herramienta wsimport creará como paquete el directorio que le indicamos y este no siempre es el mismo de nuestra aplicación.
Para mas información acerca de wsimpot puedes ver la documentacion oficial de oracle

4. Escribiendo el Controlador

Ahora escribamos la clase SaludoController.java con el metodo saludo() que se encargará de consumir el web service

package com.codelious.clientejaxb.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.ws.client.core.WebServiceTemplate;

import com.codelious.clientejaxb.generados.SaludoRequest;
import com.codelious.clientejaxb.generados.SaludoResponse;

@Controller
public class SaludoController {


 @Autowired
 @Qualifier("webServiceTemplate")
 private WebServiceTemplate webServiceTemplate;
 
 @RequestMapping("/saludo")
 public ModelAndView saludo() {
  
  // crear solicitud al ws
  SaludoRequest solicitud = new SaludoRequest();
  solicitud.setNombre("Mario Espinoza Aguayo");
  
  // obtener la respuesta
  SaludoResponse respuesta = (SaludoResponse) webServiceTemplate.marshalSendAndReceive(solicitud);
     
  // obtiene el saludo
  String mensaje = respuesta.getSaludo();
  
  return new ModelAndView("saludo", "mensaje", mensaje);
 }
}
Como se ve arriba, estamos instanciando un webServiceTemplate, SaludoRequest y SaludoResponse que en conjunto nos ayudan a simplificar las tareas de transformación de xml a objetos java. webServiceTemplate está inyectado por el bean de su mismo nombre desde el archivo spring-ws.xml que veremos luego...

5. Escribiendo la vista Saludo

La vista saludo.jsp simplemente desplegará en el navegador el mensaje devuelto por el controlador...
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!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>Cliente WS</title>
</head>
<body>
 <h1>${mensaje}</h1>
</body>
</html>

6. Escribiendo la página de entrada

La pagina de entrada a la aplicación index.jsp contiene el link que llama al controlador saludo...

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!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>Cliente WS</title>
</head>
<body>
 <h1>Bienvenido al ClienteWS</h1>
 <p>
  Presiona el link para ver el <a href="saludo.html">saludo</a>
 </p>
</body>
</html>

7. Configurando la aplicación

Para configurar la aplicación escribiremos varios archivos xml...

por convención Spring buscará el archivo applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/mvc 
   http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

  <!-- Escanea el classpath para componentes anotados que seran auto-registrados como beans de Spring.
  For ejemplo @Controller y @Service. Asegurate de establecer el base-package correcto --> 
    <context:component-scan
        base-package="com.codelious.clientejaxb.controller" /> 

 <!-- Activa varias anotaciones para ser detectadas en las clases bean -->
 <context:annotation-config />
  
 <!-- Configura el modelo de programacion annotation-driven de Spring MVC Controller.
   Nota que, con Spring 3.0, este tag trabaja en Servlet MVC solamente! -->
 <mvc:annotation-driven />
  
 <!-- Contiene configuraciones relacionadas a Spring WS -->
 <import resource="spring-ws.xml" />
 
</beans>

Nuestro archivo spring-ws.xml contendrá el bean webServiceTemplate que inyectamos anteriormente en nuestro controlador...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
 xmlns:sws="http://www.springframework.org/schema/web-services"
 xmlns:oxm="http://www.springframework.org/schema/oxm"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/web-services
           http://www.springframework.org/schema/web-services/web-services-2.0.xsd
           http://www.springframework.org/schema/oxm
           http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd">

 <!-- * El WebServiceTemplate requiere un messageSender y messageFactory
   * Para facilitar el envio de plain Java objects, el WebServiceTemplate
   requiere un marshaller y unmarshaller.
   * La clase WebServiceTemplate usa una URI como el destinatario del mensaje.
   Mira http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template -->
 <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"
  p:marshaller-ref="jaxbMarshaller" p:unmarshaller-ref="jaxbMarshaller"
  p:defaultUri="http://localhost:18080/MiWS/services"
  p:messageSender-ref="messageSender">
  <constructor-arg ref="messageFactory" />
 </bean>

 <!-- Hay dos implementaciones del WebServiceMessageSender: HttpUrlConnectionMessageSender
  y CommonsHttpMessageSender. el CommonsHttpMessageSender provee funcionalidades avanzadas
  y faciles de usar (tales como authentication, HTTP connection pooling, y asi sucesivamente).
  Esta usa el Jakarta Commons HttpClient. 
  Mira http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template -->
 <bean id="messageSender"
  class="org.springframework.ws.transport.http.CommonsHttpMessageSender" />

 <!-- Hay dos message factories para SOAP: SaajSoapMessageFactory y AxiomSoapMessageFactory.
  Si no se especifica ningun message factory (via la propiedad messageFactory), Spring-WS usara
  el SaajSoapMessageFactory por defecto. 
  Mira http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template -->
 <bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" />

 <!-- Aqui usamos el Jaxb2 marshaller para marshall y unmarshal nuestros objetos Java -->
 <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"
  p:contextPath="com.codelious.clientejaxb.generados" />

</beans>

El archivo spring-servlet.xml como siempre es nuestro dispatcher servlet, es decir que es el encargado de despachar solicitudes a controladores y luce asi...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd">
         
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

Finalmente nuestro archivo web.xml es donde definimos nuestro archivo de entrada a la aplicación, y nuestros dispatcher servlet...
<?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>ClienteWS JAX-WS JAXB</display-name>
 
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>
 
 <servlet>
  <servlet-name>spring</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 </servlet>

 <servlet-mapping>
  <servlet-name>spring</servlet-name>
  <url-pattern>*.html</url-pattern>
 </servlet-mapping>
 
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
</web-app>

8. Probando la aplicación

Ya podemos probar nuestra aplicación en http://localhost:18080/ClienteJAXB/ y ver la página de entrada...
 Al hacer clic al link llamaremos al controlador que consume el web service y devuelve el mensaje...
Ya esta!! si quieres el codigo descargalo en github.. https://github.com/codelious/ClienteJAXB


01 noviembre, 2013

Spring Web Service Contract-First

Existen dos aproximaciones para desarrollar servicios web: Contract-Last y Contract-First, en este post vamos a desarrollar un web service con Spring y por lo tanto usaremos el acercamiento Contract-First que consiste en preparar primero los contratos de datos y de servicios, para luego implementar las clases y todo lo demás...En un post anterior puedes ver como definir un contrato así que puedes darle una mirada si aun no los has visto.
Ok... Aquí vamos a diseñar una aplicación de ejemplo muy simple, nuestro web service nos responderá con un simple saludo estilo "Hola mundo!" donde el nombre que le pasemos en la solicitud será usado para completar el saludo.

Estructura de la aplicación

Como siempre, creamos una aplicación Maven con la siguiente estructura...

Configurando las dependencias

En el archivo pom.xml incluimos las librerias que necesitaremos...
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.codelious.saludows</groupId>
  <artifactId>SaludoWS</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>SaludoWS</name>
  <description>Ejemplo de Servicios Web</description>
  <dependencies>
  <!-- Spring -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>3.1.1.RELEASE</version>
   <exclusions>
    <!-- Exclude Commons Logging in favor of SLF4j -->
    <exclusion>
     <groupId>commons-logging</groupId>
     <artifactId>commons-logging</artifactId>
     </exclusion>
   </exclusions>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>3.1.1.RELEASE</version>
  </dependency>
    
  <!-- AspectJ -->
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>1.6.10</version>
  </dependency> 
  
  <!-- Logging -->
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>1.6.6</version>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>jcl-over-slf4j</artifactId>
   <version>1.6.6</version>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-log4j12</artifactId>
   <version>1.6.6</version>
  </dependency>
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.15</version>
   <exclusions>
    <exclusion>
     <groupId>javax.mail</groupId>
     <artifactId>mail</artifactId>
    </exclusion>
    <exclusion>
     <groupId>javax.jms</groupId>
     <artifactId>jms</artifactId>
    </exclusion>
    <exclusion>
     <groupId>com.sun.jdmk</groupId>
     <artifactId>jmxtools</artifactId>
    </exclusion>
    <exclusion>
     <groupId>com.sun.jmx</groupId>
     <artifactId>jmxri</artifactId>
    </exclusion>
   </exclusions>
   <scope>runtime</scope>
  </dependency>

  <!-- @Inject -->
  <dependency>
   <groupId>javax.inject</groupId>
   <artifactId>javax.inject</artifactId>
   <version>1</version>
  </dependency>
    
  <!-- Servlet -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.servlet.jsp</groupId>
   <artifactId>jsp-api</artifactId>
   <version>2.1</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
  </dependency>
 
  <!-- Test -->
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.7</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework.ws</groupId>
   <artifactId>spring-ws-core</artifactId>
   <version>2.1.4.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>jdom</groupId>
   <artifactId>jdom</artifactId>
   <version>1.1</version>
  </dependency>
  <dependency>
   <groupId>jaxen</groupId>
   <artifactId>jaxen</artifactId>
   <version>1.1.4</version>
  </dependency>
 </dependencies>
</project>

Escribiendo el contrato

Como estamos usando el enfoque Contract-First, lo primero es el contrato (revisa el post definiendo un contrato), para esto simplemente escribimos el archivo saludo-service.xsd que define la estructura que tendrá nuestro wsdl...
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
 elementFormDefault="qualified" attributeFormDefault="qualified"
 targetNamespace="http://localhost:18080/com/codelious/saludows/saludar-service"
 xmlns:tns="http://localhost:18080/com/codelious/saludows/saludar-service">

 <element name="SaludoRequest">
  <complexType>
   <sequence>
    <element type="string" name="nombre" />
   </sequence>
  </complexType>
 </element>

 <element name="SaludoResponse">
  <complexType>
   <sequence>
    <element type="string" name="saludo" />
   </sequence>
  </complexType>
 </element>
 
</schema>

Las Clases del Servicio

Nuestro servicio es simplemente un saludo, por tanto tendremos una interfaz SaludarService.java que tiene un metodo getSaludo()
package com.codelious.saludows.servicio;

public interface SaludarService {
 
    String getSaludo(String nombre);

}

Luego escribimos la clase SaludarServiceImpl.java que implementa la interfaz anterior...
package com.codelious.saludows.servicio;

public class SaludarServiceImpl implements SaludarService {

    public String getSaludo(String nombre) {
  
        String mensaje = "Hola " + nombre + " !!";
        return mensaje;

    }
}

Escribiendo la clase de EndPoint

Existen varias formas de escribir esta clase, en este caso extenderemos de AbstractDomPayloadEndpoint
package com.codelious.saludows.endpoint;

import org.springframework.ws.server.endpoint.AbstractDomPayloadEndpoint;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

import com.codelious.saludows.servicio.SaludarService;

public class SaludarServiceEndPoint extends AbstractDomPayloadEndpoint {

    public static final String NAMESPACE = "http://localhost:18080/com/codelious/saludows/saludar-service";
 
    private SaludarService saludarService;
 
    public void setSaludarService(SaludarService saludarService) {
        this.saludarService = saludarService;
    }
 
    @Override
    protected Element invokeInternal(Element requestElement,
            Document responseDocument) throws Exception {
  
        // recibe un elemento de solicitud y un documento
  
        String solicitudString = buscarStringSolicitud(requestElement);
        String saludoString = invocaServicioRetornaRespuesta(solicitudString);
        Element respuestaXml = preparaRespuestaXml(responseDocument, saludoString);
  
        return respuestaXml;
    }

    private Element preparaRespuestaXml(Document responseDocument,
          String saludoString) {
  
        // prepara los nodos de la respuesta
        Element elementoRespuesta = responseDocument.createElementNS(NAMESPACE, "SaludoResponse");
        Element elementoSaludo = responseDocument.createElementNS(NAMESPACE, "saludo");
        // prepara el texto contenido en la respuesta
        Text textoRespuesta = responseDocument.createTextNode(saludoString);
        elementoRespuesta.appendChild(elementoSaludo);
        elementoSaludo.appendChild(textoRespuesta);
  
        return elementoRespuesta;
    }

    private String invocaServicioRetornaRespuesta(String solicitudString) {
  
        // invoca el servicio pasandole el nombre y retorna el saludo
        String saludoString = saludarService.getSaludo(solicitudString);
  
        return saludoString;
    }

    private String buscarStringSolicitud(Element requestElement) {
  
        // recupera el primer elemento llamado "nombre"
        Element elementoNombre = (Element) requestElement.getElementsByTagNameNS(NAMESPACE, "nombre").item(0);
        // obtiene el texto contenido
        String solicitudString = elementoNombre.getTextContent();
  
        return solicitudString;
    }
 
}

Configurando la aplicación

Nuestro archivo web.xml define el MessageDispatcherServlet, que a diferencia del DispatcherServlet de una aplicación MVC que maneja controladores, este se encargará de manipular nuestros endpoints...
<?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>SaludoWS</display-name>
 
 <servlet>
  <servlet-name>spring-ws</servlet-name>
  <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
  <init-param>
   <param-name>transformWsdlLocations</param-name>
   <param-value>true</param-value>
  </init-param>
 </servlet>

 <servlet-mapping>
  <servlet-name>spring-ws</servlet-name>
  <url-pattern>/*</url-pattern>
 </servlet-mapping>
 
</web-app>

Luego nuestro spring-ws-servlet.xml definirá la configuración de los endpoints...
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans    
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
 
    <bean id="saludarService" class="com.codelious.saludows.servicio.SaludarServiceImpl">
    </bean>

    <bean id="saludarServiceEndpoint"
        class="com.codelious.saludows.endpoint.SaludarServiceEndPoint">
        <property name="saludarService" ref="saludarService" />
    </bean>

    <bean id="payloadMapping"
        class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
        <property name="defaultEndpoint" ref="saludarServiceEndpoint" />
    </bean>

    <bean id="saludarSchema" class="org.springframework.xml.xsd.SimpleXsdSchema">
        <property name="xsd" value="/WEB-INF/saludo-service.xsd" />
    </bean>

    <bean id="saludar"
        class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
        <property name="schema" ref="saludarSchema" />
        <property name="portTypeName" value="saludar" />
        <property name="locationUri"
            value="http://localhost:18080/SaludoWS/services" />
    </bean>

</beans>
Este archivo spring-ws-servlet.xml define varias cosas como la interfaz del servicio, la clase EndPoint, el contrato (xsd) que usará para generar el wsdl y finalmente la ruta del wsdl que usarán los clientes para consumir el web service...
Para ver el WSDL podemos visitar la direccion http://localhost:18080/SaludoWS/services/saludar.wsdl (reemplazando el puerto 18080 por el que usemos) y también podemos probar el funcionamiento usando una herramienta como SoapUI...
That's all Folks! el código está en github... https://github.com/codelious/SaludoWS

26 octubre, 2013

Hola Mundo con Spring MVC

Tipicamente cuando incursionamos con un nuevo framework o lenguaje de programacion queremos rapidamente hacer funcionar algo, y como estoy dedicando una serie de articulos a Spring Framework, no podia faltar uno dedicado al simple y bien ponderado "Hola Mundo"... La idea es mostrar como construir el Skeleton fundamental para que nuestra aplicacion Spring MVC funcione...
Para realizar este ejemplo como la mayoria de los publicados aqui usaré:
  • Eclipse (Juno) como IDE
  • Maven (plugin de eclipse) para incluir facilmente librerias y dependencias
  • Tomcat 7
  • Spring Framework (en este ejemplo la version 3.01)

Configurando el nuevo proyecto

Lo primero es crear un nuevo proyecto, para esto podemos usar clic derecho la ventana de Package Explorer o bien en Archivo->New->Project y seleccionar Maven Project
Luego seleccionado Maven Project le damos Next, para seleccionar el nombre y la ubicacion del proyecto, en esta oportunidad todos los valores quedan por defecto y ademas debemos seleccionar el checkbox "Create a simple project (skip archetype selection)" para saltarnos la selección de arquetipo puesto que lo crearemos nosotros mismos...
Ahora introducimos informacion de configuracion del proyecto como el grupo, artefacto, version y forma de empaquetamiento, en este caso el Group Id es com.codelious.mimvc, el Artifact Id es MiMVC y en Packaging seleccionamos war, la version queda por defecto...
Luego damos clic en Finish y deberiamos tener nuestro proyecto creado con una estructura basica que incluye los directorios src/main/webapp y tambien se ha creado nuestro archivo pom.xml que nos permitira el facil manejo de dependencias con Maven.
Dentro de nuestro directorio webapp debemos crear manualmente algunos directorios y archivos para que se vea finalmente una estructura como la de la imagen abajo...

Incluyendo dependencias Maven

Ahora debemos incluir algunas dependencias y las librerias de Spring Framework en nuestro archivo pom.xml para que Maven las cargue a nuestro proyecto, editemos el contenido del pom.xml para que quede asi:

<project xmlns="http://maven.apache.org/POM/4.0.0" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.codelious.mimvc</groupId>
 <artifactId>MiMVC</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>war</packaging>
 <dependencies>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>3.0.1.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>3.0.1.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>3.0.1.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>commons-logging</groupId>
   <artifactId>commons-logging</artifactId>
   <version>1.1.1</version>
  </dependency>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
  </dependency>
 </dependencies>
</project> 

Configurando nuestra aplicación

Luego de añadir las dependencias, debemos codificar nuestro archivo web.xml que es el descriptor de despliegue, y ahi debemos incluir las referencias a nuestro Dispatcher Servlet que es basicamente el despachador de solicitudes a controladores.

<?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_3_0.xsd"
 id="WebApp_ID" version="3.0">
 
 <display-name>MiMVC</display-name>
 
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>

 <servlet>
  <servlet-name>despachador</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>despachador</servlet-name>
  <url-pattern>*.html</url-pattern>
 </servlet-mapping>

</web-app>
Como se puede notar en el web.xml arriba, tenemos un <servlet> y un <servlet-mapping>, el servlet-mapping trabaja direccionando todos los patrones de url que incluyan extension .html a nuestro dispatcher servlet llamado despachador que es de clase org.springframework.web.servlet.DispatcherServlet, por tanto no es coincidencia que hayamos creado un archivo despachador-servlet.xml, ya que spring buscará un archivo con nombre compuesto por el nombre del servlet añadiendo "-servlet.xml" o sea si en el archivo web.xml estamos declarando el dispatcher servlet con <servlet-name>mascotas</servlet-name> entonces se buscará el archivo mascotas-servlet.xml
También tenemos <welcome-file-list> que permite indicar la pagina de entrada a la aplicacion, la que en este caso sera index.jsp

Ahora codificamos el dispatcher servlet llamado despachador-servlet.xml añadiendo bean viewResolver y un component-scan:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
    <context:component-scan
        base-package="com.codelious.mimvc.controller" />
         
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    
</beans>
El bean context:component-scan resaltado arriba permitirá escanear automáticamente todos los controladores ubicados en el paquete com.codelious.mimvc.controller, tambien es posible declarar  varios beans por separado que invocan directamente a cada controlador.
El bean viewResolver nos permitirá resolver las vistas de nuestra aplicación cuando las invoquemos desde nuestros controladores y en este caso indica la ubicacion de las vistas.

Codificando la pagina de entrada

Como mencionamos en el archivo de configuracion web.xml declaramos una pagina de entrada a la aplicacion, para esto agreguemos el siguiente codigo a index.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!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>MiMVC</title>
</head>
<body>
 <h1>Bienvenido a MiMVC</h1>
 <p>
  Presiona el link para ver el <a href="saludar.html">saludo</a>
 </p>
</body>
</html>

Creando el controlador

Vamos a crear un contralador llamado "Saludo" que recibira nuestra solicitud desde la pagina de entrada index.jsp y luego nos direccionará a la vista de saludo, para esto debemos crear en src/main/java el paquete com.codelious.mimvc.controller donde crearemos la clase SaludoController.java y le agregaremos el siguiente codigo:
package com.codelious.mimvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class SaludoController {

 @RequestMapping("/saludar")
 public ModelAndView saludar(){
  
  String mensaje = "Hola Mundo Maravilloso";
  return new ModelAndView("saludo", "mensaje", mensaje);
  
 }
}
En el codigo hemos creado un metodo saludar() que devuelve ModelAndView y es el metodo que procesará nuestra solicitud y nos direccionará a la vista deseada, luego hemos puesto un par de anotaciones de Spring, la primera es @Controller e indica que la clase es un controlador, la segunda es @RequestMapping("/saludar") que permite mapear la solicitud desde la url. El metodo saludar() nos retornará un objeto ModelAndView al cual le indicamos la vista que en nuestro caso sera saludo.jsp, luego incluimos un mensaje que estará disponible en nuestra vista para accederlo mediante tags jstl.

Creando la vista

Para nuestra vista crearemos en WEB-INF/jsp el archivo saludo.jsp en el cual agregaremos nuestro codigo:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!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>MiMVC</title>
</head>
<body>
 <h1>${mensaje}</h1>
</body>
</html>

Probando la aplicacion

Hecho todo lo anterior deberiamos tener una estructura similar a la siguiente:
y entonces ya podemos probar nuestra aplicación en un navegador web, para eso podemos dar clic derecho sobre la raiz de nuestro proyecto y seleccionar Run As->Run on Server y verlo en la direccion http://localhost:18080/MiMVC/ (reemplazar el puerto 18080 por el que uses)
Si damos clic al link saludo estaremos haciendo la llamada al controlador y este nos devolvera la pagina saludo.jsp
Y esto sería todo, ya tenemos nuestro hola mundo MVC en Spring Framework. Si quieres descargar el proyecto completo puedes hacerlo en github: https://github.com/codelious/MiMVC

20 octubre, 2013

Spring Framework y Vistas XSLT

XSLT es un lenguaje de transformación para XML y es popular como una tecnología de vistas con aplicaciones web. XSLT puede ser una buena elección como una tecnología de vista si tu aplicación naturalmente negocia con XML, o si tu modelo puede ser fácilmente convertido a XML. Este post muestra como producir un documento XML como modelo de datos y tenerlo transformado con XSLT en una aplicación Spring Web MVC.

Este ejemplo es una aplicación trivial de Spring que crea una lista de palabras en el Controlador y las agrega al mapa de modelo. El mapa es retornado junto con el nombre de vista de nuestra vista XSLT. La vista XSLT pondrá la lista de palabras en un documento simple XML listo para la transformación.

La estructura de la aplicacion

Nuestra aplicacion es una aplicacion Simple de Maven y deberá tener una estructura similar a esto:


Usando Maven

Como yo estoy usando Maven para el manejo de las dependencias de la aplicacion, mi archivo pom.xml se ve asi:
<project xmlns="http://maven.apache.org/POM/4.0.0" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                    http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.codelious.mixslt</groupId>
  <artifactId>MiXSLT</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <dependencies>
   <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>3.0.1.RELEASE</version>
   </dependency>
   <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>3.0.1.RELEASE</version>
   </dependency>
   <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>3.0.1.RELEASE</version>
   </dependency>
   <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>3.0.1.RELEASE</version>
   </dependency>
   <dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
   </dependency>
   <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.1</version>
   </dependency>
   <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
   </dependency>
  </dependencies>
</project>

Los archivos de configuracion y dispatcher sevlet

El archivo web.xml tiene el siguiente aspecto:
<?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_3_0.xsd"
 id="WebApp_ID" version="3.0">
 
 <display-name>MiXSLT</display-name>
 
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>

 <servlet>
  <servlet-name>spring</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>spring</servlet-name>
  <url-pattern>*.htm</url-pattern>
 </servlet-mapping>

</web-app>
y El archivo spring-servlet.xml que es nuestro despachador de solicitudes sigue asi:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.0.xsd">

 <bean id="viewResolver"
  class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
  <property name="order">
   <value>1</value>
  </property>
  <property name="basename" value="views" />
 </bean>
 
 <bean id="xsltViewResolver"
  class="org.springframework.web.servlet.view.xslt.XsltViewResolver">
  <property name="order">
   <value>2</value>
  </property>
  <property name="viewClass"
   value="org.springframework.web.servlet.view.xslt.XsltView" />
  <property name="sourceKey" value="obj" />
  <property name="suffix" value=".xsl" />
  <property name="prefix" value="/WEB-INF/xsl/" />
 </bean>

 <bean id="simpleUrlMapping"
  class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="mappings">
   <value>
    /home.htm=homeController
   </value>
  </property>
 </bean>

 <bean id="homeController" class="com.codelious.mixslt.controller.HomeController" /> 
</beans>

Definicion de Beans

Como se ve arriba, la configuracion es estandar para una aplicacion simple de Spring. El archivo de configuracion de dispatcher servlet contiene una referencia a un ViewResolver, URL mappings y un Bean de controlador que encapsula nuestra logica de generacion de palabras:
<bean id="homeController" class="com.codelious.mixslt.controller.HomeController" />

Codigo del Controlador MVC

La logica del controlador es encapsulada en una subclase de AbstractController, con el metodo handler que se define como sigue...
package com.codelious.mixslt.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

public class HomeController extends AbstractController {

    protected ModelAndView handleRequestInternal(HttpServletRequest request,
        HttpServletResponse response) throws Exception {
  
        Map mapa = new HashMap();
        List listaPalabras = new ArrayList();
  
        listaPalabras.add("Hola");
        listaPalabras.add("Universo");
  
        mapa.put("listaPalabras", listaPalabras);
  
        return new ModelAndView("home", mapa);
    }

}
Hasta aqui no tenemos nada especifico de XSLT. Los datos del modelo han sido creados en la misma forma en que hariamos otra aplicacion Spring MVC. Dependiendo de la configuracion de la aplicacion, esta lista de palabras podria ser renderizada por JSP/JSTL teniendolas agregadas como atributos en la solicitud (request attributes), o podrian ser manipuladas por Velocity agregando el objeto al VelocityContext. Para tener XSLT renderizalos, y por supuesto tienen que ser convertidos en un documento XML de alguna manera. Existen paquetes de software que automaticamente 'DOMifican' los objetos, pero con Spring, tienes completa flexibilidad para crear el DOM desde tu modelo en cualquier forma que quieras. Esto evita el juego exesivo con la transformacion de XML, lo cual es peligroso cuando usamos herramientas para manejar procesos de DOMificacion

Convertir los datos del modelo a XML

Para crear un documento DOM desde nuestra lista de palabras o cualquier otro dato del modelo, debemos extender de la clase org.springframework.web.servlet.view.xslt.AbstractXsltView. Haciendo esto, debemos tambien implementar el metodo abstracto createXsltSource(..). El primer parametro pasado a este metodo es nuestro mapa del modelo. Aqui esta la clase HomePage en nuestra aplicacion:
package com.codelious.mixslt.controller;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;

import org.springframework.web.servlet.view.xslt.AbstractXsltView;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

public class HomePage extends AbstractXsltView {

    protected Source createXsltSource(Map modelo, String nombreRaiz,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception {

        Document documento = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        Element raiz = documento.createElement(nombreRaiz);

        List palabras = (List) modelo.get("listaPalabras");
        for (Iterator it = palabras.iterator(); it.hasNext();) {
            String palabraSiguiente = (String) it.next();
            Element nodoPalabra = documento.createElement("palabra");
            Text nodoTexto = documento.createTextNode(palabraSiguiente);
            nodoPalabra.appendChild(nodoTexto);
            raiz.appendChild(nodoPalabra);
        }
        return new DOMSource(raiz);
    }
}

Una serie de parametros nombre/valor pueden ser definidos opcionalmente por tu subclase la cual sera agregado al objeto de transformacion. Los nombres de parametro deben coincidir con los definidos en la plantilla XSLT declarados con <xsl:param name="miParametro">valorDefecto</xsl:param><bean id="homeController" class="xslt.HomeController" />. Para especificar los parametros, sobreescribe el metodo getParameters() de la clase AbstractXsltView y retorna un Map de nombre/valor. Si tus parametros necesitan derivar informacion desde la solicitud actual, tu puedes sobreescribir el metodo getParameters(HttpServletRequest request) en su lugar.

Definiendo las propiedades de la vista

El archivo views.properties (o definicion xml equivalente si estas usando un view resolver basado en XML) luce como este para la unica vista de la aplicacion que es 'Mis Primeras Palabras':
home.(class)=com.codelious.mixslt.controller.HomePage 
home.stylesheetLocation=/WEB-INF/xsl/home.xsl
home.root=palabras
Aqui, puedes ver como la vista esta enlazada con la clase HomePage recien escrita la cual maneja el modelo domificacion en la primera propiedad '.class'. La propiedad 'stylesheetLocation' apunta al archivo XSLT el cual manipulara para nosotros la transformacion XML dentro de HTML y la propiedad final '.root' es el nombre que sera usado como la raiz del documento XML. Este obtiene acceso a la clase HomePage de arriba en el segundo parametro para los metodos createXsltSource(..).

Transformacion del documento

Finalmente, tenemos el codigo XSLT usado para transformar el documento de arriba. Como muestra en el archivo 'views.properties', la hoja de estilos es llamada 'home.xslt' y esta ubicada en el directorio 'WEB-INF/xsl'.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" omit-xml-declaration="yes" />

    <xsl:template match="/">
        <html>
            <head>
                <title>Hola!</title>
            </head>
            <body>
                <h1>Mis Primeras Palabras</h1>
                <xsl:apply-templates />
            </body>
        </html>
    </xsl:template>

    <xsl:template match="palabra">
        <xsl:value-of select="." />
    </xsl:template>
</xsl:stylesheet>

El archivo index.jsp solamente es la pagina de entrada a la aplicacion y en ella hemos puesto un link a nuestro controlador http://localhost:18080/MiXSLT/home.htm
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!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>MiXSLT</title>
    </head>
    <body>
        <h1>Bienvenido a mi XSLT</h1>
        Prueba la vista XSL en <a href="http://localhost:18080/MiXSLT/home.htm">
                      http://localhost:18080/MiXSLT/home.htm</a>
    </body>
</html>

Solo nos queda probar nuestra aplicacion en un navegador usando la pagina de entrada o bien directamente escribiendo la url http://localhost:18080/MiXSLT/home.htm y deberia verse algo asi:
Puedes descargarte el codigo en github https://github.com/codelious/Spring_XSL_views