DWR (Direct Web Remoting)es una librería Javascript que permite el uso de Ajax
(Asynchronous JavaScript and XML) de forma mucho más simple (Este artículo asume
que se entiende los conceptos de Ajax, y de Java).
DWR es una librería mas orientada a apoyar la integración, que a apoyar la parte
gráfica, de hecho si se buscan Widgets (objetos gráficos) esta no es la librería, pero por
otro lado lo fuerte de DWR es que permite “publicar” fácilmente funcionalidad de
clases Java para accederlas vía Javascript.
Ahora si se requiere además darle una interfaz más rica (rich interface) a los usuarios, es
bueno combinar DWR con otras librerías Ajax como YUI (Yahoo User Interface),
JQuery, Prototype, Scriptaculous, Dojo, o Spry.
Con Ajax se terminan las paginas JSP, o ASP (o deberían terminarse), porque Ajax solo
necesita Javascript y HTML para la parte de presentación, esto lo explicaremos mejor
en otro articulo, pero por ahora créannos. Y con DWR ni siquiera son necesarios los
Servlets, esto en el sentido de que no se necesitan desarrollar servlets para implementar
la lógica de negocio, porque DWR si internamente esta basado en Servlets, en otras
palabras gracias a DWR no necesitamos implementar nuestros servlets sino solo
necesitamos clases Java (POJO).
Si se conoce la tecnología Axis, que permite publicar clases Java como Webservices,
este es el símil para publicar clases Java como objetos Ajax (objetos Javascripts), de
hecho es muy fácil publicar con DWR un servicio realizado para Axis. Incluso las
buenas prácticas o blueprints de Axis para publicar clases como Webservices se aplican
totalmente para publicar clases para Ajax., ya que hay que tener los mismos cuidados en
cuanto a seguridad y manejo de desempeño (performance).
DWR permite a Javascript (en un Browser) interactuar con las clases Java en
un Servidor, y ayuda a manipular las paginas Web con los resultados.
Hemos llamado a este tutorial “el Mejor”, solo para llamar su atención, pero la verdad
es que es bastante bueno, por lo siguiente:
• Es lo mas simple posible, tiene lo justo y necesario para entender el concepto principal de DWR,
y como funciona.
3. A continuación se debe implementar la clase Java que va a ofrecer los servicios, esta basta que
sea un clase Java simple (POJO), con un constructor sin parámetros, y donde cada método de la
clase es un “potencial” servicio Ajax.
Esta clase va a estar del lado del servidor de aplicaciones (ejemplo: Tomcat,
JBoss, o Websphere) no necesariamente tiene que ser un servidor J2EE.
EasyService.java:
1. package com.soaagenda.services;
2.
3. import com.soaagenda.valueobjects.*;
4.
5. public class EasyService {
6. public EasyService() {
7. }
8.
9. public EasyResponse getProducts(EasyParameter parametersX){
10. EasyResponse responseX= new EasyResponse();
11.
12. // si parametros vacios devuelve error, error if empty parameters
13. if (parametersX==null || parametersX.getClientID()==null || parameter
sX.getClientID().length()< =0){
14. responseX.setErrorCode(10001);
15. responseX.setErrorDescription("Debe indicar ID Cliente. Give us Client
ID");
16. return responseX;
17. }
18.
19. //crea lista productos del cliente, fill the client product list
20. //para ejemplo en duro, for the example fixed data
21. Product[] productsListX= new Product[2];
22.
23. Product productX= new Product();
24. productX.setBarCode("0001");
25. productX.setName("Tarjeta Visa, Visa Credit Card");
26. productsListX[0]= productX;
27.
28. productX= new Product();
29. productX.setBarCode("0002");
30. productX.setName("Tarjeta American Express, American Express Credit
Card");
31. productsListX[1]= productX;
32.
33. //respuesta exitosa, sucessfull response
34. responseX.setErrorCode(0);
35. responseX.setErrorDescription("Consulta Banco Exitosa, Succesfull Bank
Query");
36. responseX.setProducts(productsListX);
37.
38. return responseX;
39. }
40. }
Este ejemplo simula una consulta de los productos bancarios de un cliente como
Tarjetas de Crédito (VISA, Master Card, Dinners, American Express), Cuentas
Corrientes, o Creditos de Consumo, para esto se le pasa como parámetro un
objeto que tiene el ID del cliente, y el tipo de producto a consultar, el servicio (o
método) devuelve otra clase con el código de error, mensaje de error, y la lista
de productos (un arreglo de clases producto).
4. También hay que definir las clases de datos (Value Objects) que va a utilizar el servicio, esta
clases deben ser javabeans (atributo privados, con getters y setters):
1. package com.soaagenda.valueobjects;
2.
3. public class EasyParameter {
4. private String clientID;
5. private String productType;
6. public EasyParameter() {
7. }
8.
9. public void setClientID(String clientID) {
10. this.clientID = clientID;
11. }
12.
13. public void setProductType(String productType) {
14. this.productType = productType;
15. }
16.
17. public String getClientID() {
18. return clientID;
19. }
20.
21. public String getProductType() {
22. return productType;
23. }
24. }
1. package com.soaagenda.valueobjects;
2.
3. public class EasyResponse {
4. private int errorCode;
5. private String errorDescription;
6. private Product[] products;
7.
8. public EasyResponse() {
9. }
10.
11. public void setErrorCode(int errorCode) {
12. this.errorCode = errorCode;
13. }
14.
15. public void setErrorDescription(String errorDescription) {
16. this.errorDescription = errorDescription;
17. }
18.
19. public void setProducts(Product[] products) {
20. this.products = products;
21. }
22.
23. public int getErrorCode() {
24. return errorCode;
25. }
26.
27. public String getErrorDescription() {
28. return errorDescription;
29. }
30.
31. public Product[] getProducts() {
32. return products;
33. }
34. }
1. package com.soaagenda.valueobjects;
2.
3. public class Product {
4. private String barCode;
5. private String name;
6. public Product() {
7. try {
8. jbInit();
9. } catch (Exception ex) {
10. ex.printStackTrace();
11. }
12. }
13.
14. private void jbInit() throws Exception {
15. }
16.
17. public void setBarCode(String barCode) {
18. this.barCode = barCode;
19. }
20.
21. public void setName(String name) {
22. this.name = name;
23. }
24.
25. public String getBarCode() {
26. return barCode;
27. }
28.
29. public String getName() {
30. return name;
31. }
32. }
5. Vamos a indicarle a DWR que clases vamos a publicar para Javascript (Ajax), esto se hace en el
archivo “dwr.xml”, y también corresponde a un esquema de seguridad porque podemos llegar a
especificar solo que métodos de una clase queremos exponer, y que atributos.
dwr.xml
6. Ahora si compilamos las clases, y publicamos nuestro ejemplo Web (deploy), DWR nos presta
una utilidad para probar que todo anda bien, esta se accede desde un Browser, en el path
“/dwr/”, dentro de nuestro sitio (ejemplo: http://localhost:8028/dwrEasy/dwr/)
Seleccionado el servicio, nos aparece primero las librerías javascript necesarias para
implementar una pagina Web, luego la lista de servicios (métodos de las clase servicio)
a los que tenemos acceso (getProducts).
Como no restringimos los métodos de la clase, incluso nos aparecen los métodos
que hereda por ser una clase Java (como hashCode, getClass).
7. Lo siguiente es crear nuestra pagina HTML que va a consultar los resultados y mostrarlos, esta
pagina es sumamente simple, tiene un formulario (Html Form), en realidad solo tiene las
variables del form, porque ya no es necesario el tag “<form>” (recuerden que con Ajax la forma
de hacer request al Server cambia, ahora es asíncrona), y tiene una tabla (html table) para
mostrar el resultado.
dwrEasyPage.html
Podemos ver que hay ciertas características especiales en el código Html, estas
le van a servir a DWR para encontrar donde obtener, o donde mostrar los datos:
Los “Id” de los tags html le sirven a DWR para manejar los datos:
dwrEasyJS.js
view plaincopy to clipboardprint?
1. function submitProductsRequest() {
2. var idX=dwr.util.getValue("formClientID");
3. var typeX=dwr.util.getValue("formProductType");
4.
5. var parametersX={clientID:idX,productType:typeX};
6.
7. EasyService.getProducts(parametersX,showProducts);
8.
9. }
10.
11. function showProducts(responseX) {
12.
13. // borro filas excepto el patron, delete rows except pattern row
14. dwr.util.removeAllRows("myTable", { filter:function(tr) { return (tr.id !
= "myPattern");}});
15.
16. if (responseX.errorCode!=0){
17. alert('Error: '+responseX.errorDescription);
18. return;
19. };
20. var productsX=responseX.products;
21. var lengthX=productsX.length;
22. var itemProductX;
23.
24. if (lengthX==0){
25. alert('No hay productos, Cant find products');
26. return;
27. };
28.
29. dwr.util.setValue("serviceResponse", responseX.errorDescription);
30.
31. var id="00";
32. for (var i=0 ; i<lengthx ; i++)
33. {
34. temProductX= productsX[i];
35. id="00"+i;
36. dwr.util.cloneNode("myPattern", { idSuffix:id });
37. dwr.util.setValue("codePattern" + id, itemProductX.barCode);
38. dwr.util.setValue("namePattern" + id, itemProductX.name);
39. $("myPattern" + id).style.display = "";
40. }
41. }
9. Esta librería tiene dos funciones: “submitProductsRequest” la que obtiene los parámetros de
entrada y ejecuta el servicio correspondiente (clase Java EasyService.getProducts() vía DWR), y
la función que muestra los datos (showProducts).
Finalmente hay que subir las páginas (Deploy) en el sitio Web, quedando el
proyecto con la siguiente estructura:
.
*******************************************************************
Volviendo otra vez al proyecto actual en el que estamos asignados Dani Gonzalez y yo,
nos hemos encontrado con que las versiones de Portlet y de JSF utilizadas no permiten
el uso de componentes con comportamiento AJAX. En versiones posteriores estos
problemas tienen solución e incluso existen librerías de componentes JSF muy potentes
en este sentido (ICE Faces, RichFaces, Oracle ADF) pero como todos os imagináis a los
dueños de una aplicación no suele gustarles que les digas que vas a invertir un
tiempecito migrando a una nueva versión de algo que no conocen y que además para
utilizarla es necesario cambiar la versión del servidor de aplicaciones en producción…
así que hemos tenido que “invertar” alguna cosa, para dar ese comportamiento dinámico
que nos requería el usuario final. Concretamente la primera petición de nuestros
usuarios vino para recuperar la irradiación (cantidad de sol recibido por un punto de la
superficie terrestre) a partir de las coordeandas seleccionadas por el usuario en un mapa
(en este caso generado con Google Maps) sin necesidad de realizar un submit y recargar
toda la página…
Estuvimos viendo distintas alternativas como dojo (aunque se caracteriza más por su
librería de componentes gráficos javascript también tiene funcionalidad para realizar
llamadas ajax), prototype, el uso del objeto XMLHttpRequest, y otros aunque
finalmente nos decidimos por DWR dada la facilidad con la que se puede utilizar en un
entorno Java. En realidad, después de un poco de tiempo trabajando con DWR coincido
bastante con la forma en que ellos se definen en su site: “DWR es una librería java que
permite al código java ejecutado en un servidor de aplicaciones y al código Javascript
ejecutado en un navegador interactuar entre ambos de la manera más simple posible” y
su eslogan es: “DWR is Easy Ajax for Java”
Bueno, a grandes rasgos nos encontramos con dos piezas que son necesarias para que
esto funcione:
• Un servlet java ejecutándose en el servidor que procesa las peticiones Ajax recibidas y
devuelve la respuesta al navegador
• Una librería javascript en el navegador utilizada para enviar peticiones al servidor y recibe
las respuestas desde éste para actualizar la página que se muestra
• DWR genera dinámicamente el código javascript para que cada una de las clases java de
servidor expuestas como servicios AJAX puedan ser accedidas desde javascript. Es decir el
javascript generado por DWR crea un objeto javascript que puede ser referenciado desde
cualquier parte de nuestro código js en el navegador.
• El objeto creado se encarga de abstraernos de la comunicación con el servidor. Cuando se
invoca a alguno de los métodos javascript ofrecidos se desencadena una llamada al
servidor en la que DWR se encarga del envío y recepción (marshalling / unmarshalling) de
los parámetros de forma transparente.
Si queréis ver un ejemplo muy sencillo de lo que hay que hacer para poner esto a
funcionar podéis ir a un tutorial en la página oficial de DWR
A partir de la versión 2 (la actual es la 3) ofrece una funcionalidad que ellos llaman
“reverse ajax” que permite realizar acciones “push” al estilo comet… También ofrecen
dentro de la librería javascript un conjunto de funciones de utilidad para manejar los
objetos HTML / JS en cliente / navegador. Y parece que también están trabajando en
integrarse con algunos frameworks de componentes de interfaz de usuario como Dojo o
Yahoo YUI .
Molto più che documenti.
Scopri tutto ciò che Scribd ha da offrire, inclusi libri e audiolibri dei maggiori editori.
Annulla in qualsiasi momento.