Servicios Personalizados de Pimento

En los artículos anteriores dedicados a Pimento Data Service exploramos el uso de la clase EntityManager para invocar operaciones CRUD y la funcionalidad de “lazy loading”. Esta vez vamos a tratar el uso de los servicios personalizados y lo haremos como siempre a través de un ejemplo.


Habiamos mencionado en el primer artículo que Pimento Data Services ofrece dos modelos de programación, uno basado en la clase EntityManager y el otro basado en los servicios personalizados. Con este último se crean clases de Java que asemejan a la capa de servicios de una arquitectura multicapa, y se exponen como servicios remotos de Cinnamon, el framework que implementa AMF y que soporta tareas “ant” que facilitan la creación de “proxies” en ActionScript de estas clases Java.

El uso de este modelo de programación permite también aprovechar las facilidades de Pimento en cuanto a que entidades que hayan sido cargadas por un servicio personalizado pueden ser gestionadas por el framework, o sea, se cargarán en el “cache” del cliente, se gestionará su llave primaria cuando se haga persistente una nueva instancia, etc. Esto quiere decir que los dos modelos se pueden complementar entre sí para adaptarse a los requerimientos.

El ejemplo

El ejemplo que desarrollaremos será el mismo que en el artículo dedicado al “lazy loading”, pero en este caso, en vez de hacer la carga inicial de la entidad “Project” utilizando la clase EntityManager lo haremos utilizando un servicio personalizado, la asociación “One To Many” la cargaremos a través del método “initialize”, de EntityManager, lo que probará la integración de ambos modelos de programación.

Lo primero será descargar el framework de aquí. Luego creamos un proyecto de tipo “Dynamic Web Project” con las siguientes características:

  • Nombre del proyecto: CustomPimentoServer
  • Target Runtime: En nuestro caso usaremos Apache Tomcat 6, pero puede utilizarse cualquier otro que se haya configurado.
  • Versión del módulo Web Dinámico: 2.5
  • Configuración: Configuración por defecto para Apache Tomcat 6.0
  • Cambiamos la carpeta donde se compilarán las clases a “CustomPimentoServer/WebContent/WEB-INF/classes”.

Una vez creado el proyecto copiamos el contenido de la carpeta “server/web/WEB-INF/lib” de la distribución del framework en “WebContent/WEB-INF/lib” de nuestro proyecto. Sustituimos el archivo de HSQLDB por el controlador JDBC de MySQL, y copiamos de la carpeta “server/release” los archivos “cinnamon-core”, “cinnamon-reflect”, “pimento-core” y ”pimento-generator”. Necesitamos copiar también “freemarker” y “paranamer” de la carpeta “server/lib” y el paquete “javassist”, este lo podemos encontrar en la distribución de Spring con dependencias. La carpeta “generatorTemplate” la copiamos en la raíz del proyecto.

Creamos una carpeta denominada “config” dentro de “WebContent/WEB-INF” de nuestro proyecto y copiamos los archivos “jpa-spring.xml” y “pimento-spring.xml” en “server/web/WEB-INF/config” en la distribución del framework; también copiamos el archivo “dp.properties.template.mysql” de “server/web/WEB-INF/config/db-templates” como “db.properties” en “WebContent/WEB-INF/config” de nuestro proyecto y ajustamos los valores de la conexión a la base de datos. Como estamos en fase de desarrollo ponemos “hibernate.hbm2ddl.auto=update”.

Finalmente el archivo “web.xml” de nuestro proyecto queda así:

[ftf w=”500″ h=”200″]

Pimento_Server


index.html
index.htm
index.jsp
default.html
default.htm
default.jsp

contextConfigLocation /WEB-INF/config/jpa-spring.xml
/WEB-INF/config/pimento-spring.xml
/WEB-INF/config/service-spring.xml

org.springframework.web.context.ContextLoaderListener org.springframework.web.context.request.RequestContextListener


Cinnamon
org.spicefactory.cinnamon.web.SpringCinnamonServlet
1


