Llevo ya dos o tres semanas jugando con Grails. La parte de hacer código estupenda, se hace mucho con muy poco, la parte de vistas y controladores bien, la de modelo y base de datos me ha dado algún problemilla, pero supongo que lo habitual si te metes con cosas que hay por debajo, como Hibernate y encima no lo controlas.
Sin embargo, me ha dado por configurar el DataSource para la base de datos. Por defecto, Grails pone una base de datos HSQLDB. Si en el fichero DataSource.groovy cambias los parámetros de conexión y pones otra base de datos, también funciona bien todo. Puse una base de datos MySQL, puse en el directorio lib el jar con el conector de MySQL, cambié los parámetros de conexión y todo correcto.
Pero claro, a mi me gustaría hacer un war de mi aplicación y ponerlo en algún sitio descargable para que la gente se lo descargue, lo ponga en su servidor, configure la base de datos a su gusto y le funcione en su entorno. Y ahí es donde me he encontrado con problemas y cosas que no me han parecido muy lógicas.
DataSource.groovy es un fuente groovy, por lo que una vez compilado, metido en un war y desplegado, no se puede cambiar fácilmente. Tampoco parece muy amigable poner en las instrucciones de instalación que se toquen los fuentes groovy y se compilen, obligando a descargar el entorno grails al que sólo quiera instalar y utilizar la aplicación.
Pero no hay problema, se mira en la documentación de grails y se acaba encontrando que se puede poner un fichero de propiedades normalito, de los de toda la vida, con la configuración de la base de datos. Estas propiedades sobreescriben a las de DataSource.groovy. Unicamente hay que hacer dicho fichero de properties y en el fichero Config.groovy poner esto al principio
grails.config.locations = ["file:path/fichero.properties"]
Podemos poner file:, como en el ejemplo, o classpath:, para cogerlo del classpath.
Lo del classpath funciona correctamente, basta meter el fichero de propiedades en el el directorio WEB-INF/classes y todo bien. Pero claro, yo soy un poco "tikis-mikis" y no me gusta meter un fichero de configuración en el directorio de classes. No creo que sea un lugar intuitivo donde alguien busque un fichero de configuración. Quizás un directorio conf o algo así….
Así que me decanto por la opción file. Pero se me presenta otro problema. Cuando despliego mi war en un Tomcat, el directorio actual de ejecución resulta ser el directorio en el que está el script de arranque del Tomcat (el catalina.bat o catalina.sh). Desde ahí no se puede poner un path relativo hacia el fichero de configuración. Bueno, sí se puede, pero sería así de feo ../webapps/MiAplicacion/WEB-INF/conf/fichero.propiedades o algo así. Y si en vez de Tomcat es otro servidor, igual no existe eso de webapps (no lo sé).
Pues nada, vamos a ver si conseguimos de alguna forma el directorio raíz de la aplicación una vez desplegada, para poder poner el path relativo desde ahí. Las variables predefinidas de grails en el config.groovy no ayudan. Tenemos ${appName}, para el nombre de la aplicación y no recuerdo las otras, pero eran dos o tres nada más y hacen referencia al número de versión de la aplicación y poco más. Nada sobre ningún path donde se está ejecutando nuestra aplicación. Siento no poner el enlace donde he visto esas tres variables, pero la maravillosa documentación de grails no me permite volver a encontrarlo fácilmente.
Sí podemos poner variables de entorno, por lo que definir una variable propia, estilo MIAPLICACION_HOME o ${userHome} sí valen. Pero tampoco es una solución elegante. No podemos decir a nuestro usuario que defina una variable de entorno indicando dónde ha desplegado tomcat nuestra aplicación y rearranque el Tomcat entero, o que se vaya a su HOME y ponga un fichero, sobre todo si el Tomcat se arranca como servicio/demonio. Es más, poner el fichero de propiedades en un sitio fijo y apuntado por una variable de entorno, la que sea, no nos permitiría desplegar dos instancias de nuestra aplicación en el mismo servidor.
Sigo investigando y descubro que hay una maravillosa cosa llamada ServletContext en la que creo que puedo obtener este path que me hace falta para localizar el fichero de propiedades. Veo además en Grails que las clases groovy tienen accesible un servletContext como atributo (o parecido). Qué casualidad, justo Config.groovy y DataSource.groovy no lo tienen, así que directamente no lo tengo accesible. Bueno, no pasa nada, ServletContextHolder lo tiene guardado como atributo estático, así que ahí podemos acceder a él. Pues nuevamente vaya, resulta que durante la ejecución de Config.groovy y DataSource.groovy, ese atributo es null.
El ServletContext se le pasa a Grails en la clase Bootstrap, método init() y cuando se llama a eso, ya se han leído todas las propiedades, cargado el dataSource y establecido la conexión a la base de datos por defecto. Ni tenemos el ServletContext disponible antes, ni podemos cambiar el DataSource después.
Así que nada, la única opción transparente para posibles usuarios es meter dicho fichero de propiedades en el classpath, en el directorio classes.
Así que mi conclusión es que grails puede estar muy bien para hacer una aplicación web que tú vas a montar y de la que tú eres responsable del servidor, quizás una aplicación web corporativa o para poner al público en un dominio concreto y ya en ejecución, Pero desde luego, no parece muy amigable si tu intención es hacer un war que luego la gente en general pueda descargarse y montar en su propio servidor. Es más, muchas aplicaciones piden al usuario a través de la misma interface web la configuración de la base de datos (url, username y password). No sé si es posible hacer esto en grails, pero si lo primero que hace grails, incluso antes de tener el servletContext disponible, es liarse a cargar ficheros de propiedades y establecer las conexiones con la bd, dudo mucho que cuando se le muestre la página de bienvenida al usuario se pueda cambiar fácilmente nada de eso.
Y encima otra cosa que me preocupa, resulta que mi aplicación son tres clases de modelo, otros tres o cuatro clases de controlador, un par de páginas gsp….. y he tenido que aumentarle la memoria al tomcat para que sea capaz de ejecutarla. El war generado ocupa 26 Megas y Tomcat empezó a dar OutOfMemory con frecuencia, por lo que tuve que subirle la memoria.
En fin, dejaré el fichero de properties en el el directorio classes (ya he perdido bastante tiempo para algo que creo no tiene solución), haré un par de cosas más que me quedan pendientes y dejaré aparcado grails una temporada. Quizás lo retome si tengo que hacer una aplicación para el departamento, pero desde luego, no lo vuelvo a escoger si mi intención es hacer una aplicación que la gente pueda instalarse en sus propios servidores.
La externalizacion de propiedades es opcional y cumulativa. Es decir, puedes declarar cuatro o cinco lugares donde grails debe encontrar configuraciones. Tipicamente, yo los pongo en el ../conf, que los pone en el mismo directorio de Tomcat o Jetty, pero fuera de la carpeta webapp.
Para mi, tu critica no es una limitacion en el mismo Grails, sino en Spring. Pues Spring carga los beans cuando empieza el programa.
Si quieres hacer una interface web para la configuracion de base de datos, te recomiendo este post de Burt Beckwith: http://burtbeckwith.com/blog/?p=312
Re: memoria – aunque tu solo tengas poco contenido, ten en cuenta que estas usando Spring, hibernate, groovy y otros libraries que vienen con grails.
Si quieres war files mas pequenos, puedes usar este truco de Mr. Haki – http://mrhaki.blogspot.com/2009/05/create-much-smaller-grails-war-file.html
Hola tomas.
Gracias por los links, echaré un ojo al de Burt Beckwith a ver si lo veo factible con mis pocos conocimientos de groovy/grails y el segundo creo que sí podré aprovecharlo, quizás eliminando todos los jars que me sobren.
Lo del ../conf es una solución, no es elegante que tu fichero de propiedades esté con los del tomcat/jetty y tampoco permite dos instancias de la misma aplicación en el servidor, pero desde luego, dentro de las posibles ubicaciones no óptimas, ../conf parece buena. He visto en algunos foros que para linux ponen la configuración en /etc/aplicacion/fichero.properties, que en el mundo linux también es un sitio adecuado para dejar ficheros de configuración (desgraciadamente, no hay equivalente en windows).
En cuanto a culpa de spring, posiblemente sea cierto (no lo sé), pero entonces quizás spring no sea una buena opción para basar la creación de una aplicación web y grails debería haberlo solucionado de otra forma. O bien se podría haber esperado a la carga de propiedades/datasources y cualquier otra cosa susceptible de ser configurada habitualmente a la llamada del init del bootstrap. Es más, no sé si entiendo el concepto de «convención sobre configuración», pero posiblemente debería bastar con poner el fichero de propiedades en algún path concreto para que grails lo cargara en el momento adecuado (quizás el mismo path en el que están Config.groovy y DataSource.groovy, pero como ficheros .properties en vez de ficheros compilables).
Como comento, creo que grails puede ser buena opción para hacer una aplicación web propia «interna» en la que el que hace el código es el que se arregla con la configuración, pero le veo carencias si quieres darle un war a los demás para que se lo instalen. No sé los demás frameworks de aplicaciones web si son similares en este sentido, pero echaré un ojo a ver.
Se bueno.
Para un projecto normal, permitimos que el config.groovy resida en
${user.home}/.grails/myapp/myapp.properties <- esto me funciona en windows y mac
../conf/myapp/myapp.properties
classpath:myapp.properties
Existen varios plugins y blog posts que permiten el cambio de datasources y config.
Este articulo por Lee Butts describe como cambiar datasources por el cliente- http://www.leebutts.com/2008/07/switchable-grails-datasource.html
El reloadable configuration plugin tambien permite esto.
http://www.grails.org/plugin/reloadable-config
En mi experiencia, ni rails ni PHP te dan la capacidad de cambiar datasources. Esto se hace al nivel de el programa o a travez de plugins.
Una de las cosas que machacan la memoria en Grails es que genera un montón de material «por debajo», y el nivel mínimo de memoria necesario es bastante alto (luego no requiere tantísimo más, aunque eso ya va a depender de muchas cosas).
Y como te han dicho, te llevas «de regalo» un montón de cosas que realmente una aplicación de tres clases de dominio y un par de GSPs no necesita (realmente no lo usarías si fuera sólo para eso)
Al resto ya te ha dado soluciones, tambien puedes optar por la ruta JNDI para temas de configuración (aunque no se si has pillado del todo lo que te decía tomas de que puedes elegir dónde se buscarán los ficheros, y el orden)
Jeje, dale otra oportunidad, y también a los foros y a la documentación, porque soluciones a varios de las dudas que te han hecho dar tantos rodeos y pruebas (lo que a veces es gratificante) están documentadas 😉
A mí me gusta, despues de un par de años de trabajar a fondo con él, me siento muy cómodo. Y seguro que hay cosas que le mejoraría, nadie es perfecto 😉
Hola, pues sí la «limitación» este caso viene de Spring, pero vamos yo he usado alguna aplicación web basada en Java Enterprise y siempre me decía de que tenía que tener cierta base de datos creada…. Yo por ahora todas las aplicaciones que he hecho con Grails o JEE siempre han sido tener que instalarlas yo y eso… No le voy a decir a un cliente de una tienda de zapatos que le he hecho un programa que se instale en tomcat, que se instale mysql etc. :-).
En frameworks PHP si que lo he visto, que te da una pantalla para configurar cosas al instalar ( o CMS’s etc ).
Me he asustado un poco al leer el post, pensaba que iba sa sacar los colores a Grails 🙂
Hola:
Lo de recargar el datasource está claro que es posible según un par de artículos que habeis puesto, pero yo no pretendo tanto. Sólo pretendo configurar el datasource desde un fichero de propiedades que esté dentro de la aplicación, cosa que me parece básica. Sí he visto que se puede hacer si el fichero está en WEB-INF/classes o algún path bien absoluto, bien relativo al user.home, bien relativo al directorio bin de tomcat (y que al igual que yo y porque no queda otro remedio, son las soluciones que habeis adoptado la mayoría de los que habeis contestado por aquí). Ninguno de esos directorios me parece una opción elegante y me parece un «despiste» por parte de grails no haberlo previsto, ya que configurar la base de datos desde un fichero de propiedades en un path «adecuado» es básico en cualquier aplicación web.
Como comento, grails puede ser bueno para aplicaciones que el desarrollador se monta, configura e instalan (como la de la tienda que comenta josem, una intranet, etc), pero le falta un último «remate» para ser adecuado para aplicaciones que se pretende que la gente se baje e instale en sus tomcats.
En cuanto al tamaño del war, quizás si es cierto que es culpa mía intentar matar moscas a cañonazos, y hacer una aplicación pequeña con un framework tan grande. Como comento al final del post, igual vuelvo a Grails si en algún momento tengo que hacer algún tipo de aplicación web para nuestro departamento, pero dudo que la vuelva a usar para algo como un tablero Kanban que luego la gente pueda bajarse y montarse en «su casa».
En cuanto a «sacarle los colores» a Grails, nunca me atrevería 🙂 . Soy novato en esto y sólo puedo comentar mi experiencia, las cosas concretas con las que me he tropezado y aún así, esos tropezones pueden ser simplemente culpa mía y de mi ignorancia. Para criticar lo de la configuración del datasource me he tirado casi tres días probando, buscando en google y en foros para asegurarme que efectivamente, no hay posibilidad de leer un fichero de propiedades en un path dentro de mi aplicación y que no sea WEB-INF/classes. De hecho, he visto en un foro que a alguien parece que le ha funcionado el obtener el ServletContext dentro de Config.groovy a través del ServletContextHolder y con él podía referenciar al directorio WEB-INF y a partir de ahí hacer lo que yo quería (casualmente, es lo mismo que él quería). Pero el post era de Dic del 2009 y a mí no me ha funcionado http://n4.nabble.com/How-can-I-specify-in-grails-config-locations-file-in-the-WEB-INF-not-WEB-INF-classes-td1317828.html ¿Es posible que en alguna versíón de los últimos tres meses se haya perdido esa característica?
Si quieres, puedes mirar esto: http://phatness.com/2010/03/how-to-externalize-your-grails-configuration/ Creo que hace algo de lo que quieres. El autor también está muy contento de lo bien que está todo documentado… 😉
@Aitor gracias por el enlace. Lo que quiero más o menos lo tengo resuelto, el único problema es que parece que no hay forma de referenciar a un fichero dentro del mismo proyecto dentro del Config.groovy, por lo que hay que recurrir a paths que no me acaban de convencer para dejar la configuración de tu aplicación.
En cuanto a la documentación, supongo que debe ser general, con lo que yo me he tropezado, se habrá tropezados más gente. Viene más o menos todo, pero muy escueto en algunos puntos, con lagunas en otros y cualquier cosa que no hayan contemplado se convierte en un misterio. Por ejemplo, me llama la atención que en la relación hasMany, insistan mucho en muchos sitios en que si borras el padre, se borran automáticamente los hijos si pones belongsTo y no lo hacen si no lo pones, parece que cuando escribieron eso, les resultaba muy importante dejarlo claro, y lo repiten hasta la saciedad en todo tipo de ejemplos, pero…. no ponen ni un solo ejemplo de removeFrom(), es más, ni siquiera mencionan el método en la documentación estilo tutorial (sí en la parte de referencia, aunque muy escueto).
gracias por el enlace.
Creo que en el fondo del problema es justamente la decision de «soldar» grails a spring e hibernate. Supongo que la decision es correcta en la medida en que el cliente que busca grails son empresas con desarrolladores habituados a desarrollar aplicaciones j2ee que ya usaban esos frameworks o se estaban planteando usarlos ya que se han convertido casi en estandares. Y en la mayoria de los casos grails mejora la productividad en ese contexto que creo que no encaja con el tuyo, que es un acercamiento mas de investigacion y de evaluacion sin un deseo de «comprar» obligatoriamente spring e hibernate.
La otra opcion hubiera sido hacer grails independiente tanto del famework mvc, como del contenedor de la inyeccion de dependencia como del orm (u otra forma de acceder a la bbdd) pero hubiera supuesto mucho mas trabajo y al dia de hoy lo mas efectivo a corto plazo a la hora de que las empresas adopten grails era elegir lo que ahora usan todas que es spring+hibernate. No solo eso sino que grails podria haberse diseñado de una forma mucho mas modular, liviana y menos monolitica aprovechando el dinamismo de groovy. Spring mismo en principio esta diseñado asi y es uno de sus atractivos.
Pero en la informatica no hay nada inmutable y lo que hoy es un estandar tal vez pasado mañana no lo sea y creo que es justo esa la debilidad de grails…
Echa un vistazo también a este link del Observatorio de Grails que te explica cómo externalizar las propiedades:
http://observatoriodegrails.com/2010/04/07/como-sobreescribir-la-configuracion-de-grails-con-ficheros-de-propiedades-ingles/
Hola Enrique, gracias por el enlace.
De todas formas, sí sé como externalizar las propiedades (hay suficiente documentación sobre eso), lo que no me gusta son las posibles ubicaciones en que se pueden poner esos ficheros de propiedades: en WEB-INF/classes, en el bin de Tomcat (o el servidor de aplicaciones que sea), en el UserHome o en un path absoluto. No hay forma de saber el path en el que se despliega tu aplicación en el entorno real de producción.