Service Builder para desarrollar un portlet con gestión de base de datos Parte 1/3

En el blog ya hemos tratado el tema de crear portlets que procesan un formulario así que ya he llegado la hora de aprender a utilizar portlets que interactúen con la base de datos.

Existen muchas maneras de crear portlets que utilicen la base de datos de Liferay, pero en este hoy vamos a aprovecharnos un poco más de Liferay IDE y vamos a aprender a utilizar Service Builder.

Para realizar este post me he basado en las explicaciones de los libros “Liferay in Action” y “Portlets in Action”, además de utilizar como idea de base el portlet de Albert Coronado disponible en el Marketplace de Liferay, sí como la documentación oficial de Liferay.

Service Builder

Es una herramienta integrada en el plugin de Liferay para Eclipse que genera el código necesario (clases e interfaces) para crear una capa de servicio y poder utilizar la persistencia.

¿Por qué utilizar Service Builder?

En un principio cuando nos conectamos a base de datos utilizamos JDBC para obtener una conexión e implementar los métodos de acceso. El problema es que mantener el código es un poco difícil, consultas SQL, acoplamiento con la base de datos, había que tener cuidado con las inyecciones SQL,… en fin eran necesarias mucho esfuerzo para mantenerlo todo.

Después llegaron los EJB´s y para no alargar mucho la explicación llegó Hibernate, que tomó un enfoque un tanto diferente. Hibernate crea un mapeo entre objetos del mundo Java y tablas de la base de datos, lo que ayuda al programador a “desentenderse” de la base de dato y utilizar objetos Java con los que está familiarizado.

La combinación de Spring e Hibernate se utiliza desde hace mucho tiempo, Spring e Hibernate nos ayudan a construir portlets y aplicaciones web de una manera bastante sencilla.

Como ya hemos dicho Service Builder es una utilidad creada por Liferay que nos ayuda con todo este proceso. Con solo definir un archivo XML se genera automáticamente toda la configuración de Hibernate y Spring que un portlet pueda interactuar con la base de datos.

Brown tasks

Este portlet que vamos a crear nos ayudará a ser más organizados en nuestro día a día, ya que crearemos un gestor de tareas. Con este gestor podremos crear listas de tareas, e ítems en cada lista quedando un portlet más o menos como este:

Podemos crear nuevas listas de tareas (Add List) y editar las listas existentes (Edit List). Así es el look and feel al crear nuevas listas de tareas.

Podemos hacer lo mismo para los ítems dentro de una lista.

Y así es como quedará la vista de un ítem creado

Creando el proyecto

Con esto ya podemos empezar a crear nuestro Portet “Brown Tasks” con service builder. Para ello creamos un proyecto utilizando Liferay IDE:

Ya tenemos un portlet hola mundo creado, ahora vamos a crear un Service Builder

Creando un Service Builder

Lo primero es crear un Service builder, para ello nos posicionamos encima del proyecto, hacemos clic derecho sobre el nombre del proyecto y después vamos a menú new -> service builder.

Esto nos creará y abrirá un archivo llamado service.xml. Aquí tendremos que crear nuestras entidades. En nuestro caso las entidades son 2 TaskList y TaskItem  con sus correspondientes atributos.

Este es el archivo xml generado:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.1.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_1_0.dtd">
<service-builder package-path="com.jesuslc.demos.browntasks">
       <author>Jesus</author>
       <namespace>sb</namespace>
      <entity name="TaskList" remote-service="false" local-service="true">
        <column name="id" type="long" primary="true"></column>
        <column name="portlet" type="String"></column>
        <column name="description" type="String"></column>
        <column name="weight" type="int"></column>
    </entity>
    <entity name="TaskItem" local-service="true" remote-service="false">
        <column name="id" primary="true" type="long"></column>
        <column name="list" type="long"></column>
        <column name="label" type="String"></column>
        <column name="weight" type="int"></column>
        <column name="description" type="String"></column>
        <column name="status" type="int"></column>
    </entity>
