1 July, 2010

Aprendiendo a desarrollar con tests

El proyecto en el que trabajo actualmente es mi primera experiencia mas o menos seria con el desarrollo orientado a tests. Al principio los escribía después de implementar la funcionalidad requerida, pero por recomendación de un compañero pasé a escribirlos antes (TDD). Escribes el test que falla porque todavía no tienes implementada la funcionalidad que lo hace pasar, implementas la funcionalidad para que pase el test, y le das las vueltas que necesites a tu código (para hacerlo mas legible o eficiente) si el test pasa tu código es válido.

Cuesta iniciarse en esta forma de desarrollo, cuesta escribir buenos tests, cuesta mantenerlos, pero como se suele decir es una inversión con retorno y me estoy convenciendo de que estos son imprescindibles para profesionalizar en gran parte nuestro trabajo. Es mas, ahora me acuerdo de algunos proyectos en los que trabajé anteriormente y lo bien que nos habrían venido en el testeo de algunos procesos complejos, la de tiempo que habría ahorrado y sobre todo la tranquilidad que habría aportado al equipo.

De todas formas, aun tenemos algunas lagunas, por lo menos yo no tengo nada claro como se debe mantener un juego de datos coherente con el que hacer pasar los tests, sin que esto lleve mas tiempo que beneficio, por el momento tenemos 2 aproximaciones:
- Almacenar con dbunit un juego de datos (xml, cvs, etc) con unos identificadores reservados (por ej de 1 a 500), e importarlos a BD cada vez que pasemos los tests.
- Usar una BD independiente contra la que ejecutar los tests.
Usaremos la segunda opción aunque insisto, no tengo una postura clara sobre el tema y no termina de convencerme.

Hay quien dice que lo mejor es tener los X registros que necesitamos en xml para cada test de forma independiente, solo esos X registros ni uno mas ni uno menos. Me gusta la idea de tener muy controlados los registros que pruebas y que todo el equipo los conozca, del identificador 1 al 20 entidad en Y estado, del 20 al 40 en Z estado etc etc.

Al final escribir y mantener tests y sus datos de prueba no es gratis, lleva tiempo y creo que no solo cuando empiezas, pero debes convecerte de que es la forma de garantizar un software de calidad, de desarrollar con tranquilidad sabiendo que si haces algo que afecte a otra parte del sistema te vas a enterar antes que tu cliente. No creo que se escriban tests para hacer el desarrollo mas rápido sino para hacerlo mejor.

Recomiendo especialmente un par de podcasts de javahispano sobre el tema:

http://www.javahispano.org/contenidos.item.action?id=1985256&menuId=JH_PODCASTS

http://www.javahispano.org/contenidos.item.action?id=6813316&menuId=JH_PODCASTS

Y habrá que seguir leyendo y buscar mas opiniones de gente con experiencia.

29 June, 2009

Api gxt rc1: cierre y ocultamiento de ventanas

Pasamos a probar la nueva rc1 de gxt2.0.

Sorpresón, las ventanas ya no se cierran, solo se ocultan, y claro esto ya ha provocado debate. Explican que ellos las eliminarán completamente en cuanto se pierda la referencia. Hasta aquí (aunque no acabo de entender el porqué del cambio, bien podrían haber mantenido el close por si la quiero destruir yo mismo! e implementar igualmente el mecanismo de liberación de memoria de los objetos no usados) tampoco voy a reprocharles nada.

Ahora, tengo una ventana, con los 3 típicos botones: minimiza, maximiza, cierra. Necesito de alguna forma distinguir el evento de cierre del de minimizar. Hasta ahora simplemente se implementaban 2 listeners diferentes: windowHide, windowClose. Pero como decimos windowClose desaparece, hemos de buscar otra forma alternativa de diferenciar entre un cierre y un hide, y por defecto el evento generado por botón close de las ventanas no nos da el botón que hemos pulsado, supongo que se les ha escapado.

Finalmente veo 2 opciones:

La primera y mas sencilla es pasar algún parámetro a la ventana en el momento del ocultamiento/mimización (navegando a los fuentes del sistema MDI que implementa gxt veo que esta es la opción que utilizan), por ejemplo:

  1. setData("minimize", true);

y ya en el evento hide comprobar si la ventana ha sido mimizada o por el contrario está cerrada.

  1. public void windowHide(WindowEvent we) {
  2.    boolean minimize = getData("minimize");
  3.    if(!minimize)
  4.    {// Si minimize es false es que la hemos cerrado =>
  5.      // hacemos lo que necesitemos, por ejemplo eliminar un boton de la barra de tareas
  6.    }
  7. }

Y la segunda:
Ya que como deciamos el evento generado por el botón close de la ventana no nos ofrece el botón pulsado, vamos a ocultar los botones por defecto de la ventana y añadir los nuestros.

Primero ocultamos los botones "por defecto":

  1. setMinimizable(false);
  2. setMaximizable(false);
  3. setClosable(false);

Ahora añadimos nuestros propios botones, y para close nuestro propio evento pasando un botón (creado exclusivamente con este fin) al método hide, ya que hide solo puede recibir Button y no ToolButton:

  1. final ToolButton closeBtn = new ToolButton("x-tool-close");
  2. closeBtn.addListener(Events.Select, new Listener<ComponentEvent>() {
  3.    public void handleEvent(ComponentEvent ce) {
  4.       // Buff, el hide solo recibe un Button no un ToolButton, q coñazo!! =>
  5.       // creamos un botón simplemente para pasarlo como argumento
  6.       // y saber que estamos cerrando la ventana
  7.       Button buttonCloseTmp = new Button("close-window");
  8.       buttonCloseTmp.setId("close-window");
  9.       hide(buttonCloseTmp);
  10.    }
  11. });
  12.  
  13. window.getHeader().addTool(closeBtn);

Y ahora si, en el evento generado por el ocultamiento de una ventana podemos diferenciar cuando la estamos cerrando o cuando la estamos enviando por ejemplo, a la barra de tareas:

  1. @Override
  2. public void windowHide(WindowEvent we) {
  3.    if (we.getButtonClicked() != null) {
  4.       if (we.getButtonClicked().getId().equals("close-window")) {
  5.          // sabemos que hemos pulsado el botón de cierre de la ventana =>
  6.          // hacemos lo que necesitemos, por ejemplo eliminar un boton de la barra de tareas
  7.       }
  8.    }
  9. }

En fin, que no acabo de entender porque eliminan la funcionalidad del close, como decía sería mejor mantenerla e implementar además el mecanismo de liberación de memoria. Se mantendría la compatibilidad y podríamos diferenciar de una forma mas lógica y fiable cuando se produce el cierre, ya que son dos operaciones claramente diferenciadas.

30 April, 2009

Mas cosas sobre gwt y derivados

A ver por donde empiezo, que son muchas las novedades/experiencias acumuladas los últimos días sobre gwt, buenas y no tan buenas:

SmartClient

1- El rendimiento de smartclient, sobre todo en ie y equipos poco potentes, deja bastante que desear. Especialmente utilizando grids con muchas columnas. Varios fueron los intentos por solucionarlo: precargar imágenes antes de mostrar componente, activar caché, hacer rollover sobre color de fondo y no sobre imagen, setShowAllRecords(false), personalizar estilo filas setBaseStyle("estilo_filas_grid"). En fin, que no soy el único quejica, aqui un hilo significativo en los foros, el problema parece que está en la raíz.

2- Soporte: 2 caras 1 cruz

Dos problemas de maquetación, y dos envíos a los foros de smartclient.

Cara, una duda sobre la existencia de un flowlayout perfectamente resuelta por uno de los usuarios.

Cruz, un problema al intentar posicionar un DisclosurePanel de gwt dentro de un window de smartclient con posición absoluta, ni una sola respuesta. Finalmente lo solucioné con un SectionStack de smartclient, pero nada de posiciones absolutas.