Cinnamon
/service/*


[/ftf]

En este caso el servicio personalizado se define en el archive service-spring.xml, cuyo contenido es el siguiente:

[ftf w=”500″ h=”200″]




[/ftf]

Las entidades con que trabajaremos son:

Project:
[ftf w=”500″ h=”200″]
package com.nonocarballo.pimento.vo;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;

import org.spicefactory.pimento.config.Managed;

@Entity
@Managed
public class Project {

private Long id;
private String name;
private String description;
private List tasks;

@Id
@GeneratedValue
public Long getId() {
return id;
}

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

@OneToMany(fetch=FetchType.LAZY)
@JoinColumn
public List getTasks() {
return tasks;
}

public void setTasks(List tasks) {
this.tasks = tasks;
}

}
[/ftf]

Task
[ftf w=”500″ h=”200″]
package com.nonocarballo.pimento.vo;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.spicefactory.pimento.config.Managed;

@Entity
@Managed
public class Task {

private Long id;
private String name;
private String description;

@Id
@GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
[/ftf]

Estas son entidades de JPA con anotaciones del framework que indica que serán gestionadas por éste.

El servicio personalizado se concibe como una clase que implementa una interface donde se definen todas las operaciones. El código es el siguiente:

ProjectService
[ftf w=”500″ h=”200″]
package com.nonocarballo.pimento.service;

import org.spicefactory.cinnamon.config.annotation.CinnamonService;

import com.nonocarballo.pimento.vo.Project;

@CinnamonService
public interface ProjectService {

public Project loadProjectById(Long id);
}
[/ftf]

Nótese aquí la anotación “@CinnamonService” que indica un servicio a ser invocado remotamente.

ProjectServiceImpl
[ftf w=”500″ h=”200″]
package com.nonocarballo.pimento.service.impl;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import com.nonocarballo.pimento.service.ProjectService;
import com.nonocarballo.pimento.vo.Project;

public class ProjectServiceImpl implements ProjectService{

private EntityManager entityManager;

public EntityManager getEntityManager() {
return entityManager;
}

@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}

@Override
public Project loadProjectById(Long id) {
// TODO Auto-generated method stub
Project result = (Project)entityManager.find(Project.class, id);
return result;

}
}
[/ftf]

Esta es una clase que utiliza JPA del modo tradicional donde de realiza la carga de la entidad Project. Para poder utilizar esta clase desde Flex a través de Pimento debemos generar el “proxy” para ActionScript, lo cual haremos mediante las tareas “ant” suministradas por el framework para esto:

[ftf w=”500″ h=”200″]









[/ftf]

Antes de proseguir con el cliente cargaremos algunos datos iniciales en la base de datos:

[ftf w=”500″ h=”200″]
INSERT INTO `project` (`id`,`description`,`name`) VALUES
(1,’Explora la funcionalidad de lazy Loading utilizando Pimento Data Services y Cinnamon’,’Lazy Loading con Pimento y Cinnamon’);

INSERT INTO `task` (`id`,`description`,`name`,`tasks`) VALUES
(1,’Configuración de Pimento’,’Configuración’,1),
(2,’Carga de la entidad del lado \”One\” de la relación’,’Carga de la entidad’,1),
(3,’Carga de las entidades del lado \”Many\” de la relación’,’Carga de las asociaciones’,1);
[/ftf]

Creamos un proyecto Flex con las siguientes características:

  • Nombre del proyecto: CustomPimentoClient
  • Tipo de aplicación: Web
  • Seleccionamos el SDK por defecto
  • Como tecnología del servidor no seleccionamos ninguna
  • Como carpeta de salida seleccionamos la carpeta WebContent del proyecto CustomPimentoServer que creamos anteriormente.

Nuestra interface de usuario será la misma que en el artículo anterior:

1

Inicialmente cargaremos una instancia de Project, pero esta vez utilizando el servicio personalizado, e inspeccionaremos el contenido de su propiedad “tasks”, luego cargaremos las instancias de “Task” asociadas mediante el método “initialize” de la clase EntityManager, las cuales mostraremos en el “DataGrid”.

Para estructurar mejor el proyecto nos auxiliaremos del framework Robotlegs. Lo primero que haremos será incluir en el proyecto las librerías del framework Pimento y Cinnamon. Copiamos en la carpeta “libs” del proyecto los archivos “cinnamon-1.1.0.swc” y “pimento-1.1.0.swc” que se encuentran en la carpeta “client\release” de la distribución, incluimos también “spicelib-core-2.0.1.swc” y “spicelib-reflect-2.0.1.swc” de la carpeta “client\lib” y la librería del framework Robotlegs.

Creamos luego las clases en ActionScript que representan las entidades:

Project
[ftf w=”500″ h=”200″]
Package com.nonocarballo.pimento.vo
{
import mx.collections.ArrayCollection;

public class Project
{
public function Project()
{
}

public var id:Number = 0;
public var name:String;
public var description:String;
public var tasks:Array;
}
}
[/ftf]

Task
[ftf w=”500″ h=”200″]
package com.nonocarballo.pimento.vo
{
public class Task
{
public function Task()
{
}

public var id:Number = 0;
public var name:String;
public var description:String;
}
}
[/ftf]

La configuración del framework en el cliente comienza con la creación de una instancia de la clase “PimentoConfig”, a través de la cual podemos obtener el “EntityManager” que usaremos para invocar las operaciones de persistencia. La clase PimentoConfig necesita conocer el URL de la aplicación JEE que a través de Cinnamon recibirá las solicitudes del cliente para invocar las operaciones de persistencia, específicamente el URL al servlet “service”. En nuestro caso cargaremos esta información de un archivo xml externo. El comando que hace todo esto y además carga la instancia de “Project” que insertamos en la base de datos es el siguiente:

[ftf w=”500″ h=”200″]
package com.nonocarballo.pimento.command
{

import com.nonocarballo.pimento.service.ProjectService;
import com.nonocarballo.pimento.service.ProjectServiceImpl;
import com.nonocarballo.pimento.vo.Project;
import com.nonocarballo.pimento.vo.Task;

import mx.controls.Alert;
import mx.events.DynamicEvent;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;

import org.robotlegs.mvcs.Command;
import org.spicefactory.pimento.config.PimentoConfig;
import org.spicefactory.pimento.service.EntityManager;

public class StartUpCommand extends Command
{

Task;
Project;

public function StartUpCommand()
{
super();
}

override public function execute():void{
var service:HTTPService = new HTTPService();
service.url = “config/config.xml”;
service.resultFormat = “e4x”;
service.addEventListener(ResultEvent.RESULT, result);
service.addEventListener(FaultEvent.FAULT, fault);
service.send();

}

private function result(event:ResultEvent):void{
var serviceURL:String = event.result..serviceUrl;
var config:PimentoConfig = new PimentoConfig();
config.serviceUrl = serviceURL+”/service”;
config.defaultTimeout = 5000;
config.configure();
var projectService:ProjectService = new ProjectServiceImpl();
config.addService(“projectService”, projectService);
var entityManager:EntityManager = config.entityManager;
injector.mapValue(EntityManager, entityManager);

projectService.loadProjectById(1).addResultHandler(loadResult);

}

private function fault(event:FaultEvent):void{
Alert.show(event.toString());
}

private function loadResult(value:Project):void{
var event:DynamicEvent = new DynamicEvent(“projectLoaded”);
event.project = value;
dispatch(event);
}
}
}
[/ftf]

Para configurar el servicio personalizado creamos una instancia de ProjectServiceImp y lo registramos en el framework a través del método “addService”. Al final cargamos la entidad basado en su Id.

Una vez cargada la instancia de Project, ante el evento “Click” del botón se ejecuta el comando que carga los datos de la asociación:

[ftf w=”500″ h=”200″]
package com.nonocarballo.pimento.command
{
import com.nonocarballo.pimento.vo.Project;

import mx.collections.ArrayCollection;
import mx.events.DynamicEvent;

import org.robotlegs.mvcs.Command;
import org.spicefactory.pimento.service.EntityManager;

public class LoadTaskCommand extends Command
{
public function LoadTaskCommand()
{
super();
}

[Inject]
public var event:DynamicEvent;

[Inject]
public var entityManager:EntityManager;

private var project:Project;
override public function execute():void{
project = event.project as Project;
entityManager.initialize(project.tasks).addResultHandler(initializeResult);
}

private function initializeResult(value:Array):void{
var event:DynamicEvent = new DynamicEvent(“taskLoaded”);
event.tasks = new ArrayCollection(value);
dispatch(event);
}

}
}
[/ftf]

El código fuente del proyecto se puede descargar desde aquí.

Conclusiones

Hemos visto el modelo de programación de Pimento que permite utilizar servicios personalizados, que no son más que clases de Java expuestas como destinos remotos que toman entidades como parámetros o devuelven entidades como retorno. Estas entidades pueden ser gestionadas por Pimento lo que permite que este modelo coexista con el otro que se basa en la clase EntityManager, dando gran flexibilidad a la aplicación.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Acerca de Made In Flex

Made In Flex es una comunidad de desarrolladores de Apache Flex creada en 2006.

Apache Flex, anteriormente conocido como Adobe Flex, es un SDK (kit de desarrollo de software) para crear aplicaciones enriquecidas - multiplataforma basadas en Adobe Flash donado por Adobe a la fundación Apache in 2011 y promocionado a proyecto de primer nivel en Diciembre de 2012.

Actualmente estamos cambiando muchos aspectos del sitio web para ofrecer un sitio útil para toda la comunidad que tenga en cuenta las necesidades actuales.

Últimas Fotos

Instalador de Apache Flex

Entrar o Registrase