Lo que viene con Grails 1.1

Todavía no he tenido oportunidad(¿tiempo?) de probar las betas de la versión 1.1 de Grails, pero ya llevo unas semanas siguiendo un poco las novedades que están llegando con las tres betas que se han publicado, tanto con las relesae notes como en la lista de correo.

Hay cosas que me parecen muy interesantes: el trabajo que se ha hecho en cuanto infraestructura, el manejo de submits duplicados, el "nuevo" framework de testing, las mejoras para el desarrollo de plugins, poder usar GORM fuera de Grails...

Estas son las principales novedades:

GORM:

GORM es standalone, ya se puede usar fuera de Grails.

Se completan los eventos de GORM con afterInsert, afterUpdate y afterDelete.

Persistencia de colecciones de tipos básicos, como colecciones de String:
class Person {
static hasMany = [nicknames:String]
}

Persistencia de coleciones de tipos enum:
enum VehicleStatus { OFF, IDLING, ACCELERATING, DECELARATING }
class Truck {
static hasMany = [statuses:VehicleStatus]
}

Acceder a objetos persistentes en modo sólo lectura, buscándolos por id:
def book = Book.read(1)

Ordenación por defecto a nivel de clase y en las asociaciones:
class Book {
String title
static mapping = {
sort "title"
}
}
class Author {
static hasMany = [books:Book]
static mapping = {
books sort:"title"
}
}

Obtención por lotes a nivel de clase y en asociaciones:
class Book {
String title
static mapping = {
batchSize 15
}
}

Mejoras en los finders dinámicos. Se podrá utilizar el sufijo InList, cachear queries y usar bloqueo pesismista:

def books = Book.findByAuthorInList(['Dierk Koenig', 'Graeme Rocher'])
def book = Book.findByTitle("Groovy in Action", [cache:true] )
def book = Book.findByTitle("Groovy in Action", [lock:true] )

Relaciones uno a muchos unidireccionales con mapeo heredado, usando joinTable:
class Book {
String title
static belongsTo = Author
static hasMany = [authors:Author]
static mapping = { authors joinTable:[name:"mm_author_books", key:'mm_book_id' ] }
}
class Author {
String name
static hasMany = [books:Book]
static mapping = { books joinTable:[name:"mm_author_books", key:'mm_author_id'] }
}

Los tipos Enum pueden especificar un método getId() que GORM llamará para persistir el estado del enum
enum Country {
AUSTRIA('at'),
UNITED_STATES('us'),
GERMANY('de');
final String id
Country(String id) { this.id = id } }

Plugins:

Plugins globales, para instalar en todas las aplicaciones
grails install-plugin webtest -global

Múltiples repositorios de plugins:
grails.plugin.repos.discovery.myRepository="http://svn.codehaus.org/grails/trunk/grails-test-plugin-repo"
grails.plugin.repos.distribution.myRepository="https://svn.codehaus.org/grails/trunk/grails-test-plugin-repo"

Resolución transitiva de depndencias entre plugins.

Se puede definir un ámbito y el entorno donde un plugin se cargará o empaquetará
def environments = ['dev', 'test']
def scopes = [excludes:'war']

Desarrollo modular de aplicaciones usando plugins, sin necesidad de instalarlos y pudiendo estar en cualquier lugar del sistema de ficheros. Muy útil para probar un plugin propio en una aplicación real(esto antes resultaba incómodo), o para unir en una aplicación funcionalidades repartidas en plugins.

Testing:

Se ha añadido testing plugin como framework de tests que mejora el de las versiones 1.0.x

Data Binding:

Se pueden definir de qué propiedades se hace el binding:
person.properties["firstName","lastName"] = params

Es posible hacer binding de colecciones de objetos, Grails se encarga de instanciar los objetos y los índices:
<g:textField name="books[0].title" value="the Stand" />
<g:textField name="books[1].title" value="the Shining" />
<g:textField name="books[2].title" value="Red Madder" />

Scaffolding:

El scaffolding dinámico también generará las vistas usando los templates generados(y personalizados) con install-templates.

El scaffolding ahora soporta relaciones muchos a muchos y asociaciones uno a muchos unidireccionales.

Controllers:

Manejo de submits duplicados o invalidos usando el patrón Synchronizer Token:
//en el gsp
<g:form useToken="true">...</g:form>
//controlador
withForm {
// good request
}.invalidToken {
// bad request
}

Además de redireccionar ya es posible hacer forward de una petición:
forward controller:"home", action:"index"

Groovy Server Pages:

Ya es posible utilizar librerías de tags JSP, de igual forma que cualquier librería de tags GSP:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<fmt:formatNumber value="${10}" pattern=".00"/>
${fmt.formatNumber(value:10, pattern:".00")}

Un namespace propio para usar templates, tmpl:
//template _tableRow.gsp
<tr>
<td class="prop">${label}</td>
<td class="value">${value}</td>
</tr>
//Otro gsp
<tmpl:tableRow label="one" value="two" />

Es posible hacer includes de la respuesta de otro controlador, acción o vista en la vista actual:
<g:include controller="book" action="list"/>

Posibilidad de renderizar templates de los plugins:
<g:render template="pathToTemplateFile" plugin="miplugin"/>

Ahora los gsp se renderizan más rápido, evitando el uso de StringBuffer y StringWriter.

Infraestructura:

Grails viene con un plugin de Maven y un arquetipo:
mvn grails:create-pom