Otra cara, contacto directo vía mail con gente de smartclient, siempre responden :-) .

3- Integración gwt-smartclient: Al hilo de estos problemas, comentar que la integración de componentes gwt con smartclient no es buena. Así que si elegimos smartclient tendremos que usar muchos componentes smartclient para evitar problemas de maqueta.

De cualquier forma no puede haber queja del soporte.

Gracias a smartclient por ofrecer una librería gratuita sobre gwt como esta. Pero queremos mas y sobre todo mejor, estaremos atentos.

gwt-exporter

Desde javahispano me entero de la existencia de gwt-exporter. Aun existiendo librerías javascript libres (jquery&otras) tan buenas, prácticas, con gran comunidad, etc, es muy interesante la posibilidad de desarrollar una propia librería bajo gwt para que después terceras personas/equipos la usen desde javascript al estilo jquery&otras.

Google Plugin for Eclipse

Desde que hace tiempo probé sin éxito cypal, no habia buscado alternativas y me valía la simple estructura generada por los scripts de gwt. Ahora google publica Google Plugin for Eclipse, tanto para gwt como para App Engine, un nuevo pasito.

Gwt 1.6

Nueva versión de gwt. Aqui lo nuevo, a modo de resumen:

Nueva estructura de proyecto: Bien! se eliminan los (.launch, .compile, .shell) y se añade fichero de tareas ant.

Se sustituyen Listeners por Handlers.

Nuevos widgets, DatePicker, DateBox y LazyPanel, no llegan no ¡queremos mas!.

Creación y activación de eventos nativos.

Mejoras en el Modo Hosted.

Slider

Que gwt todavía no tenga un slider pasa (está en la incubadora). Pero que ext gwt no tenga slider en su versión stable ya es demasiado, si, lo incluyen en su próxima versión 2.0.

Google!, que sepas que echamos de menos nuevos y mejores widgets, ya se que no me escucha pero hay que intentarlo.

Ext GWT nativo

Me gusta que la implementación de extgwt sea de forma nativa sobre gwt y no se utilicen librerías externas. En general (aun con los problemas que comenté en el post anterior) la integración con gwt está mas conseguida y el rendimiento es mucho mejor que en smartclient, aunque me pese es así.

Sobre el semestre en la uoc, lo mas destacable: TALF2 me mata.

Sobre El quinto día, mantengo lo dicho quitando el último capítulo (que pesado).

Me he enganchado desde el principio a El Ocho, imprescindible para los jugones del ajedrez ;-)

6 April, 2009

Gwt > smartclient: Por un puñetero punto y coma


Desde que hace algo mas de 1 año dejé de luchar a fondo con el html+css (ahora priorizamos funcionalidad a diseño) no me había topado con un problema tan tonto, de esos tan tontos que te tocan lo que ya sabeis. Un puñetero punto y coma.

El caso es que hace un par de semanas que he decidido retomar mis pinitos de hace 9 meses con gwt, esta vez algo mas en serio y centrandome sobre todo en la construcción de la interfaz.

Todavía no había escrito nada sobre gwt, entre otras cosas porque no tengo tiempo, pero vamos, que dando una vuelta por la documentación oficial la idea queda clara. Un framework que pretende hacer mas sencilla la generación de la interfaz para aplicaciones web (y sobre todo mas próxima a los programadores que no se llevan bien con el html+css+javascript, cuando menos la mayoría que han programado siempre en escritorio).

La idea básica es programar en java (como para swing) y mediante el compilador gwt generar toda la capa cliente html+css+javascript. Pero bueno dejamos para otro post generalidades sobre gwt, y vamos con mi estúpido problema.

Primero probé gwt sin más, componentes muy muy básicos, pero que funcionan.

Continuamos con gxt, componentes muy elaborados, demostración de interfaz MDI, tablas, formularios, etc. Aunque a veces se hace un lio con la generación de estilos, y otras no hace caso a los tamaños que inyectas desde java y debes atacar directamente al css generado (es un peligro). Además desde hace un tiempo la versión comercial es de pago.