</service-builder>

No te preocupes, este archivo es muy fácil de entender. Vamos a explicarlo un poco.

En la cabecera tenemos el paquete donde se generarán los archivos (“com.jesuslc.demos.browntasks”) y el namespace.

Después tenemos la definición de las entidades. Hemos definido dos entidades donde debemos indicar que son servicios locales (local-service=“true”) ya que vamos a crear entidades para interactuar con la base de datos.

Dentro de cada entidad tenemos la definición de cada columna con su tipo de dato correspondiente. Es importante que cada entidad tenga definida siempre una clave primaria (primary=“true”).

Una vez que ya tenemos todas las entidades creadas debemos pinchar sobre el botón Build Services esto generará una serie de ficheros y directorios con los que trabajaremos después.

Con esto ya tenemos creada una capa de servicio con la que atacar a la base de Liferay. Ahora poco a poco iremos construyendo las siguientes clases para crear el portlet.

En la siguiente figura podemos ver el árbol del proyecto justo después de utilizar Service Builder

Atención, vemos que se han generado muchas clases, por ello no se puede meter código a lo loco, solo se puede escribir código en algunas clases, ya que de lo contrario la funcionalidad “Service Builder” no funcionará correctamente.

Creando el idioma

Vamos a crear un fichero de propiedades donde definiremos una serie de variables que será con las que trabajamos en los ficheros JSP, el valor de estas variables es la cadena que se mostrará en el portlet. Este fichero de propiedades se encontrará dentro de la carpeta ser en una carpeta llamada “content”, el nombre del fichero será “Language.properties”.

Vamos a ver un trozo de código del fichero de propiedades:

attention-delete=ATENTION!! Do you want remove the registry?

En los JSP (vista) utilizaremos el valor “attention-delete” en cualquier JSP, y cuando terminemos el portlet lo que se mostrará al usuario es el mensaje “ATENTION!! Do you want remove the registry?”. Esto nos ayudará a la hora de las posibles modificaciones en la vista, ya que así desacoplaremos el código. Si en algún momento queremos cambiar el mensaje, solo tendremos que modificar el archivo “Language.properties”.

La semana que viene habrá una segunda parte donde seguiremos desarrollando el portlet.

Anuncios

