Tag Archives: openmrs

Desarrollando en openmrs con JRebel para realizar cambios en caliente

Cuando se desarrolla una aplicación JavaEE, puede resultar frustrante tener que detener la aplicación cada vez que se haya realizado un cambio en ella, para ser honesto recién estoy comenzando a desarrollar en JavaEE y viniendo del desarrollo en php desde el comienzo me pareció impensable cuando comencé a desarrollar un módulo de OpenMRS esto de tener que detener tomcat y reinstalar la aplicación o utilizar uno de los targets de ant para reiniciar openmrs (exactamente el target update), bueno y así me encontraba durante una semana aproximadamente, cuando derepente llegó un correo de la lista de openmrs para desarrolladores en la que me inscribí y era la solución a éste problema propuesta por Justin Miranda, parte de la conversación se puede ver aquí

Bueno, antes de comenzar con mi adaptación de ésta solución debo comenzar atribuyéndole todo el crédito a Justin Miranda, que además de proponer la solución me ayudó durante varios días mientras aún intentaba hacer que ésto funcione, que no imaginan cuantos problemas tuve, la entrada original se puede encontrar en el blog de Justin:

http://blog.justinmiranda.com/2010/02/hotswap-this.html

Bueno, comenzemos.

Los requisitos:

– OpenMRS, les  recomiendo bajárse la última versión en desarrollo a través de svn de aquí http://svn.openmrs.org/openmrs/trunk/

– Tomcat 5.5 ó 6.0.20 que son las versiones en las que he probado y funciona.

– JRebel http://www.zeroturnaround.com/jrebel/ (es un producto de pago, ya lo sé, pero pueden evaluarlo por 30 días)

– Un módulo de OpenMRS sobre el que realizar las pruebas, les recomiendo éste: http://svn.openmrs.org/openmrs-modules/devexamples/patientnotes/

Entonces comencemos, asumiré que saben como descargar fuentes usando svn, que están sobre windows, y que su estructura de directorios será esta:

D:openmrsopenmrs-trunk <— fuentes de openmrs descargadas por svn

D:openmrspatientnotes <—- modulo de pruebas descargado también por svn

D:JRebel <— ubicación de la instalación de JRebel, en un momento veremos como instalar JRebel

D:tomcat-6.0.20-openmrs <— ubicación de la instalación de JRebel, en un momento veremos como instalar JRebel

Instalación de JRebel:

Será tan sencillo como descargarlo, para Windows lo pueden encontrar aquí: http://www.zeroturnaround.com/downloads/jrebel-setup.exe,

ejecutarlo, indicarle la ruta en la que instalará: “D:JRebel”, y después de que se haya instalado y se inicie el asistente de configuración, no marcar la opción “I run the server from my IDE”, aunque dudo que afecte hacerlo ya JRebel cargará al nivel de ejecución de tomcat y desde allí escaneará nuestros proyectos en busca de cambios.

En un momento determinado se toparán con un plugin de JRebel para eclipse, realmente no hace falta, porque como dije será JRebel al nivel de ejecución de tomcat el que escaneará nuestros proyectos en busca de cambios.

Bueno, ya tenemos JRebel instalado, es hora de configurar tomcat, las indicaciones serán para tomcat 6.0.20, en tomcat 5.5 son idénticas pero puede variar la forma de establecer la variables JAVA_OPTS que es la que modificaremos. Bueno, todo lo que hay que hacer abrir D:tomcat-6.0.20-openmrsbincatalina.bat y modificar para que quede así, aproximadamente a la altura de la línea 78.


rem $Id: catalina.bat 750920 2009-03-06 14:43:19Z markt $
rem ---------------------------------------------------------------------------
set JAVA_OPTS=-Xverify:none -javaagent:D:JRebeljrebel.jar=org.openmrs.util.OpenmrsClassLoader,org.openmrs.module.ModuleClassLoader -Drebel.log=true -Xms512m -Xmx512m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m -XX:MaxPermSize=256m -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5000 %JAVA_OPTS%

rem Guess CATALINA_HOME if not defined
set CURRENT_DIR=%cd%
if not "%CATALINA_HOME%" == "" goto gotHom

Como se puede ver solo hemos agregado la variable de entorno JAVA_OPTS en la que activamos a Jrebel como agente utilizando los classloaders propios de openmrs, activamos el debugging para la aplicación, lo que será extremadamente útil aunque aquí no se explicará como hacer debugging en openmrs, y además modificamos la memoria asignada a la jvm para evitar problemas de memoria como el permGen, en fin.

Eso es todo dentro de tomcat. Ya podemos iniciarlo usando:

D:tomcat-6.0.20-openmrsbinstartup.bat

para ver los mensajes propios de JRebel, que deben verse aproximadamente así:

Bueno, eso significa que ya no hay nada más que hacer con la configuración de tomcat, ahora hay que configurar la aplicación OpenMRS agregando un archivo rebel.xml dentro de WEB-INFclasses. Podríamos hacerlo después de desplegar la aplicación en tomcat dirigiéndonos a webappsopenmrsWEB-INFclasses y copiando el archivo allí pero yo preferí modificar el build.xml que se encuentra en la raíz de openmrs-trunk para que copie éste archivo en la carpeta classes cuando compile la aplicación, aquí hay otra solución que se está proponiendo como parche para openmrs http://dev.openmrs.org/attachment/ticket/2106/jrebel-build.patch

Bueno, primero crearemos el rebel.xml

rebel.xml


<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://www.zeroturnaround.com"
 xsi:schemaLocation="http://www.zeroturnaround.com http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd">

<!-- supervision y actualizacion de clases y xml de configuracion de spring -->

<classpath>
 <dir name="D:openmrsopenmrs-trunkbuild"></dir>

<!--descomentar si estas teniendo problemas del tipo ClassNotFoundException en tomcat *
<jarset dir="D:openmrsopenmrs-trunklibjunit"></jarset>
 <jar name="D:openmrsopenmrs-trunklibspring-frameworkspring-test.jar"></jar>

-->

 <dir name="D:openmrspatientnotesbuild"></dir>

 </classpath>

 <web>

 <link target="WEB-INF/">
 <dir name="D:openmrsopenmrs-trunkwebWEB-INF">
 <exclude name="**/*.xml" />
 </dir>
 </link>

 <link target="WEB-INF/view/module/patientnotes/">
 <dir name="D:openmrspatientnoteswebmodule">
 <include name="**"/> <!-- nunca esta de mas -->
 <exclude name="**/*.xml" />
 </dir>
 </link>

 </web>
</application>

ahora copiamos este archivo dentro de D:openmrsopenmrs-trunkwebWEB-INF

y modificamos D:openmrsopenmrs-trunkbuild.xml a altura de la línea 335 (!) para que quede así:

</pre>
<classes file="${metadata.dir}/api/log4j/log4j.xml" />
 <classes file="${metadata.dir}/api/log4j/velocity.properties" />

 <!-- este es el unico cambio, podria ir en otra parte, notar que es un cambio improvisado, la ubicacion de rebel.xml se deberia configurar de manera externa-->
 <strong><classes file="web/WEB-INF/rebel.xml" /></strong>

 <classes dir="${build.dir}/liquibase-data">
 <include name="*" /> <!-- for the initial setup files: liquibase-schema-only.xml, liquibase-core-data.xml, liquibase-demo-data.xml-->
 </classes>

listo. Llegó la hora de probar, el flujo de instalación de openmrs y el módulo (patientnotes) podría parecer algo extraño, pero es la forma en la que he probado y que al parecer funciona con más frecuencia. Cabe destacar que existen varios factores por lo que derepente nos encontramos con que arrancamos tomcat, y funciona la actualización de jsp´s pero no de clases y pues, si somos observadores podremos detectar por qué suceden éstas cosas y como podemos manejarlas.

1. Iniciar eclipse (asumiré que ya instalaron openmrs-trunk, que lo han iniciado antes y que lo tienen importado en eclipse)

2. Importar proyecto patientnotes a eclipse

3. Activar Project > Build Automatically en eclipse

4. Ejecutar el target package-module del build.xml dentro de patientnotes

5. Copiar  patientnotes/dist/patientnotes-1.0.omod en C:Users ó Documents and setting en XPUsuarioApplication DataOpenMRSmodules

6. Hacer Project > Clean… para el proyecto patientnotes, si no se hace ésto algunas veces JRebel no actualizará clases.

7. Hacer un build dentro de eclipse para los proyecto que JRebel se encuentre manejando (IMPORTANTE, sobre todo si se ha hecho un clean con ant).

8. Iniciar tomcat

9. Reinstalar openmrs ejecutando los targets de ant: clean remove install en ese orden (asumiré que CATALINA_HOME apunta a D:tomcat-6.0.20-openmrs)

Listo, ahora ya podemos modificar controladores, incluso los marcados con anotaciones de spring, crear nuevas clases, modificar jsp’s, etc.

Pero hay un problema, al menos uno que yo he experimentado, las hojas de estilo y javascripts creados o modificados en nuestro proyecto no son sincronizados con el servidor, la solución que he encontrado ahora mismo para este problema es usar el target deploy-web dentro de build.xml de los módulos de openmrs, pero ya que no me gusta ejecutarlo manualmente creé un nuevo Builder de Eclipse, para que, aprovechando que tenemos activado build automatically en eclipse, cada vez que detecte cualquier cambio en nuestro proyecto (un módulo) ejecute deploy-web, no sé si existe una mejor manera de hacerlo, pero postearé esa solución después de experimentar un poco más.