Llegamos a smartgwt, componentes muy parecidos a gxt, un wrapper sobre smartclient, esta última de pago, pero parece que la versión gwt es gratuita. La verdad: menudo jaleo de licencias, cada vez entiendo menos. Pruebo esta versión, combinando con controles de gwt nativos para depender lo menos posible de una tercera librería.

Por el momento me gusta smartclient (incluso el codigo generado no parece ser tan "cochino" como el de gxt), sigo con las pruebas..., inserto un DisclosurePanel dentro de un Window de smartgwt, problema, aparece con un height que yo no pongo, no se de donde sale (el problema de gwt cuando las cosas no salen a la 1ª). Le pongo un tamaño dpContentSearch.setHeight("40px;"), ni caso. Además no es el height del DisclosurePanel sino el del contenedor, el del layout del Window de smartgwt. Cambio el DisclosurePanel por un HorizontalPanel, nada, lo cambio por un Canvas de smartgwt a ver si el problema va a ser la mezcla de componentes, tampoco.

Se me acaban las ideas, navego por los foros de smartclient, por los fuentes de los diversos componentes buscando algún método que lo solucione, vueltas y mas vueltas... ya por desesperación y tras largo tiempo intentando mas cosas cambio de nuevo el 40 y funciona!, cosa mas rara. Intento buscar la diferencia... el punto y coma del 40, dpContentSearch.setHeight("40px") no, no es lo mismo. Y que conste que el ";" no era ninguna tontería, por ejemplo en gxt se permite, incluso se permite insertar un "40px !important;", por eso este método recibe un string, además de para especificar el tamaño en la unidad que necesites.

Isa se ríe de mi (parece q a las químicas no les pasan estas cosas), me piro a la siesta, es domingo y toca descansar, aunque con este sentimiento de rabia-euforia-emoción-soyunpocotonto es imposible, mejor leo y punto: "El quinto día (Franz Schätzing)" ahora que llego al final me he enganchao :-) .

30 January, 2009

Volviendo a j2ee, comenzando con Maven (eclipse, tomcat)

Este pequeño descanso en la uoc esta viniendo muy bien, tanto para descansar como para probar cosillas que tenía en el baúl de los recuerdos, ya sabéis, para eso de "sentirse vivo" tecnológicamente hablando.

Después de 2 días iniciándome en RoR, en realidad de rails apenas he visto nada todavía, simplemente he preparado el entorno, familiarizado con ruby, me peleé un poco con las gemas y mysql, y ejecuté algunos de sus comandos para crear una aplicación rails, modelo, controlador.
Logo maven
Pues eso, que después de estos 2 días y por razones que no vienen a cuento he estado probando maven (desde el curso de j2ee tenía pendiente echarle un vistazo). La experiencia esta siendo muy satisfactoria, lejos de la complejidad de la que muchos compañeros me habían hablado.

Maven al igual que ant es una utilidad para... automatizar muchas de las tareas en el desarrollo de un proyecto (compilar, desplegar, descargar librerías, pasar tests de unidad, empaquetar, etc etc). Si conoceis ant estaréis pensando que no es nada nuevo, en realidad se podría decir que es una evolución de ant, incluso podemos integrar las dos utilidades para ejecutar tareas ant desde maven.

Comentar que un proyecto maven tiene una estructura global mas o menos fija (que se puede variar, pero ni lo he probado ni lo necesito). Cuando creamos un proyecto mediante la linea de comandos mvn archetype:create -DgroupId=net.jsanroman -DartifactId=aprendiendoMaven, o añadiendo el parámetro -DarchetypeArtifactId=maven-archetype-webapp para un proyecto web, se crea una estructura como la que podeis encontrar en la documentación.