7 comentarios sobre “Service Builder para desarrollar un portlet con gestión de base de datos Parte 1/3

  1. Muy buen artículo Jesús!

    Tengo una duda, si por ejemplo yo tengo mi BBDD con xampp (MySQL) donde o cómo defino para que mire esa bbdd con sus respectivas tabla/s.

    Gracias!

    Me gusta

    1. Muchas gracias por comentar.
      Service builder es un servicio que proporciona Liferay para construir portlet, es muy fácil de utilizar sí tienes instalado y configurado el plugin de eclipse “Liferay IDE”.
      Por tanto utilizará la misma base de datos que utilizas para Liferay.

      Espero que te sea de ayuda, si necesitas algo más pregunta 🙂

      Me gusta

  2. Buen articulo Jesus
    Soy nuevo haciendo esto y he creado un portlet 6.1 en en eclipse y al momento de ejecutar el Build Services me sale el siguiente error:

    [Console output redirected to file:D:\LiferayCE-6.1\SISDGT\workspace\.metadata\.plugins\com.liferay.ide.eclipse.sdk\sdk.log]
    Buildfile: D:\LiferayCE-6.1\SISDGT\liferay-plugins-sdk-6.1.0\portlets\brown-tasks-portlet\build.xml
    build-service:
    [java] java.lang.NoSuchMethodError: com.liferay.util.log4j.Log4JUtil.configureLog4J(Ljava/lang/ClassLoader;)V
    [java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:194)
    [java] at org.apache.tools.ant.taskdefs.Java.run(Java.java:771)
    [java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:221)
    [java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:135)
    [java] at org.apache.tools.ant.taskdefs.Java.execute(Java.java:108)
    [java] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
    [java] at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
    [java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    [java] at java.lang.reflect.Method.invoke(Unknown Source)
    [java] at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
    [java] at org.apache.tools.ant.Task.perform(Task.java:348)
    [java] at org.apache.tools.ant.Target.execute(Target.java:390)
    [java] at org.apache.tools.ant.Target.performTasks(Target.java:411)
    [java] at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1399)
    [java] at org.apache.tools.ant.Project.executeTarget(Project.java:1368)
    [java] at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
    [java] at org.eclipse.ant.internal.launching.remote.EclipseDefaultExecutor.executeTargets(EclipseDefaultExecutor.java:32)
    [java] at org.apache.tools.ant.Project.executeTargets(Project.java:1251)
    [java] at org.eclipse.ant.internal.launching.remote.InternalAntRunner.run(InternalAntRunner.java:424)
    [java] at org.eclipse.ant.internal.launching.remote.InternalAntRunner.main(InternalAntRunner.java:138)
    [java] Caused by: java.lang.NoSuchMethodError: com.liferay.util.log4j.Log4JUtil.configureLog4J(Ljava/lang/ClassLoader;)V
    [java] at com.liferay.portal.util.InitUtil.init(InitUtil.java:94)
    [java] at com.liferay.portal.util.InitUtil.initWithSpring(InitUtil.java:159)
    [java] at com.liferay.portal.tools.servicebuilder.ServiceBuilder.main(ServiceBuilder.java:117)
    [java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    [java] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    [java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    [java] at java.lang.reflect.Method.invoke(Unknown Source)
    [java] at org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:217)
    [java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:152)
    [java] … 19 more
    [java] Java Result: -1
    [echo] ${service.test.output}
    [mkdir] Created dir: D:\LiferayCE-6.1\SISDGT\liferay-plugins-sdk-6.1.0\portlets\brown-tasks-portlet\docroot\WEB-INF\service-classes

    soy nuevo asi que no se que le falta te agradeceria si me pudieras dar una mano con esto

    Me gusta

  3. He bajado el proyecto del git hub pero en los paquetes me salen errores
    como este :
    dentro de AddItemController.java

    The import com.jesuslc.demos.browntasks.model.TaskItem cannot be resolved.
    The import com.jesuslc.demos.browntasks.service.TaskItemLocalService cannot be resolved.
    The import com.jesuslc.demos.browntasks.service.TaskItemLocalServiceUtil cannot be resolved.

    estoy usando LIFERAY 6.1

    creo que soy yo el que esta haciendo algo mal, no se que le falta.

    Buildfile: D:\LiferayCE-6.1\SISDGT\liferay-plugins-sdk-6.1.0\portlets\brown-tasks-portlet\build.xml
    compile:
    merge:
    [copy] Copying 5 files to D:\LiferayCE-6.1\SISDGT\liferay-plugins-sdk-6.1.0\portlets\brown-tasks-portlet\docroot\WEB-INF\lib
    compile-java:
    merge:
    war:
    build-css:
    [java] D:\LiferayCE-6.1\SISDGT\liferay-plugins-sdk-6.1.0\portlets\build-common-portlet.xml:15: java.io.IOException: Cannot run program “D:\LiferayCE-6.1\Bundles\liferay-portal-6.1.0-ce-ga1\tomcat-7.0.23\jre1.6.0_20\win\bin\java.exe”: CreateProcess error=87, El parámetro no es correcto
    [java] at org.apache.tools.ant.taskdefs.Java.fork(Java.java:798)
    [java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:214)
    [java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:135)
    [java] at org.apache.tools.ant.taskdefs.Java.execute(Java.java:108)
    [java] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
    [java] at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
    [java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    [java] at java.lang.reflect.Method.invoke(Method.java:597)
    [java] at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
    [java] at org.apache.tools.ant.Task.perform(Task.java:348)
    [java] at org.apache.tools.ant.Target.execute(Target.java:390)
    [java] at org.apache.tools.ant.Target.performTasks(Target.java:411)
    [java] at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1399)
    [java] at org.apache.tools.ant.helper.SingleCheckExecutor.executeTargets(SingleCheckExecutor.java:38)
    [java] at org.eclipse.ant.internal.launching.remote.EclipseSingleCheckExecutor.executeTargets(EclipseSingleCheckExecutor.java:30)
    [java] at org.apache.tools.ant.Project.executeTargets(Project.java:1251)
    [java] at org.apache.tools.ant.taskdefs.Ant.execute(Ant.java:442)
    [java] at org.apache.tools.ant.taskdefs.CallTarget.execute(CallTarget.java:105)
    [java] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
    [java] at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
    [java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    [java] at java.lang.reflect.Method.invoke(Method.java:597)
    [java] at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
    [java] at org.apache.tools.ant.Task.perform(Task.java:348)
    [java] at org.apache.tools.ant.Target.execute(Target.java:390)
    [java] at org.apache.tools.ant.Target.performTasks(Target.java:411)
    [java] at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1399)
    [java] at org.apache.tools.ant.Project.executeTarget(Project.java:1368)
    [java] at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
    [java] at org.eclipse.ant.internal.launching.remote.EclipseDefaultExecutor.executeTargets(EclipseDefaultExecutor.java:32)
    [java] at org.apache.tools.ant.Project.executeTargets(Project.java:1251)
    [java] at org.eclipse.ant.internal.launching.remote.InternalAntRunner.run(InternalAntRunner.java:424)
    [java] at org.eclipse.ant.internal.launching.remote.InternalAntRunner.main(InternalAntRunner.java:138)
    [java] Caused by: java.io.IOException: Cannot run program “D:\LiferayCE-6.1\Bundles\liferay-portal-6.1.0-ce-ga1\tomcat-7.0.23\jre1.6.0_20\win\bin\java.exe”: CreateProcess error=87, El parámetro no es correcto
    [java] at java.lang.ProcessBuilder.start(ProcessBuilder.java:460)
    [java] at java.lang.Runtime.exec(Runtime.java:593)
    [java] at org.apache.tools.ant.taskdefs.Execute$Java13CommandLauncher.exec(Execute.java:862)
    [java] at org.apache.tools.ant.taskdefs.Execute.launch(Execute.java:481)
    [java] at org.apache.tools.ant.taskdefs.Execute.execute(Execute.java:495)
    [java] at org.apache.tools.ant.taskdefs.Java.fork(Java.java:791)
    [java] … 32 more
    [java] Caused by: java.io.IOException: CreateProcess error=87, El parámetro no es correcto
    [java] at java.lang.ProcessImpl.create(Native Method)
    [java] at java.lang.ProcessImpl.(ProcessImpl.java:81)
    [java] at java.lang.ProcessImpl.start(ProcessImpl.java:30)
    [java] at java.lang.ProcessBuilder.start(ProcessBuilder.java:453)
    [java] … 37 more
    [java] Java Result: -1
    compile:
    merge:
    compile-java:
    merge:
    build-common-plugin.war:
    [delete] Deleting: D:\LiferayCE-6.1\SISDGT\liferay-plugins-sdk-6.1.0\dist\brown-tasks-portlet-6.1.0.1.war
    clean-portal-dependencies:
    [zip] Building zip: D:\LiferayCE-6.1\SISDGT\liferay-plugins-sdk-6.1.0\dist\brown-tasks-portlet-6.1.0.1.war
    deploy:
    [copy] Copying 1 file to D:\LiferayCE-6.1\Bundles\liferay-portal-6.1.0-ce-ga1\deploy
    BUILD SUCCESSFUL
    Total time: 1 second

    esta es la estructura de donde esta ubicado el portlet
    -NET(D)
    -LiferayCE-6.1
    -SISDGT
    -liferay-plugins-sdk-6.1.0
    -portlets
    -brown-tasks-portlet
    el portlet no esta dentro del workspace sino lo he creado dentro del sdk/portlets
    gracias de antemano por el apoyo.

    Me gusta

Comenta la entrada

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s