via Raj Blogs
viernes, septiembre 30, 2005
martes, agosto 30, 2005
DWR y Spring
DWR (Direct Web Remoting) o "Easy AJAX for Java" es una biblioteca para facilitar la utilización de AJAX. Y con AJAX (Asynchronous JavaScript And XML for Web GUI processing) podemos actualizar una página web sin necesidad de gets y posts, eliminando el correspondiente "roundtrip" al servidor y refrescos de páginas, logrando una interfaz similar a cualquier aplicación desktop.
DWR expone métodos de una clase Java utilizando Javascript, permitiendo asi su acceso desde cualquier página web (HTML/JSP/etc):

¿Pero cómo se configura DWR y cómo logramos que esa clase Java sea un bean de Spring?
Luego de copiar dwr.jar al servidor, configuraremos DWR en el WEB-INF/web.xml de la aplicación:
Luego crearemos un fichero WEB-INF/dwr.xml donde especificaremos qué métodos de qué beans queremos "exponer" mediante dwr, y que beans van a servir de transporte de datos y por lo tanto dwr debe convertir.
Por ejemplo, si queremos llenar una lista desplegable con categorías (paises, por ejemplo) y otra dependiente de esta (ciudades), necesitamos dos métodos de un bean Java (ciudadesManager), y un DTO para transferencia de datos (ListBean).
Consecuentemente, en nuestro beans.xml estará el bean ciudadesManager:
Llegados a este punto, lo que queda es desarrollar la página de nuestra aplicación, y para ello deberemos incluir el javascript necesario para acceder al ciudadesManager (recordando actualizar el [appfolder]:
El primer include corresponde al javascript que DWR generará automaticamente para nuestro bean ciudadesManager, el segundo es el core de DWR, y el tercero una serie de utilidades para manipular controles html, como gets y sets de propiedades.
Las funciones javascript necesarias para acceder remotamente a los métodos del bean se dividen en dos: uno que hace la llamada y otro de callback. Asi, para llenar la lista de paises crearemos las funciones execPaises y fillPaises, y para llenar la lista de ciudades execCiudades y fillCiudades:
La primer funcion, execPaises, la llamaremos al inicio de la página, dentro del onLoad del body. Al ejecutarse, llamará al método getPaises de ciudadesManager y el resultado lo tendremos en la función que le pasemos como parámetro, en este caso fillPaises.
Dentro de fillPaises utilizaremos la función DWRUtil.fillList para rellenar la lista desplegable cuyo id es paises con la lista de datos recibidos, diciéndole cuál propiedad corresponde al código y cuál a la descripción.
Análogamente, la función execCuidades estará en el onChange de la lista paises, y cuando se ejecute (cada vez que cambiemos de pais) borrará todas las opciones de la lista ciudades y ejecutará el método getCiudades, pasando como parámetro el value de la lista paises (el pais elegido).
El código de las listas quedará asi:
Solo nos queda codificar el bean ciudadesManager y el DTO. El manager obtiene la lista de paises o ciudades utilizando un DAO y las trasnfiera al DTO. Cabe señalar que podríamos utilizar directamente los beans Pais y Ciudad y transferirlos a la página, pero estas clases suelen tener muchas mas propiedades que no utilizaríamos y penalizaría la performance. De cualquier modo dependerá de vuestra propia aplicación como hacerlo, esta es solamente una forma mas.
Si todo ha sido configurado correctamente, el resultado será una lista desplegable de paises que se llena al cargar la página:

y una lista desplegable de ciudades que se refresca cada vez que cambiamos la primera:
Y todo sin que se refresque la página.
En el sitio de DWR hay numerosos ejemplos de como utilizarlo para diversas tareas, como editar tablas y formularios o validar datos, solo hace falta animarse.
DWR expone métodos de una clase Java utilizando Javascript, permitiendo asi su acceso desde cualquier página web (HTML/JSP/etc):
¿Pero cómo se configura DWR y cómo logramos que esa clase Java sea un bean de Spring?
Luego de copiar dwr.jar al servidor, configuraremos DWR en el WEB-INF/web.xml de la aplicación:
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<description>Direct Web Remoter Servlet</description>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
Luego crearemos un fichero WEB-INF/dwr.xml donde especificaremos qué métodos de qué beans queremos "exponer" mediante dwr, y que beans van a servir de transporte de datos y por lo tanto dwr debe convertir.
Por ejemplo, si queremos llenar una lista desplegable con categorías (paises, por ejemplo) y otra dependiente de esta (ciudades), necesitamos dos métodos de un bean Java (ciudadesManager), y un DTO para transferencia de datos (ListBean).
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 0.4//EN"
"http://www.getahead.ltd.uk/dwr/dwr.dtd">
<dwr>
<allow>
<create creator="spring" javascript="ciudadesManager" beanName="ciudadesManager">
<include method="getPaises"/>
<include method="getCiudades"/>
</create>
<convert converter="bean" match="com.package.ListBean" />
</allow>
</dwr>
Consecuentemente, en nuestro beans.xml estará el bean ciudadesManager:
<bean id="ciudadesManager" class="com.package.ciudadesManager">
<property name="paisesDAO" ref="paisesDAO"/>
<property name="ciudadesDAO" ref="ciudadesDAO"/>
</bean>
Llegados a este punto, lo que queda es desarrollar la página de nuestra aplicación, y para ello deberemos incluir el javascript necesario para acceder al ciudadesManager (recordando actualizar el [appfolder]:
<script type='text/javascript' src='/[appfolder]/dwr/interface/ciudadesManager.js'></script>
<script type='text/javascript' src='/[appfolder]/dwr/engine.js'></script>
<script type='text/javascript' src='/[appfolder]/dwr/util.js'></script>
El primer include corresponde al javascript que DWR generará automaticamente para nuestro bean ciudadesManager, el segundo es el core de DWR, y el tercero una serie de utilidades para manipular controles html, como gets y sets de propiedades.
Las funciones javascript necesarias para acceder remotamente a los métodos del bean se dividen en dos: uno que hace la llamada y otro de callback. Asi, para llenar la lista de paises crearemos las funciones execPaises y fillPaises, y para llenar la lista de ciudades execCiudades y fillCiudades:
<script>
function execPaises() {
ciudadesManager.getPaises(fillPaises);
}
function fillPaises(data) {
DWRUtil.fillList('paises', data, 'key', 'value');
}
function execCiudades() {
DWRUtil.removeAllOptions('ciudades');
ciudadesManager.getCiudades(fillCiudades, DWRUtil.getValue('paises'));
}
function fillCiudades(data) {
DWRUtil.fillList('ciudades', data, 'key', 'value');
}
</script>
La primer funcion, execPaises, la llamaremos al inicio de la página, dentro del onLoad del body. Al ejecutarse, llamará al método getPaises de ciudadesManager y el resultado lo tendremos en la función que le pasemos como parámetro, en este caso fillPaises.
Dentro de fillPaises utilizaremos la función DWRUtil.fillList para rellenar la lista desplegable cuyo id es paises con la lista de datos recibidos, diciéndole cuál propiedad corresponde al código y cuál a la descripción.
Análogamente, la función execCuidades estará en el onChange de la lista paises, y cuando se ejecute (cada vez que cambiemos de pais) borrará todas las opciones de la lista ciudades y ejecutará el método getCiudades, pasando como parámetro el value de la lista paises (el pais elegido).
El código de las listas quedará asi:
<select id="paises" onChange="execCiudades();"></select>
<select id="ciudades"></select>
Solo nos queda codificar el bean ciudadesManager y el DTO. El manager obtiene la lista de paises o ciudades utilizando un DAO y las trasnfiera al DTO. Cabe señalar que podríamos utilizar directamente los beans Pais y Ciudad y transferirlos a la página, pero estas clases suelen tener muchas mas propiedades que no utilizaríamos y penalizaría la performance. De cualquier modo dependerá de vuestra propia aplicación como hacerlo, esta es solamente una forma mas.
public class CiudadesManager {
private DAO paisesDAO = null;
private DAO ciudadesDAO = null;
public Object[] getPaises() {
List objects = getPaisesDAO().findByNamedQuery("allPaises");
List list = new ArrayList();
for (Iterator it=objects.iterator(); it.hasNext(); ) {
Pais pais = (Pais)it.next();
ListBean bean = new ListBean(pais.getCodigo(), pais.getNombre());
list.add(bean);
}
return list.toArray();
}
public Object[] getCiudades(String idPais) throws BusinessException {
List objects = getCiudadesDAO().findByNamedQuery("byPais", new Object[]{idPais});
List list = new ArrayList();
for (Iterator it=objects.iterator(); it.hasNext(); ) {
Ciudad ciudad = (Ciudad)it.next();
ListBean bean = new ListBean(ciudad.getCodigo(), ciudad.getNombre());
list.add(bean);
}
return list.toArray();
}
public DAO getPaisesDAO() {return paisesDAO;}
public void setPaisesDAO(DAO paisesDAO) {this.paisesDAO = paisesDAO;}
public DAO getCiudadesDAO() {return ciudadesDAO;}
public void setCiudadesDAO(DAO ciudadesDAO) {this.ciudadesDAO = ciudadesDAO;}
}
public class ListBean {
private String key = null;
private String value = null;
public ListBean (String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {return key;}
public String getValue() {return value;}
public void setKey(String key) {this.key = key;}
public void setValue(String value) {this.value = value;}
}Y todo sin que se refresque la página.
En el sitio de DWR hay numerosos ejemplos de como utilizarlo para diversas tareas, como editar tablas y formularios o validar datos, solo hace falta animarse.
jueves, agosto 11, 2005
Mule
Con el auge de SOA estuve experimentando con Mule como parte de la estrategia opensource de un cliente.
Resulta admirable que con tan solo (o casi solo) una configuración similar a esta:
Este mensaje puede ser reenviado mediante diversos medios de transporte, como JMS (en mi caso), archivos, ftp, http, soap, pop/smtp.
Muy útil, como se ve, para "conectar" sistemas muy dispares y "orquestar" el buen funcionamiento entre ellos.
Resulta admirable que con tan solo (o casi solo) una configuración similar a esta:
se pueda exponer un servicio via webservices, el cual derivará el mensaje a una lista (StaticRecipientList) de destinos que proveerá la implementación (ServiceDomainRouterImpl).
<bean id="domainRouterEP" class="org.mule.impl.endpoint.MuleEndpoint">
<property name="endpointURI">
<bean class="org.mule.impl.endpoint.MuleEndpointURI">
<constructor-arg value="axis:http://${broker.host}:${broker.ws.port}/router"/>
</bean>
</property>
<property name="synchronous" value="true"/>
</bean>
<bean id="serviceDomainRouter" class="org.mule.impl.MuleDescriptor">
<property name="inboundEndpoint" ref="domainRouterEP"/>
<property name="outboundRouter">
<bean class="org.mule.routing.outbound.OutboundMessageRouter">
<property name="routers">
<list>
<bean class="org.mule.routing.outbound.StaticRecipientList"/>
</list>
</property>
</bean>
</property>
<property name="implementation" value="serviceDomainRouterImpl"/>
<property name="properties">
<map>
<entry key="axisOptions">
<map>
<entry key="wsdlServiceElement" value="RouterService"/>
<entry key="wsdlPortType" value="RouterPort"/>
</map>
</entry>
<entry key="serviceInterfaces">
<list>
<value>broker.router.ServiceDomainRouter</value>
</list>
</entry>
</map>
</property>
</bean>
<bean id="serviceDomainRouterImpl" class="broker.router.impl.ServiceDomainRouterImpl"
singleton='false'>
<property name="hub" value="${broker.hub}"/>
<property name="directory" ref="directory"/>
<property name="schemaFileName" value="request-schema.xsd"/>
</bean>
Este mensaje puede ser reenviado mediante diversos medios de transporte, como JMS (en mi caso), archivos, ftp, http, soap, pop/smtp.
Muy útil, como se ve, para "conectar" sistemas muy dispares y "orquestar" el buen funcionamiento entre ellos.
lunes, febrero 14, 2005
Utilización de EJBs en Spring
Desde su introducción en la especificación EJB 2.0 en Septiembre 2001, las interfaces locales de los EJBs han probado ser de gran valor para el desarrollador.
Eliminan la obligatoriedad de distribuir nuestros objetos (ya que solo en algunos pocos casos es necesario), con la consiguiente mejora de performance, y por lo tanto eliminan la necesidad de lidiar con RemoteException en cada método. Es de destacar también que las interfaces locales utilizan llamadas por referencia, a diferencia de utilizar llamadas por valor (copias de objetos serializados) en la interfaz remota. Para ello, el servidor de aplicaciones instancia nuestros EJBs en la misma JVM que, por ejemplo, la capa de presentación web desde donde son llamados.
Pero no todo es color de rosa con los EJBs, ya que seguimos teniendo clases que son difíciles de probar (con JUnit, por ejemplo), y seguimos teniendo el añadido (en contraposición a utilizar POJOs para nuestros objetos de negocio) de complicar el desarrollo con interfaces y descriptores.
Pero veamos como utilizar Spring para simplificar el desarrollo en el caso que no poder reemplazar los EJBs por POJOs + AOP/ORM/JDBC.
Para utilizar un EJB tradicionalmente se ocultan las búsquedas JNDI detrás de un Service Locator que nos devuelve un objeto EJB Home, el cual a su vez utilizamos para obtener el EJB real (local o remoto) mediante una llamada al método create.
Esto no nos libra de tener que implementar también un Business Delegate para despegar al cliente de la utilización directa de la API de EJB, y por lo tanto de las RemoteException lanzadas por su método de networking.
El método de Spring para simplificar lo anteriormente expuesto es la utilización de proxys dentro del ApplicationContext, que nos libran de escribir un nuevo Service Locator y/o Business Delegate para nuestro objeto de negocio.
Utilizando el mismo ejemplo que la documentación de Spring, lo primero que haremos será seguir las buenas prácticas y construir una Business Methods Interface para nuestro componente. Este patrón nos asegura una correcta sincronización entre el nuestro objeto de negocio y la interfaz (local o remota), ya que ambos implementan la misma Business Method Interface. Otra razón para utilizar este patrón, es que nos será mas fácil intercambiar una implementación EJB por otra POJO, si mas adelante lo consideramos necesario:
Ante cada llamada del cliente a myComponent, Spring hará la llamada correspondiente a create para obtener el EJB y al correspondiente método en el objeto de negocio.
Si por cualquier razón queremos cambiar la implementación del objeto de negocio de un EJB a un POJO, simplemente cambiamos la definición del bean en Spring sin necesidad de tocar una sola linea de código en el cliente:
Actualización: El artículo Pro Spring: Spring and EJB (en inglés) presenta el mismo tema en forma mucho mas extensa.
Eliminan la obligatoriedad de distribuir nuestros objetos (ya que solo en algunos pocos casos es necesario), con la consiguiente mejora de performance, y por lo tanto eliminan la necesidad de lidiar con RemoteException en cada método. Es de destacar también que las interfaces locales utilizan llamadas por referencia, a diferencia de utilizar llamadas por valor (copias de objetos serializados) en la interfaz remota. Para ello, el servidor de aplicaciones instancia nuestros EJBs en la misma JVM que, por ejemplo, la capa de presentación web desde donde son llamados.
Pero no todo es color de rosa con los EJBs, ya que seguimos teniendo clases que son difíciles de probar (con JUnit, por ejemplo), y seguimos teniendo el añadido (en contraposición a utilizar POJOs para nuestros objetos de negocio) de complicar el desarrollo con interfaces y descriptores.
Pero veamos como utilizar Spring para simplificar el desarrollo en el caso que no poder reemplazar los EJBs por POJOs + AOP/ORM/JDBC.
Para utilizar un EJB tradicionalmente se ocultan las búsquedas JNDI detrás de un Service Locator que nos devuelve un objeto EJB Home, el cual a su vez utilizamos para obtener el EJB real (local o remoto) mediante una llamada al método create.
Esto no nos libra de tener que implementar también un Business Delegate para despegar al cliente de la utilización directa de la API de EJB, y por lo tanto de las RemoteException lanzadas por su método de networking.
El método de Spring para simplificar lo anteriormente expuesto es la utilización de proxys dentro del ApplicationContext, que nos libran de escribir un nuevo Service Locator y/o Business Delegate para nuestro objeto de negocio.
Utilizando el mismo ejemplo que la documentación de Spring, lo primero que haremos será seguir las buenas prácticas y construir una Business Methods Interface para nuestro componente. Este patrón nos asegura una correcta sincronización entre el nuestro objeto de negocio y la interfaz (local o remota), ya que ambos implementan la misma Business Method Interface. Otra razón para utilizar este patrón, es que nos será mas fácil intercambiar una implementación EJB por otra POJO, si mas adelante lo consideramos necesario:
public interface MyComponent {
...
}Luego expondremos una propiedad en el objeto cliente (un web controller en el ejemplo de Spring):private MyComponent myComponent;y finalmente configuraremos las dependencias en el xml de configuración de Spring:
public void setMyComponent(MyComponent myComponent) {
this.myComponent = myComponent;
}
<bean id="myComponent"Lo que sucede luego, es que Spring (gracias a AOP) crea un proxy para el EJB, el cual implementa dinámicamente nuestra Business Methods Interface (MyComponent) y hace las búsquedas JNDI necesarias para encontrar el EJB Local Home (el cual pone en cache).
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
<property name="jndiName"><value>myComponent</value></property>
<property name="businessInterface"><value>com.mycom.MyComponent</value></property>
</bean>
<bean id="myController" class="com.mycom.myController">
<property name="myComponent"><ref bean="myComponent"/></property>
</bean>
Ante cada llamada del cliente a myComponent, Spring hará la llamada correspondiente a create para obtener el EJB y al correspondiente método en el objeto de negocio.
Si por cualquier razón queremos cambiar la implementación del objeto de negocio de un EJB a un POJO, simplemente cambiamos la definición del bean en Spring sin necesidad de tocar una sola linea de código en el cliente:
<bean id="myComponent"Esta facilidad para cambiar de EJBs a POJOs, sugiere que es posible, en una aplicación existente que utiliza extensivamente EJBs, ir reemplazando primero la infraestructura de configuración de dependencias, luego la de acceso a los objetos de negocio y finalmente la implementación misma de estos objetos. Asi resulta mucho menos traumático para el equipo de desarrollo, y menos estresante para la dirección.
class="com.example.MyBusinessObject">
</bean>
Actualización: El artículo Pro Spring: Spring and EJB (en inglés) presenta el mismo tema en forma mucho mas extensa.
miércoles, febrero 09, 2005
Libros de Spring
Al mismo tiempo que el valor de Spring comienza a ser reconocido y es adoptado en las empresas, nuevos libros hacen su aparición y ayudan al proceso.
Hasta el momento:
Spring Live (€33.60 o €23.40 digital)
Spring in Action (€23.20)
Pro Spring (€23.21)
Spring Live es para iniciarse en el framework y es un libro eminentemente "práctico", casi un tutorial de alto nivel. Y tiene la ventaja de que si compramos la versión digital, obtenemos actualizaciones y nuevos capítulos en forma periódica.
Los otros dos libros son muy recientes, pero los comentarios que he oído dicen que son de libros para usuarios mas avanzados.
Y por ahora están solamente en inglés.
Hasta el momento:
Spring Live (€33.60 o €23.40 digital)
Spring in Action (€23.20)
Pro Spring (€23.21)
Spring Live es para iniciarse en el framework y es un libro eminentemente "práctico", casi un tutorial de alto nivel. Y tiene la ventaja de que si compramos la versión digital, obtenemos actualizaciones y nuevos capítulos en forma periódica.
Los otros dos libros son muy recientes, pero los comentarios que he oído dicen que son de libros para usuarios mas avanzados.
Y por ahora están solamente en inglés.
martes, febrero 08, 2005
El Patrón Business Methods Interface
Un problema que tenemos al desarrollar EJBs es el de sincronizar los métodos de la interfaz local o remota con los métodos de la implementación.
Ya que la interfaz y el EJB tienen una jerarquía diferente, se da comunmente el caso en el cual la interfaz tiene una firma determinada para un método, pero el EJB otra.
Para solucionar el problema y capturar esta incoherencia en tiempo de desarrollo (en la compilación), se utiliza comunmente el patrón llamado Business Methods Interface. En este patrón la interface (local o remota) y la implementación (el EJB) implementan la misma interface (business methods).

Por ejemplo, si quisiéramos implementar ciertas funcionalidades de negocio en un EJB con interfaz local, crearíamos primero una Business Methods Interface, donde definiríamos nuestro métodos de negocio:
De esta forma queda asegurada en tiempo de compilación la integridad de ambos componentes entre si.
Ya que la interfaz y el EJB tienen una jerarquía diferente, se da comunmente el caso en el cual la interfaz tiene una firma determinada para un método, pero el EJB otra.
Para solucionar el problema y capturar esta incoherencia en tiempo de desarrollo (en la compilación), se utiliza comunmente el patrón llamado Business Methods Interface. En este patrón la interface (local o remota) y la implementación (el EJB) implementan la misma interface (business methods).
Por ejemplo, si quisiéramos implementar ciertas funcionalidades de negocio en un EJB con interfaz local, crearíamos primero una Business Methods Interface, donde definiríamos nuestro métodos de negocio:
public interface MyBusinessInterface {
public void myBusinessMethod1 ( ... );
...
}y en base a ella crearíamos el EJB, con la implementación de estos métodos:
import javax.ejb.SessionBean;y por último la interfaz local, extendiendo también de MyBusinessInterface:
public class ExampleEJB implements SessionBean,
MyBusinessInterface {
public void myBusinessMethod1 ( ... ) {
...
}
...
}
import javax.ejb.EJBLocalObject;En el caso de necesitar una interfaz remota, los métodos de la Business Methods Interface deberían lanzar RemoteException, tal como es requerido por la especificación de EJB.
public interface ExampleLocal extends EJBLocalObject,
MyBusinessInterface {
}
De esta forma queda asegurada en tiempo de compilación la integridad de ambos componentes entre si.
sábado, febrero 05, 2005
Inversión de Control e Inyección de Dependencias
Gracias este post de Joaquin, me he enterado que Juan Antonio ha puesto en Java en Castellano la traducción del artículo de Martin Fowler Inversion of Control Containers and the Dependency Injection pattern.
Suscribirse a:
Entradas (Atom)