Integración con Ivy y Ant, crea el build.xml y el ivy.xml para construir la aplicación Grails sin que sea necesario que Grails esté instalado en el servidor.

BeanBuilder (el DSL de Spring), ahora soporta los namespaces de Spring pudiendo utilizar así el soporte de AOP.

Nuevo API para acceder al entorno de ejecución y a los meta datos de la aplicación:
switch(Environment.current) {
case Environment.DEVELOPMENT:
configureForDevelopment()
break
case Environment.PRODUCTION:
configureForProduction()
break
}
def metadata = grails.util.Metadata.current
println metadata.applicationName
println metadata.applicationVersion

Nuevo DSL para configurar Log4j

La configuración de los builds se ha flexibilizado pudiendo configurar diferentes aspectos en el nuevo BuildConfig

Posibilidad de encriptar las contraseñas del DataSource

--
Veremos qué añadidos/mejoras más aparecen en las RC y hasta que esté disponible Grails 1.1

Acceder al ApplicationContext en un HttpSessionListener

Apple también la caga

Desde el día 26 de diciembre soy propietario de un flamante Mac Book, que lleva desde el día 12 de enero en el servicio técnico... lo compré por lo bien que me habían ido hablando, y empujado por un poco de presión popular ;).

Tengo que decir que los primeros días estaba encantado con la compra, me gustaron esas pequeñas diferencias que se encuentran respecto a un PC. Pero luego empezó la "pesadilla", tal y como movía mínimamente el mac se ponía en reposo y no volvía en sí hasta unos minutos más tarde o si reiniciaba, pero luego fué a peor y ni reiniciando conseguía que volviera en sí.

Aquí viene la muestra:

Entonces acabé llamando a Apple Care, que tras probar varias cosas vía teléfono, me dijeron que lo llevara al servicio técnico(K-tuin Zaragoza) y eso hice. A los dos días me llamaron para decirme que para resolver el problema iban a pedir una pieza para sustituirla... pero no resultó ser la solución... y todavía siguen buscando :S. Por esto el viernes(11 días después) volví a llamar a Apple Care para explicarles la situación y ver si se podía sustituir o devolver, con quien hablé me dijo que llamara el lunes para hablar con atención al cliente(a las 18:00 ya está cerrado). El lunes(14 días después y tras 30 minutos al teléfono), por fin encontré a alguien(la segunda persona con la que he hablé) que me explicó que es un defecto grave de fabricación y me remitió al servicio post-venta de Apple Store(resulta que no es lo mismo).

Ayer, ya sin ganas de seguir perdiendo el tiempo contando una y otra vez lo mismo, y empezando a perder las buenas formas(otros 30 minutos de teléfono). La primera persona con la que hablé, al ver mi mosqueo(tras decirme que llamara a Apple Care...), me pasó con otra compañera que finalmente me dijo que no me podía ayudar con la sustitución(con lo que aumenté a cabreo) y al final le pedí(lo más educadamente que pude) que me pasara "con alguien que me pueda ayudar, que es lo que estoy pidiendo...". Al final me pasaron con una tercera persona con la que me termino de desahogar, que finalmente me dijo que no podía prometer una sustitución, pero que iba a contactar con K-tuin para conocer el caso y que me llamaría en un par de días para contarme.

Resumiendo, me va a llegar una factura de teléfono interesante, en atención al cliente Apple (Care y Store) hay gente que no sabe por dónde le sopla el aire, y sobre K-tuin... puedo aceptar hasta cierto punto que no sepan cuál es el problema, pero tras decirme en dos ocasiones que me llamarían y no hacerlo(al final lo tenía que hacer yo) para mi es falta de seriedad y profesionalidad, deberían ser más atentos con sus clientes y como mínimo mantenerte informado de la situación, a mi se me han ido las ganas de comprar nada allí(cosa que iba a hacer)... Y ya veremos si vuelvo a comprar más productos de apple, para esto habrá que olvidar primero una de las peores experiencias de usuario que he tenido y, como no parece que seamos demasiados los que hemos tenido este tipo de problemas(haberlos haylos), no tengo esperanza de que la atención al cliente de apple cambie.

Veremos como termina la odisea.

2008 de todo un poco

Acabándose el año, toca mirar un poco atrás para ver como ha ido el año, que para mi ha sido muy movido :)

Algunos éxitos, o cosas con las que me siento satisfecho, han sido:

Pero como no todo puede ser bueno, hay cosas que no han salido como esperaba y de lo que no me siento especialmente orgullloso:

  • La evolución de los plugins de Grails(Include y Mor.ph), que debería haber publicado al menos otra versión de cada uno, y no les he podido dedicar el tiempo necesario para hacerlo.
  • La colaboración con el plugin JCR/Jackrabbit, al que en su momento le procuré dedicar tiempo, pero donde no ha salido nada aprovechable
  • El desarrollo de flatee, que formaba parte del internship con Linking Paths para aprender Rails, con lo que me comprometí después del internship a tenerlo para finales de año, y que aunque no sea por mucho(espero) no ha sido posible tenerlo este año

Ha sido un año interesante, aunque como freelance haya pecado de novato en varias ocasiones, me haya metido en más jaleos de los que podía manejar, la crisis... :P, he disfrutado de este trabajo más que nunca. Sólo espero que en 2009 se empiece a ver el trabajo realizado durante este año, además de seguir aprendiendo y disfrutando en esta profesión ;)

PD: Feliz año nuevo!! :D