Archivo de octubre de 2005





  • por admin - 28 de octubre de 2005 - Etiquetado como ,
    1 comentario »

    Ya tenía claro que esto de tener una empresa daba dolores de cabeza, que la gestión me consumiría mucho tiempo, y que al final, de eso de programar, más bien poco. Esta semana no es representativa, pero… Y es que se puede decir (salvo por el teléfono e internet, que tenemos prestada gracias a Josetxu) que hoy hemos acabado de instalarnos en las nuevas oficinas. Vaya semanita que hemos tenido de paseos de una lado a otro, muebles montados y desmontados, idas y venidas, llamadas, listas de precios, etc.

    Si tuviéramos que dar un premio a los más eficientes… a parte de a Gotxon y su furgoneta… supongo que se lo daría a Iberdrola, menos de 24 horas desde la solicitud de alta hasta tener la electricidad en el local. Lástima que aún no tengan PLC en Bilbao, estaría por contratárselo.

    Menos mal que siempre queda Ibon para hacer el trabajo de verdad.

  • por admin - 28 de octubre de 2005 - Etiquetado como , , ,
    1 comentario »

    El problema de ser un blade runner de nuevos frameworks es que más de una vez nos encontramos con problemas que ni el google puede solucionar. En el caso de JSF es fácil encontrarse con infinidad de tutoriales (que más o menos enseñan lo mismo), un buen sitio de tutoriales sobre JSF sería este, por ejemplo. El problema reside en encontrar sitios que comenten buenas prácticas a la hora de diseñar una aplicación JSF o que describa los errores más comunes a la hora de ponerse manos a la obra. En el caso de el archiconocido struts una de las páginas a las que más utilidad le hemos sacado a lo largo del tiempo es una simple página en la que se describen los errores más comunes y sus posibles soluciones, aquí. Partiendo un poco de la idea de esa página pero aplicada a JSF, en Linking Paths hemos pensado en dedicar una página de este blog a describir las excepciones más comunes en JSF, sus posibles causas y un detalle de sus soluciones. Y por supuesto os animamos a todos a participar, para ir construyendo lo que puede ser una referencia para el sufrido programador que se adentra en territorios inexplorados ;-) Podéis enviar vuestros errores (con solución, que no se trata de que esto se convierta en un foro de JSF) a través de los comentarios a este post, que prometo ir incluyéndolos en el cuerpo de la página. Y para predicar con el ejemplo:

    Error: javax.faces.FacesException: Cannot get value for expression Algún componente de JSF no puede acceder al value que hemos indicado de un backing bean Causas Probables:

  • Comprobar que la clase y paquete del backing bean está bien escrita en faces.xml
  • Comprobar que existe la propiedad a la que hacemos referencia en el componente
  • Error: Al pinchar en un CommandButton, no hace nada y vuelve a la misma página Causas Probables:
  • Comprobar que la clase y paquete del backing bean está bien escrita en faces.xml
  • Si en el form no existe ningún campo que esté relacionado con una propiedad (no con un método) del backing bean, NO se creará al entrar en el form, por tanto no se podrá llamar a sus métodos (que siempre devolverán null y por tanto te mostrarán la página de nuevo, ya que null a la vuelta de una llamada hace que se vuelva a mostrar la página que la originó). Se debe usar un CommandLink en esos casos; si queremos que tenga apariencia de botón hacerlo a través de style
  • TomaHawk Error: javax.faces.FacesException: java.io.NotSerializableException: - Parece que suele suceder cuando un commandbutton vuelve a la misma pagina que lo originó y se debe actualizar otro componente. Causas Probables:
  • La clase a poner en la tabla en sus columnas DEBE ser serializable, usar una clase auxiliar que lo sea si la original no puede serlo.
  • El método para guardar el estado debe ser CLIENTE. En web.xml:
      
    javax.faces.STATE_SAVING_METHOD
    client
      
    Pues nada, a ver si os animáis y nos mandáis vuestros errores ;-)

    ACTUALIZACIÓN: Error: java.lang.IllegalStateException: No Factories configured for this Application – typically this is because a context listener is not setup in your web.xml. A typical config looks like this; org.apache.myfaces.webapp.StartupServletContextListener Causas Probables

  • Comprobar la sintaxis xml de faces-config.xml
  • por admin - 24 de octubre de 2005 - Etiquetado como ,
    1 comentario »

    Si hace unos días os informábamos de que oficialmente teníamos oficina, hoy os podemos decir que ya se puede (casi) trabajar en ella, de modo que os dejamos un plano de su localización.

    Francisco Macia 11, 7º 48014 Bilbao

    Los amigos, los conocidos y los potenciales clientes están invitados a tomar un café de inauguración.

  • por admin - 21 de octubre de 2005 - Etiquetado como , ,
    4 comentarios »

    Uno de los problemas a los que siempre me enfrento a la hora de diseñar una aplicación es la interfaz de usuario. Cada vez creo más cierto que hay que empezar a pensar en la arquitectura de la aplicación a partir de lo que los usuarios de ella quieren/necesitan. Y no soy el único sino mira.

    Pero este post no va de eso. En todos los estados previos de definición de la aplicación siempre nos encontramos rodeados de folios sacados de la impresora donde hacemos bocetos de lo que será la aplicación de usuario. Incluso para tener las ideas más claras se opta a realizar una página web en HTML simple sólo para ver cómo se relacionarán los distintos elementos, y si tienes un diseñador gráfico a mano ;-) que te la haga en photoshop/gimp. Pero siempre me he encontrado con el problemita de no encontrar gráficos hechos para hacer algo rápido (¿cómo hacéis si queréis meter un calendario o un reloj, por ejemplo?)

    Pues bien, hoy buceando en los entresijos de la web he encontrado una pequeña joyita: denim Está realizado en java (cómo no! ;-P) y permite realizar bocetos en pantalla de lo que queremos/creemos va a ser la GUI de la aplicación. Como muestra un bocetillo chorra:

    Un pantallazo de denim

    La interfaz me resulta hasta divertida (en vez de pantallas distintas lo que tienes es zooms de tu boceto), y viene con algunos componentes ya hechos que sólo tienes que arrastrar a tu boceto. Me ha gustado la idea y la propia UI de denim me ha dado algunas ideas interesantes. No sé tal vez debería mirarme mi nivel de frikismo ;-)

  • por admin - 19 de octubre de 2005 - Etiquetado como ,
    5 comentarios »

    Tenemos oficina. Este sábado toca mudanza. Pues sí, ya tenemos oficina en Bilbao, y dejamos de trabajar de forma distribuida. Con esto esperamos que podamos acelerar nuestra integración dentro de la cultura de la empresa. Para el que conozca… en la calle Francisco Macía 11, al lado de la Universidad de Deusto.

    La verdad es que en el pasado pensábamos que el trabajo distribuido iba a ser más fácil de lo que ha resultado en realidad. Quizás el hecho de distribuirnos en nuestro hogar personal (es más duro de lo que podríais pensar) haya sido el problema, pero aunque el Skype lo ha facilitado, para nosotros no ha sido la experiencia que esperábamos.

  • por admin - 18 de octubre de 2005 - Etiquetado como , ,
    5 comentarios »

    Por distintas razones, estamos desarrollando un CMS basado en el servicio de repositorio (JCR, JSR 170) de OCAS y todos los estándares, así como una interface con JSF + AJAX. El objetivo principal es la de hacerlo muy muy muy sencillo de utilizar. El resultado lo tenemos bastante claro (si alguien quiere ver el PDF del producto sólo tiene que pedirlo), aunque la parte del backoffice nos esta planteando varias dudas, y es que cometimos el error de sondear a varios usuarios sobre como debería ser para que les resultara sencilla su utilización, la mayor queja que presentan todos los CMS.

    Al final nos hablaron siempre de dos familias de soluciones: editar directamente desde el front y un administrador sencillo con las opciones mínimas. En el primer caso, con un botón de editar estarían contentos, sin añadir todas las opciones, y en el segundo consideran que una analogía del árbol de carpetas sería bastante acertada, pues todo el mundo la entiende. Ninguna gran sorpresa.

    Me alegra saber que andábamos bien encaminados. Aunque lo que puede tener sentido para un producto sencillo (en realidad nuestro CMS tendrá cinco sabores) puede ser un problema para el resto, pero lo iremos solventando sobre la marcha, supongo.

    ¿Tiene esta aplicación sentido empresarial?. Bueno, como producto separado posiblemente no mucho (does the world need a new CMS?), pero encaja dentro de otra serie de ideas y productos, combinando componentes, así que la inversión nos parece necesaria. Aunque la licencia será con prácticamente toda la seguridad una GPL (lo que no quiere decir que sea gratis!), de modo que quizás cobre algo más de sentido.

  • por admin - 17 de octubre de 2005 - Etiquetado como , , ,
    No hay comentarios »

    Pues nada, que creo que ya hemos solucionado el tema, o por lo menos eso dicen mis tests ;-). Y la solución que hemos tomado no la veo por ningún lado de hibernate.org, y en algunos casos puede ser muy útil: cuando hacemos uso de una librería que haga uso de hibernate y no queremos obligar al programador a conocer los entresijos de las sesiones y las transacciones, pero a la vez queramos hacer uso de la caché de primer nivel de forma eficiente. Perdonad lo pretencioso del título pero es que me ilusiono rápido, a ver si me hacéis caer de las nubes y me decís los problemas que le véis :-) (cuatro ojos ven más que dos) Veamos, el problema con jbpm es que usaba el lazy loading ampliamente a lo largo de su código. Al dar implementación al workflow de OCAS nos encontramos con el siguiente problema: se creaba un proceso en una sesión de jbpm (=sesión hibernate), pero además teníamos un método process.getVariables() en el que teníamos que abrir una nueva sesión jbpm, cargarnos de la base de datos el proceso (que ya teníamos en memoria), y entonces hacer el jbpmProcess.getVariables() (y el lazy loading funcionaba porque ahora el proceso SÍ estaba cargado en la misma sesión en la que iba a cargar las variables). Un poco de código:

    public class JBPMWorkflowService implements WorkflowService{ (...) public net.javahispano.ocas.workflow.Process startProcess(String processName, String usr) { JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession(); org.jbpm.graph.def.ProcessDefinition definition = jbpmSession .getGraphSession() .findLatestProcessDefinition(processName); ProcessInstance jbpmProcess = new ProcessInstance(definition); jbpmSession.getGraphSession().saveProcessInstance(jbpmProcess); jbpmSession.close(); JBPMProcess proceso = new JBPMProcess(jbpmProcess); return proceso; } }

    public class JBPMProcess implements Process{ (...) public Map getVariables(){ JbpmSession sesion = wfService.getJbpmSession(); ProcessInstance process = sesion.getGraphSession() .loadProcessInstance(processInstance.getId()); Map result = process.getContextInstance().getVariables(); wfService.closeJbpmSession(sesion); return result; }

    Buff HORRIBLE! Y ¿porqué lo teníamos que realizar así? Porque realmente estabamos usando el patrón de hibernate session-per-request lo que pasa es que OCAS es una librería cuyas peticiones van a venir de otro código, que no sabemos exactamente a qué métodos va a llamar (en algún sitio puede que sólo llamen a startProcess, en otros puede llamar a los dos métodos presentados). En una aplicación web, el patrón session-per-request tiene sentido ya que conocemos que vamos a hacer en cada petición (traernos datos de la bd, modificarlos y salvarlos), pero nuestro problema es que no conocemos a priori que métodos iban a ser llamados, con lo cual debíamos contemplar cada llamada al método del wfService como una petición independiente.

    De repente surgió la idea: el patrón sesión por transacción de aplicación, pero un poco al revés. En hibernate dicen que usando los métodos connect y disconnect puedes hacer que una sesión dure varias transacciones; pues bien lo que necesitábamos es usar los métodos connect y disconnect entre las llamadas a los métodos del WF, con ello conseguiríamos:

  • No abrir una nueva sesión en cada llamada a los métodos
  • Aprovecharnos de la caché de primer nivel de hibernate: por ejemplo si alguien llamase al método getVariables dos veces seguidas, solamente en la primera habría un acceso a la base de datos
  • Claro está, que no hay nada gratis, para poder implementar la idea nos obligaba a idear algún sitio donde la sesión se abriese por primera vez y se cerrase de una vez por todas, así que “algo” sí hemos tenido que cambiar la interfaz: ahora aparece el concepto de ProcessTransaction (con sus métodos open(), commit() y rollback de toda la vida ;-)) Pero eso sí, para nada aparece el concepto de ProcessSession, no existe, las sesiones jbpm son transparentes al programador que use OCAS

    Otro poco de código:

    public class JBPMProcessTransaction implements ProcessTransaction{
        private JbpmSessionFactory sesionFactory;
        private JbpmSession jbpmSession;
        private Session hibernateSession;

    (..)

    public void open() {
    
        if(jbpmSession.getCurrentJbpmSession() == null){
            jbpmSession = sesionFactory.openJbpmSession();
        }else{
            jbpmSession = jbpmSession.getCurrentJbpmSession();
        }
        jbpmSession.beginTransaction();
        jbpmSession.getSession().disconnect();
    
    }
    

    }

    Y ahora el método de antes cambia así:
    public Map getVariables(){
            JbpmSession sesion = JbpmSession.getCurrentJbpmSession();
            sesion.getSession().reconnect();

        Map result = processInstance.getContextInstance().getVariables();
        sesion.getSession().disconnect();
        return result;
    

    }

    Para que esto funcione, el usuario debe abrir y cerrar transacciones con el servicio de workflow:
    ProcessTransaction transaction = new JBPMProcessTransaction();
    transaction.open();
    wfservice.deployProcessDefinition(processDefinition);
    net.javahispano.ocas.workflow.Process proceso = wfservice.startProcess("TestModel", "Test");
    wfservice.stateEnded(proceso);

    assertEquals(proceso.getVariable(JBPMProcessDefinition.AUTHOR), "Test"); assertEquals(proceso.getVariable(JBPMProcessDefinition.DESCRIPTION), "Test description"); transaction.commitAndClose();

    El método getCurrentSession(), es un método que proporciona jbpm y que funciona como un HibernateUtil (ver primer post de la serie). En todas las llamadas a esos métodos se usa la misma sesión jbpm (que al desconectarse entre llamadas a métodos no ocupa una conexión del pool), aprovechándose de su caché, y cuando finalmente se llama a transaction.commitAndClose(), todo se guarda en la BD y se cierra la conexión.

    En cuanto a hibernate, el pretencioso título de este post quiere decir, que he visto como patrón una sesión larga con varias transacciones asociadas, pero que lo que se trata es de una transacción con una sesión que se conecta y desconecta. No hemos inventado nada pero para este tipo de problemas, como el que se ha planteado, puede ser la solución genérica. Ahora mismo le estamos dando vueltas pero “intuimos” que si guardasemos la ProcessTransaction en un objeto HttpSession, se podría implementar con el mismo código el patrón “Long Session” de hibernate (lo de que una sesión permanece a través de varias transacciones, que en nuestro caso lo que queremos es que la sesión permanezca a través de varias peticiones, que pueden ser de una aplicación web o de escritorio). Ya os contaré (si aguantáis mis tostones ;-)) PD: ya sé que sigue siendo feo, tener esas llamadas a reconnect y disconnect en cada llamada a los métodos del workflow de OCAS, la idea es que en la próxima refactorización se usará AOP, pero ya llegará ese post.

  • por admin - 13 de octubre de 2005 - Etiquetado como , , ,
    No hay comentarios »

    Sigo con mi serie de posts sobre el desarrollo de OCAS. En este intentaré describir mi problema, y en el próximo lo que creo que va a ser la resolución de esta apasionante serie :-P. El objetivo que nos hemos marcado en OCAS es proporcionar una capa de servicios que ayuden a la programación en tareas típicas a los que nos enfrentamos proyecto a proyecto, abstrayendo la complejidad de las librerías a los programadores. De la misma forma nuestra idea es dar diferentes implementaciones a esos servicios para que el desarrollador elija la que más le guste. En breve el wiki contendrá más información. En estos momentos me encuentro desarrollando la implementación del servicio de workflows con la librería open source JBPM, que a su vez usa como mecanismo de persistencia hibernate. Y es aqui donde empezó la paja mental causante de esta serie de posts ;-) Veamos, jbpm ofrece en su API unas “sesiones” jbpm, que no son más que un wrapper de las sesiones hibernate. A partir de una sesión jbpm se obtienen unos objetos sesión (GraphSession, TaskMgmtSession…), que yo calificaría como una especie de DAO’s (para entendernos ;-)) para trabajar (CRUD) con determinados aspectos de un proceso. El tema es que en jbpm hacen aaaampliooooo uso del lazy loading (las variables de un proceso son lazy por ejemplo). Hasta aquí puedo leer ;-), que me reservo un post sobre jbpm cuando lo tenga acabado. Y aquí es donde empezamos a chocar con OCAS: nuestra pretensión es facilitar la vida al programador, no decirle que tiene que aprender hibernate para usar un servicio de workflows, y que tiene que tener claro que es una sesión y que es una transacción en hibernate. Y aquí es donde me parece que pecan algunas librerías que usan hibernate, simplemente transportan la interfaz de hibernate hacia arriba y le cuentan al programador que se mire la documentación. Por ejemplo, en jbpm hace falta conocer hibernate y su manejo de transacción/sesión y los patrones involucrados (ver post anterior) para entender porqué narices sale esa LazyInitializationException cuando pido las variables de un proceso fuera de la sesión jbpm que lo cargó. Para mí no tiene mucho sentido. Generalmente el código que usa hibernate adquiere una fuerte dependencia con él, lo cual tiene mucho sentido en DAO’s de acceso a BD, pero que deja de tenerlo cuando simplemente son librerías que hacen otra cosa además de usar hibernate ;-)

    En mi implementación del servicio de OCAS he barajado varias soluciones para no molestar al usuario programador con los detalles de la implementación concreta en jbpm:

  • Modificar el código de jbpm para que determinadas relaciones no sean lazy: no sigue la filosofía de OCAS, en la que damos la implementación de nuestros servicios sin tocar el código fuente de las librerías.
  • Abrir y cerrar sesión en cada uno de los métodos de mi servicio de workflow. Por ejemplo así:
    public Map getVariables(){
            JbpmSession sesion = wfService.getJbpmSession();
            ProcessInstance process = sesion.getGraphSession().loadProcessInstance(processInstance.getId());
            Map result = process.getContextInstance().getVariables();
            wfService.closeJbpmSession(sesion);
            return result;
    }
    Buff, para mí apesta :-), se podría ver como una sesión por petición, pero el problema es que aquí no se trata la petición de un usuario web, sino de una llamada a un método de una librería, y en un request de una aplicación web puede haber varias decenas de llamadas a métodos. No se aprovecha el caché de primer nivel y además me obliga a cargar de nuevo el proceso desde la BD (porque antes lo cargué en una sesión jbpm/hibernate distinta) aunque ya lo tenga en memoria. Como ventaja lo único que puedo decir es que en la interfaz ofrecida del servicio al programador el no ve ni sesiones ni transacciones de hibernate, lo cual es mi objetivo.
  • Alguien podría decirme:

    Bueno pues cargate toda la info del proceso en memoria cuando se cargue el proceso y montate tu propia caché

    Puede ser, pero creo que he encontrado una solución mejor –> más productiva y eficiente (y sin escribir mucho más código)

  • Pero la solución (que desvelaré en un próximo post para mantener la intriga, y poder hacer los tests :-)) me vino el día de la hispanidad (como buen programador yo no tengo fiestas :-() mientras fregaba mi taza del café. Sólo os adelanto que tiene que ver con uno de los patrones que describen en hibernate, y que los usuarios de OCASWF sólo deben conocer el significado de una transacción (el general, el que conoce todo el mundo vaya). Os dejo con este atroz suspense, para que estos posts sirvan para ver las ventajas de usar OCAS y los sudores que nos cuestan. Salu2 PD: Sólo espero que hibernate 3 haga todo lo que promete :-D

  • por admin - 11 de octubre de 2005 - Etiquetado como , , ,
    4 comentarios »

    En los últimos tiempos, estamos en Linking Paths trabajando con Java Server Faces en algunos de nuestros productos (más información en breve). No porque creamos que es el framework definitivo y mejor que todos los demás, sino más bien como una apuesta estratégica de cara al futuro. Pero después de 5+ años haciendo aplicaciones web, digamos que nos plantea tanto dudas como respuestas. Java Server Faces nos ofrece una serie de ventajas indudables (componentes configurables, la promesa de crear distintos clientes cambiando el renderer, ocultar en parte que es una aplicación web, promover el trabajo con backing beans e IoC, ser un estándar, etc. ), pero a la vez nos de muestra que es un entorno al que aún le faltan un par de vueltas. En mi opinión dos principalmente, aunque algunas decisiones sobre la arquitectura podrían ser discutibles, algo que no voy a hacer porque quiero pensar que las personas que tomaron esas decisiones saben más que yo.

    Volviendo a los dos grandes problemas actuales:

    • Forma estándar de distribuir y configurar los nuevos componentes.
    • Información.

    En el primer caso, nos encontramos proyectos como Tomahawk (que pertenece a myfaces) que nos ofrece componentes varios para nuestras aplicaciones (menus paginadores, pestañas, etc.), pero no hay forma sencilla de utilizarlos. Y con sencilla quiero decir: añadirlos al IDE de nuestra elección para poder usarlos con pinchar y arrastar, que es otra de las bondades que se esperan de JSF.

    Respecto a la información, me refiero a la situación inherente de toda nueva tecnología. Java Server Faces es nuevo, y como tal la cantidad de información es menor que la disponible para, digamos, Struts. Y no me refiero a libros, sino información de proyectos reales, de los problemas que se han ido encontrando, etc. No puedo evitar tener la sensación de estar en el año 1999 (obviamente mejor situación, en entorno mucho más acotado y mucha más experiencia), en la que todo lo que había era el API de Servlets, y en las que cada uno iba tirando por dónde mejor le parecía (de ahí la variedad de frameworks web en Java).

    De modo que, volviendo a la pregunta inicial… ¿está Java Server Faces preparado para un uso real en la empresa?. Obviamente nuestra respuesta es sí. A pesar de esos pequeños drawbacks (y sin entrar en peleas con otros, como Spring Framework o Ruby on Rails), Java Server Faces es una posibilidad más que ha venido para quedarse y con buenas perspectivas de futuro, y nadie que se dedique al desarrollo web en Java debería perderlo de vista (que lo use o no es decisión de cada uno). Sin duda el primero de esos grandes problemas que he comentado lo acabarán solventando, y el segundo… digamos que el segundo se solventa día a día.

    Lo que ya ofrece, lo que es seguro que ofrecerá, así como principalmente el hecho de ser un estándar mimado, hacen de Java Server Faces una buena apuesta de futuro con un uso factible hoy.

    Por poner nuestro granito de arena, hemos creado una lista de distribución para todos aquellos interesados en Java Server Faces: jsf@dev.linkingpaths.com., así como lo seguiremos impartiendo en nuestros cursos.





  • Linked, el blog de Linking Paths