Lazy loading desde Flex con Pimento y Cinnamon



El framework Pimento Data Services nos permite realizar el “lazy loading” de una asociación que haya sido configurada como “lazy” en JPA. Para ese tipo de asociación el framework envía al cliente solamente “proxies”, no los datos reales, los datos reales serán cargados en el momento que se invoque el método “initialize” de la clase EntityManager, y no obtendremos una excepción del tipo LazyInitializationException. Veamos cómo funciona a través de un ejemplo.

El ejemplo

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: LazyPimentoServer
  • 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 “LazyPimentoServer/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” y “pimento-core”. Necesitamos copiar también el paquete “javassist”, este lo podemos encontrar en la distribución de Spring con dependencias.

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

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


Cinnamon
org.spicefactory.cinnamon.web.SpringCinnamonServlet
1


Cinnamon
/service/*


[/ftf]

Seguidamente crearemos las entidades asociadas:

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]

Como vemos son dos entidades JPA con anotaciones de Pimento que indican que serán gestionadas por éste. La entidad “Project” tiene una asociación con la entidad “Task” de tipo OneToMany configurada como “lazy”, lo que implica que cuando se cargue una instancia de “Project” no se cargarán en ese instante las instancias de “Task” asociadas con ésta. En este caso el framework enviará al cliente “proxies” que serán utilizados para cargar los datos reales. Veamos cómo funciona esto desde la UI, pero primero cargaremos algunos datos 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: LazyPimentoClient
  • 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 LazyPimentoServer que creamos anteriormente.

Nuestra interface de usuario sería algo como esto:

1

Inicialmente cargaremos una instancia de Project 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.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 entityManager:EntityManager = config.entityManager;
injector.mapValue(EntityManager, entityManager);

entityManager.load(Project, 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]

Si corremos la aplicación con el “debugger” y nos paramos dentro del método loadResult veremos que el tipo de la propiedad “tasks” de Project no es un “Array” como está definido sino de tipo “ArrayProxy”.

2

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 método que carga los datos de la asociación es “initialize”, de “EntityManager”, se le pasa como argumento la propiedad “tasks” de la instancia de “Project” previamente cargada.

Una vez más, si corremos la aplicación con el “debugger” y nos paramos dentro del método “initializeResult” veremos que el tipo de la propiedad “tasks” ha cambiado de “ArrayProxy” a “Array”, conteniendo las instancias de “Tasks” asociadas.

3

El código fuente del la aplicación, cliente y servidor se puede descargar de aquí.

Conclusiones

Hemos visto como Pimento Data Services nos permite hacer “lazy loading” de entidades directamente desde ActionScript de una forma verdaderamente simple. Tan solo debemos poner las anotaciones en la entidad Java y el framework se encarga del resto, es una lástima que Pimento y Cinnamon no soporten ninguna funcionalidad que permita hacer sincronización de datos entre varios clientes. ¿Alguien se anima?

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