NOTAS:

– He observado que algunas veces JRebel no reconoce los cambios en las clases cuando éste está supervisando muchos archivos, por ejemplo cuando lo configuré para que supervisara los cambios en una carpeta con dojo y muchos archivos dejó de funcionar, aunque no estoy seguro de que haya sido por esa razón.

Publicar web service jax-ws usando el módulo webservices.jaxws de OpenMRS

Antes que nada, siendo ésta la primera vez que hablaré sobre OpenMRS en el blog tengo que aclarar que aún no conozco muy bien este proyecto; hace algún tiempo andaba buscando un proyecto opensource sobre el cual trabajar para desarrollar un sistema de gestión de información hospitalaria/historia clínica electrónica para el hospital en el que trabajo y me topé con varios, uno en php llamado: OpenEMR el cual no he tenido la oprtunidad de investigar más a fondo, sobretodo porque en el trabajo estamos buscando una solución/proyecto más orientado a Java por la herramientas que tenemos disponibles para éste lenguage como Hibernate, Spring, etc.

En fin, así fue como di con OpenMRS que tiene una comunidad bastante activa, una lista de correo colaboradora y aunque todavía no se encuentra bastante documentación me pareció que es el punto por el cual dirigirse, realmente me gusta su comunidad, incluso hace poco realizaron una conferencia aquí en Peru (a la que no tuve la oportunidad de asistir). Y pues esto se ve bastante bueno.

En fin, ya me decidí a hacer algunas pruebas reales sobre OpenMRS, y pues a investigar como usar su API. Y a modo de ejemplo e introducción en éste artículo describiré como publicar información sobre los pacientes a través de un web service con jaxws dentro de openmrs como módulo, para ésto utilizaremos los siguientes módulos:

webservices.jaxws

webservicepatientstubexample

Antes que nada, si quieren probar ésto les recomendaría leer los siguientes artículos:

http://openmrs.org/wiki/Modules

http://openmrs.org/wiki/Creating_Your_First_OpenMRS_Module

http://openmrs.org/wiki/Administering_Modules

http://openmrs.org/wiki/Step-by-Step_Installation_for_Developers

Después de leer esos artículos ya tendrán un idea bastante completa sobre como:

Instalar openmrs (lo cual puede ser una tarea bastante abrumadora al comienzo si se encuentran detrás de un proxy, por ejemplo).

Crear un módulo de prueba, lo cual recomiendo altamente que hagan.

Y también sabrán como bajarse la fuente de los  módulos desde a través de svn (obligado entender subversion)

http://dev.openmrs.org/browser/openmrs-modules

http://dev.openmrs.org/browser/openmrs-modules/devexamples

Si ya leyeron todos esos artículos pues ya casi todo está hecho. Solo falta:

Empaquetar el módulo webservices.jaxws usando ant, subirlo a openmrs a través del administrador web de módulos

Empaquetar webservicepatientstubexample y subirlo a openmrs también…

Y si OpenMRS no emite ninguna alerta, entonces ya deberíamos ser capaces de consultar nuestro web service usando SoapUI con Basic Authorization.

http://localhost:8080/openmrs/ms/examplestubs/patientservice?wsdl

A continuación un ejemplo de una petición raw y la respuesta desde openMRS:


POST http://localhost:8080/openmrs/ms/examplestubs/patientservice HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
Authorization: Basic YWRtaWw6WG8wTuM1Nao=
User-Agent: Jakarta Commons-HttpClient/3.1
Host: localhost:8080
Content-Length: 445

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://web.webserviceexamplepatientstub.module.openmrs.org/">
 <soapenv:Header/>
 <soapenv:Body>
 <web:getPatients>
 <arg0></arg0>
 <arg1>121212</arg1>
 <arg2>
 <!--Zero or more repetitions:-->
 </arg2>
 <arg3>true</arg3>
 </web:getPatients>
 </soapenv:Body>
</soapenv:Envelope>
 

Y la respuesta:


<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
 <S:Body>
 <ns2:getPatientsResponse xmlns:ns2="http://web.webserviceexamplepatientstub.module.openmrs.org/">
 <return>
 <item>
 <familyName>Hablutze</familyName>
 <givenName>Jaime</givenName>
 <identfier>121212</identfier>
 <identifierTypeId>2</identifierTypeId>
 <middleName/>
 <patientId>4</patientId>
 <personId>4</personId>
 </item>
 </return>
 </ns2:getPatientsResponse>
 </S:Body>
</S:Envelope>

Si necesitas ayuda en alguna de las fases no dudes en contactarme, puedes dirigirte a la pestaña “Sobre el autor” por mi correo y nada, los comentarios son bienvenidos .)