ßeta perpetua

El blog personal de Juan Manuel Barroso

Grails: Testing unitario de controladores que usan ‘bindData’

1 Comment »

Grails permite hacer data binding en las acciones de los controladores. Es una manera muy práctica de cargar los parámetros que nos llegan a través de los submit de los formularios a objetos de dominio.

El problema lo tenemos con los test unitarios de nuestro controlador. Al lanzarlos no se encontrará el método bindData, y obtendremos un error del tipo “No signature of method:….”

Para evitar este problema podemos inyectar el método bindData al objeto controlador que estamos probando unitariamente. A continuación se muestra un código que realiza dicha tarea:

private void addBindataToController() {
  controller.metaClass.bindData = { objectInstance, params ->
     def excludeProperties = ['class' , 'metaClass' ]
     params.each { property, value ->
       try {
         if(!excludeProperties.contains(property)) {
           objectInstance."$property" = value
         }
       } catch(MissingPropertyException ex){ }
     }
     return objectInstance
  }
}

Sólo debemos añadir el  método anterior a la clase en la que implementamos  las pruebas unitarias de nuestro controlador, e invocarlo en el setup de nuestros test.

Con esto podemos saltarnos la limitación de hacer testing unitario sobre controladores que usan el método bindData. Este limitación ha estado presente, al menos, hasta la versión 1.3.7 de Grails. Es muy posible que futuras versiones del framework den solución al problema.

Conectando Grails y EJB3

No Comments »

Me he encontrado con la necesidad de construir una aplicación web sobre un servicio EJB3 que implementa el acceso a datos y gran parte de la lógica de negocio, y como era de esperar, Grails me ha facilitado enormemente el mecanismo para la integración.

La idea es que la aplicación Grails (1.3.6) pueda desplegarse en un servidor diferente a donde se encuentra el EJB3, para esto usaremos  JNDI y la interfaz remota del servicio.

Lo primero que debemos hacer es añadir los beans correspondientes al fichero conf/spring/resources.groovy:

ejbJndi(org.springframework.jndi.JndiTemplate) {
   environment = [
      "java.naming.factory.initial" : "org.jnp.interfaces.NamingContextFactory",
      "java.naming.provider.url" : "jnp://servidorEJb3.net:1099"
   ]
}

Lo que hemos hecho es construir un bean, con nombre ejbJndi, a partir  de la clase org.springframework.jndi.JndiTemplate. Le damos valor a la variable environment especificando las propiedades que Spring usará para encontrar nuestro EJB3.

Luego procedemos a declarar nuestro bean remoto añadiendo al fichero anterior una nueva entrada:

beanServicioRemoto(org.springframework.jndi.JndiObjectFactoryBean) {
    jndiName = "aplicacion/ejbName/remote"
    jndiTemplate = ref("ejbJndi")
}

Hemos llamado a nuestro bean beanServicioRemoto, y lo hemos inicializado con el nombre del EJB (especificando la interfaz remota)  y la referencia a nuestro template  ejbJndi.

El beanServicioRemoto puede ser usado desde los controladores o servicios como un servicio más:

def beanServicioRemoto

Pero antes de poder usarlo debemos añadir algunas librerías al directorio lib de nuestra aplicación:

La primera a añadir deberá ser la que contenga la interfaz del EJB3 remoto y todos las clases que se usen en dicha interfaz. Dicha librería puede obtenerse empaquetando en un JAR las clases del EJB3

Adicionalmente, es muy probable que se necesiten añadir librerías clientes del servidor donde se encuentre desplegado el EJB3. Para JBOSS 4.2.3 se han añadido las siguientes librerías:

jbossall-client.jar
jboss-aop-jdk50-client.jar
jboss-aspect-jdk50-client.jar
jboss-common-client.jar
jboss-ejb3-client.jar
jboss-j2ee.jar
jnp-client.jar

Si la aplicación levanta, enhorabuena, en caso contrario es muy probable que aparezca el demonio de los conflictos de librerías y tengas que pelearte con él. En mi caso me apareció el siguiente error:

Server failed to start: java.lang.LinkageError:
   Class javax/management/MBeanServer violates loader constraints

Problema que solucione cambiando el servidor de aplicaciones embebido a jetty. Este cambio me lo pude permitir porque el contenedor destino de la aplicación  era JBOSS, y en tiempo de desarrollo me daba igual tomcat que jetty.

Para desinstalar tomcat e instalar jetty:

grails uninstall-plugin tomcat
grails install-plugin jetty

Si en lugar de EJB3 tenemos EJB2 se deberán cambiar las clases de Spring que se usan en el resources.groovy. Puede consultarse aquí dicho escenario.