Maven, además de la maravillosa funcionalidad de descarga automática de jars, bien de un repositorio externo, o de nuestra propia red local (típica situación de un equipo de desarrollo de muchas personas sobre un mismo proyecto), tiene preparadas para nosotros multitud de tareas y plugins, por ejemplo el despliegue de nuestro proyecto en un tomcat mediante el tomcat-maven-plugin, simplemente ejecutando mvn tomcat:deploy, aunque antes tendremos que configurar ciertos parametros en el fichero de configuración de maven pom.xml:
dentro de proyect>build:

  1. <plugin>
  2.    <groupId>org.codehaus.mojo</groupId>
  3.    <artifactId>tomcat-maven-plugin</artifactId>
  4.    <configuration>
  5.       <warFile>${project.build.directory}/${project.build.finalName}.war</warFile>
  6.       <update>true</update>
  7.       <path>/facturablock_plain</path>
  8.       <username>admin</username>
  9.       <password>admin</password>
  10.    </configuration>
  11. </plugin>

Configuramos por ejemplo en path de la aplicación a desplegar, el usuario y clave de nuestro manager de tomcat, y la localización de nuestro fichero war a desplegar, aquí mas documentación.

Para que maven sepa que jars debe descargar para nuestro proyecto también lo indicaremos en este mismo fichero pom.xml:

  1. <dependency>
  2.    <groupId>javax.servlet</groupId>
  3.    <artifactId>servlet-api</artifactId>
  4.    <version>2.4</version>
  5.    <scope>compile</scope>
  6. </dependency>

Le indicamos que se descargue la api de servlets. Tenemos un listado completo de librerias en http://mirrors.ibiblio.org/pub/mirrors/maven2/.

Maven se integra con diferentes ide's: netbeans, idea, eclipse. Yo solo he probado con eclipse, para el que hay varios plugins, aunque sin duda para mi el mejor es m2eclipse. No cometáis la misma torpeza que yo, que con las ansias de avanzar ni me fijé en el tipo de errores que daba su instalación, y simplemente que depende de otros plugins para poder ser instalado, aquí tenéis la lista http://docs.codehaus.org/display/M2ECLIPSE/Installation+Requirements.

Aunque todavía me quedan muchas cosas que ver de maven, métricas o integración continua, ya tengo lo básico en funcionamiento, y aquí dejo los 4 comandos básicos, en realidad son "mi recordatorio" que soy muy despistado :$:

  • Creamos nuevo proyecto: mvn archetype:create -DgroupId=net.jsanroman -DartifactId=aprendiendoMaven -DarchetypeArtifactId=maven-archetype-webapp
  • Compilamos proyecto: mvn compile
  • Empaquetamos proyecto: mvn package
  • Copiar jar de proyecto a repositorio local de maven: mvn install
  • Desplegar proyecto web en tomcat: mvn tomcat:deploy
  • Generar sitio web (si si como el de maven): mvn site:site

3 May, 2008

Curso J2EE (5ª semana) - JAX-WS

Java Xml
Nunca es tarde si el post llega.... bueno era algo así ¿no?. El caso es que después de bastante tiempo he aprovechado este puentecillo en el que tampoco tendremos curso para quitar este post atrasado.

En esta 5ª semana llegó el fin de los ejb's con un último ejemplo de ejb de mensaje (jms) que no voy a reproducir pues es muy parecido al ejemplo del post anterior. Y a continuación comenzamos con los servicios web, esa tecnología tan inmadura (por lo que cuidadín con las elecciones, cambios continuos y en general un jaleo de nombres, apis, versiones...) como de moda últimamente. Eso si!!, sin antes perder 3 horillas en una creo que inútil charla de igualdad de género a la que la xunta nos obliga en todos los cursos que financia, en fin, creo que los burros a esta edad seguirán siendo burros, y tampoco me parece el marco ideal para dar estas lecciones, opinión muy personal por supuesto.

Los servicios web son un conjunto de tecnologías (independientes de lenguaje y plataforma) que nos permiten el intercambio de datos entre diferentes máquinas conectadas a través de una red. Lo típico es utilizarlos bajo http (pues junto con su estándar son las dos grandes ventajas aportadas) y eliminar así los efectos de los firewalls (seguro que alguna vez habéis topado con uno). De todas formas os dejo un par de enlaces donde explican mucho mejor que yo:

http://www.w3c.es/Divulgacion/GuiasBreves/ServiciosWeb
http://es.wikipedia.org/wiki/Servicio_Web

Un breve esquema (desde el w3c):
Servicios web
Vemos la aplicación cliente que se conecta con el servicio web, envía datos a través de mensajes SOAP según las reglas descritas en el "contrato" WDSL.

En java tenemos api's y herramientas que nos ayudan a crear y desplegar servicios web. JAX-WS (que forma parte del proyecto glassfish y agrupa entre otras a SOAP 1.2, WSDL 1.1, WSDL 2.0, JAXB 2.0) nos abstrae de las tareas básicas para crear un servicio web. Nos aporta 2 buenas utilidades wsgen y wsimport que nos permitirán generar de forma automática los artefactos necesarios para generar nuestro servicio y las clases proxy que representarán el servicio web en local para los clientes. Luego a través de anotaciones, como viene siendo habitual, indicaremos que clase representa nuestro servicio, que propiedades se corresponden con los tags de nuestros xml, etc:

  1. @WebService(name="ServicioAlumnos")
  2. public class AlumnoWsFacade {
  3.  
  4.     public @WebResult(name="alumno")AlumnoBean getAlumno()
  5.     {

  1. public class AlumnoBean {
  2.     private String nombre;
  3.     @XmlElement(name="nombre")
  4.     public String getNombre() {
  5.         return nombre;
  6.     }
  7.     public void setNombre(String nombre) {
  8.         this.nombre = nombre;
  9.     }

Un par de sencillos pero útiles ejemplos:
http://java.sun.com/developer/technicalArticles/J2SE/jax_ws_2/
http://java.sun.com/developer/technicalArticles/J2SE/jax_ws_2_pt2/

Y para terminar necesitamos un servidor que soporte jax-ws, en realidad nos serviría el propio tomcat, pero yo sigo trabajando con jboss así que me tocó instalar el soporte jax-ws que nos provee el paquete jbossws:
1- Descargamos jbossws.
2- Descomprimimos y renombramos ant.properties.example por ant.properties.
2- Editamos ant.properties y modificamos la propiedad jboss422.home indicando el directorio de nuestro jboss.
3- Ejecutamos ant deploy-jboss42 (mi versión es la 4.2 sino la que toque).
4- Iniciamos jboss y comprobamos en la dirección http://localhost:8080/jbossws/ que se ha instalado el soporte jax-ws en nuestro jboss.

Con esto ya tendríamos jboss preparado para desplegar servicios web, ahora solo nos falta hacer unas pruebecillas, quizás en otro post...

22 April, 2008

Ejemplo EJB stateless

Lo prometido es deuda y ahora q se me ha pasado la vagancia y además tenía un ratillo libre (combinación compleja donde las halla) ;-) os dejo un ejemplo de un ejb sin estado (stateless).

Yo he utilizado jboss en su última versión estable (4.2.2.GA) como contenedor del ejb, para utilizarlo solo teneis que descargaros una copia y arrancar ejecutando /bin/run.sh, ¿fácil verdad?. Podriamos haber utilizado glassfish, que en ubuntu se queda la instalación en un maravilloso apt-get install glassfish, pero si os parece eso lo dejamos para otro día.

Vamos con nuestro ejb.

Primero nos creamos el bean que encapsula toda nuestra lógica de negocio. En este caso tendremos solo 2 métodos, para sumar y restar 2 números (operaciones básicas de toda calculadora).

  1. package net.jsanroman.ejb3stateless.ejb.stateless;
  2. import javax.ejb.Stateless;
  3. import net.jsanroman.ejb3stateless.ejb.interfaces.CalculadoraLocal;
  4. import net.jsanroman.ejb3stateless.ejb.interfaces.CalculadoraRemote;
  5.  
  6. @Stateless
  7. public class CalculadoraBean implements CalculadoraRemote, CalculadoraLocal
  8. {
  9.     public static final String RemoteJNDIName = CalculadoraBean.class.getSimpleName()+"/remote";
  10.     public static final String LocalJNDIName = CalculadoraBean.class.getSimpleName()+"/local";
  11.  
  12.     public int add( int x, int y ){return x+y;}
  13.     public int subtract (int x,int y){return x-y;}
  14. }

Destacar el uso de la anotación @Stateless para indicar el tipo de ejb que estamos creando.

A continuación creamos las interfaces CalculadoraLocal y CalculadoraRemote para indicar que métodos serán accesibles desde el propio contenedor o desde fuera y que serán implementadas por nuestro bean anterior.

En nuestro caso solo nos interesa acceder desde remoto pues haremos las pruebas desde un script fuera de nuestro contenedor.

  1. package net.jsanroman.ejb3stateless.ejb.interfaces;
  2. import javax.ejb.Local;
  3. @Local
  4. public interface CalculadoraLocal { 
  5. }

  1. package net.jsanroman.ejb3stateless.ejb.interfaces;
  2. import javax.ejb.Remote;
  3. public interface CalculadoraRemote {
  4.     public int add(int x, int y);
  5.     public int subtract( int x, int y);
  6. }

Ya tenemos nuestro ejb creado, lo empaquetamos en un .jar (tareilla ant) y lo soltamos en jboss/server/default/deploy. Si nos fijamos en el log de jboss podremos averiguar si se ha producido algún error, pero para estar completamente seguros nos vamos a la jmx-console http://localhost:8080/jmx-console/ y comprobamos si se ha cargado nuestro ejb, en mi caso aparecen estas lineas que indican que está listo para ser utilizado:

# jar=ejb3_stateless_calculadora.jar,name=CalculadoraBean,service=EJB3
# module=ejb3_stateless_calculadora.jar,service=EJB3

Llegados a este punto tan solo nos queda desarrollar un sencillo cliente que haga uso del ejb recién creado. Con una simple clase que muestre el resultado por consola es suficiente para esta prueba:

  1. package net.jsanroman.ejb3stateless.client;
  2. import java.util.Properties;
  3. import javax.naming.Context;
  4. import javax.naming.InitialContext;
  5. import javax.naming.NamingException;
  6. import net.jsanroman.ejb3stateless.ejb.interfaces.CalculadoraRemote;
  7. import net.jsanroman.ejb3stateless.ejb.stateless.CalculadoraBean;
  8. public class CalculadoraClient {
  9.     public static void main(String [] args){
  10.         Properties properties = new Properties();
  11.         properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
  12.         properties.put("java.naming.factory.url.pkgs","=org.jboss.naming:org.jnp.interfaces")
  13.         properties.put("java.naming.provider.url","localhost:1099");
  14.         Context contexto = null;
  15.         try{
  16.             contexto = new InitialContext(properties);
  17.             CalculadoraRemote beanRemoto = (CalculadoraRemote)
  18.             contexto.lookup(CalculadoraBean.RemoteJNDIName);
  19.             int resultado = beanRemoto.add(1, 9);
  20.             System.out.println("El resultado es:"+resultado);
  21.         }
  22.         catch( NamingException e )
  23.         {
  24.             e.printStackTrace();
  25.         }
  26.     }
  27. }

Simplemente destacar la linea contexto.lookup(CalculadoraBean.RemoteJNDIName); causa de posibles rompederos de cabeza y que nos da acceso a nuestro ejb.

Ala y ahora a hacer pruebas con los diferentes ejb's, el ejb-ql, a probar desde otra máquina, y lo que se nos ocurra.

Powered by WordPress
Bajo licencia Creative Commons
Contacto sanroman.javier at gmail.com