====== FundeWeb 2.0 vs FundeWeb 1.2.5 ====== --- //[[pedrody@um.es|PEDRO DELGADO YARZA]] 2014/01/29 13:47// Con el cambio de versión de Fundeweb, se han actualizado un gran número de librerías lo que ha supuesto un cambio sustancial en rendimiento, manejo y visualización de las aplicaciones lo que aporta grandes ventajas pero implica adaptar ciertos aspectos que se usaban en Fundeweb 1.2.5 a cómo se utilizarán en esta nueva versión. ===== Estructura de proyecto ===== La estructura del proyecto ha cambiado sustancialmente de la versión 1.2.5 a la 2.0 de Fundeweb, es importante conocerla para poder trabajar con ella sin problemas. Los contenidos referentes a la estructura se encuentran en esta [[fdw2.0:fundeweb2.0:gt:estructura_del_nuevo_proyecto_maven|guía]]. ===== Persistencia ===== **Persistir datos** En Fundeweb 2.0 la persitencia ha de hacerse **siempre** dentro de un EJB. Si intentamos persistir desde fuera de un EJB nos dará un error indicando que no existe transacción. En esta versión de fundeweb son los EJB quienes manejan la apertura y cierre de transacciones, liberando a Seam de esa tarea. **NamedQuery** Actualmente en la notación de las NamedQueries podíamos poner la variable del select con el mismo nombre que la tabla en la que buscamos select anuncio from Anuncio anuncio En la nueva versión de hiberante 4.2.7 el validador de las expresiones incluidas en las NamedQueries se ha vuelto más restrictivo y no permite que el nombre de la variable selectora sea igual al de la tabla que mapea (ignora mayúsculas/minúsculas) por lo que la Query anterior debería expresarse como: select an from Anuncio an ===== La vista ===== En Fundeweb 2.0 se deja de utilizar totalmente Richfaces debido a la falta de evolución de sus componentes y el alto tiempo de respuesta a la hora de solventar bugs o añadir nuevas características. En su lugar se utilizará **Primefaces** puesto que posee un conjunto de componentes muy amplio, junto con un gran servicio de mejora y desarrollo, lo que garantiza actualizaciones, mejoras, y resolución de bugs en un periodo corto de tiempo. * [[http://blog.primefaces.org/|Blog Primefaces]] * [[http://www.primefaces.org/showcase/ui/home.jsf|Showcase Primefaces]] Otros detalles importantes a tener en cuenta en la vista: **Validaciones** Tags: ** ** ya no son necesarios JSF es capaz de gestionar ahora la validación de componentes sin necesidad de las librerías de seam. ===== EJB 3.1 ===== La actualización a EJB 3.1 conlleva un conjunto de mejoras importantes que facilitan el manejo, acceso y gestión de los EJB. ====Acceso sin interfaz==== En EJB 3.1 no es necesario que un EJB implemente un determinado interfaz para proveer acceso local a sus métodos. El cliente podrá acceder a cualquier método **público** de un EJB una vez lo recupere. El siguiente ejemplo ilustra esto: @Stateless public class PruebaEJB { public String holaMundo() { return "Hola Mundo"; } } public class HolaMundoClass{ @EJB private PruebaEJB pruebaEJB ; public String diHola() { return pruebaEJB.holaMundo(); } } Como podemos ver el EJB no implementa ninguna interfaz y en cambio la clase HolaMundoClass puede acceder sin problemas a sus métodos públicos. No obstante existen ciertas limitaciones sobre esta nueva funcionalidad: * El cliente nunca puede usar al operador new para adquierir la referencia, debe obtener el EJB por una referencia existente. * Si se intenta invocar un método que no es público se producirá una EJBException. * Si se expone una interfaz local, sólo serán accesibles los métodos de esa interfaz aunque tenga otros públicos. ====Anotaciones==== En esta nueva versión tenemos un conjunto nuevo de anotaciones que nos mejoran y amplían las posibilidades existentes a la hora de diseñar nuestra aplicación. **@Asynchronous **: Permite marcar un método como asíncrono. El método devolverá un objeto de tipo **Future** que inicialmente estará vacío y se rellenará cuando la ejecución del método se complete. Los métodos asíncronos sólo pueden devolver tipo de objeto **Future** o ser **void**. @Singleton public class B { ... @Asynchronous public void flushBye() { ... } ... @Asynchronous public Future sayBye() { ... return new AsyncResult(bye); } } La interfaz Future provee los siguientes métodos: * **cancel (boolean mayInterruptIfRunning)**: Intenta cancelar la ejecución del método asíncrono. El contenedor intentará cancelar la invocación si todavía no fue iniciada. Si la cancelación resulta exitosa el método devuelve true, sino false. El parámetro mayInterruptIfRunning controla, en caso de que no pueda detenerse la invocación, si el bean destino tiene visibilidad del pedido de cancelación por parte del cliente. * **get**: Devuelve el resultado del método cuando termina. Este método tiene dos versiones sobrecargadas, una que se bloquea hasta que termine la ejecución, y la otra que recibe un timeout como parámetro. * **isCancelled**: Indica si el método fue cancelado. * **isDone**: Indica si el método terminó exitosamente. **@Singleton**: Nos permite crear de manera automática el singleton de una bean determinado creando lo que se conoce como Singleton Session Bean. El comportamiento en este caso, es el de un bean que se crea una única vez por aplicación y que puede ser instanciado por cualquier cliente, permitiéndose un acceso concurrente al mismo. @Singleton public class A { (...) } ====Timer Service==== Este servidio incluido en la nueva versión de EJB nos permite realizar tareas guiadas por instantes de tiempo. Ahorrando así el uso de otras tecnologías que antes eran necesarias para esta tarea como Quartz o Flux. La anotación **@Schedule** se utiliza para crear un timer de forma automática, que coge como parámetro el timeout correspondiente a la ejecución. Esta anotación se aplica al método que será utilizado como callback del timeout. En el siguiente ejemplo se definen dos timers, uno que expira cada lunes a la medianoche y el otro que expira el último día de cada mes. @Stateless public class TimerEJB { @Schedule(dayOfWeek="Mon") public void itIsMonday(Timer timer) { (...) } @Schedule(dayOfMonth="Last") public void itIsEndOfMonth(Timer timer) { (...) } } Un método puede estar anotado con más de un timer, en el siguiente ejemplo definiremos dos timers para el método mealTime, uno de los cuales expira todos los días a la 1pm y el otro expira a las 8pm. @Stateless public class MealEJB { @Schedules( { @Schedule(hour="13"), @Schedule(hour="20") } public void mealTime(Timer timer) { (...) } } Los timersser persistentes (por defecto) o no-persistentes. Los timers no-persistentes no sobreviven a un apagado de la aplicación o una caída del contenedor. La persistencia puede definirse usando el atributo persistente de la anotación, o pasando la clase TimerConfig como parámetro del método createTimer en la interfaz TimerService. Algunos ejemplos más completos de cómo definir un timer: Todos los martes a las 7.30am @Schedule(hour = "7", minute = "30", dayOfWeek = "Tue") De lunes a viernes, a las 7, 15 y 20 horas @Schedule(hour = "7, 15, 20", dayOfWeek = "Mon-Fri") Cada hora de los domingos @Schedule(hour = "*", dayOfWeek = "0") Último viernes de diciembre, a las 12 @Schedule(hour = "12", dayOfMonth = "Last Fri", month="Dec") Tres días antes del fin de mes, para cada mes del 2009, a las 8pm @Schedule(hour = "20", dayOfMonth = "-3", year="2009") Cada 5 minutos de todas las horas, comenzando a las 3pm @Schedule(minute = "*/5", hour = "15/1") ===== OC4J 10G Release 3 vs Weblogic 12c (12.1.1) ===== **Servidor** El nuevo servidor en Fundeweb 2.0 es Weblogic 12c, este servidor nos proporciona facilidades en cuanto al despliegue y administración de aplicaciones. Estas facilidades nos permiten abstraernos de las tareas Ant utilizadas en Fundeweb 1.2.5 para el despliegue facilitándonos una opción única para desplegar un proyecto. {{ :fdw2.0:fundeweb2.0:gt:fp1.jpg |}} ==== OC4J 10G Release 3 Carpeta APPLIB ==== La carpeta ///applib// del contenedor OC4J se corresponde con la carpeta ///lib// dentro de un dominio de Weblogic. Es importante destacar, que si se actualiza un JAR en la carpeta ///lib//, se tiene que reiniciar todos los servidores del dominio para que se coja el cambio. Solo se deben metar librerías que no cambien frecuentemente y que sean compartidas por todas las aplicaciones. ==== Classloader ==== Los [[http://docs.oracle.com/cd/E24329_01/web.1211/e24368/classloading.htm|classloaders en Weblogic]] funcionan de la siguiente manera: * Tendremos un //system classloader// padre del resto de classloader. * Como hijo tenemos un ///lib classloader// para las JAR compartidos para todas las aplicaciones del dominio. * Como hijo tenemos un classloader con las carpetas ///lib// y ///classes// de la raíz del EAR. * Como hijo tenemos un classloader con los módulos EJBs. * Como hijo tenemos un classloader por cada modulo web. Esta configuración puede cambiar ya que se pueden crear classloaders que contengan ejb y web, etc. Para indicar que se quieren cargar las clases de los classloader que vienen en la aplicación en lugar de el //system classloader// o el ///lib classloader// del dominio, se utilizan los ficheros //weblogic-application.xml// en la carpeta //META-INF// de la raíz del EAR o el //weblogic.xml// en la carpeta //META-INF// de la raíz del WEB. Estos ficheros admiten prefer-application-packages y prefer-application-resources: org.apache.log4j.* antlr.* org.apache.log4j.* antlr.* Además en el fichero //weblogic.xml// podemos añadir true para indicar que se prefieren las clases que están en la carpeta //WEB-INF/lib// en lugar de las que vienen por los classloaders padres. ==== Shared Library y Optional Packages ==== En Weblogic podemos instalar [[http://docs.oracle.com/cd/E24329_01/web.1211/e24368/libraries.htm| shared libraries y optional packages]]. **Optional Packages** En Java los //optional packages// se suelen instalar en las carpetas: * lib/ext [in the JRE] * jre/lib/ext [in the JDK] //Optional packages// proporcionan un funcionalidad parecida a las librerías JAVA EE, permitiendo compartir un JAR entre varias aplicaciones. Primero hay que registrarlos en el servidor webLogic desplegando un JAR como //optional package//. Después se pueden desplegar módulos Java EE que hacen referencia a estos paquetes en sus ficheros //manifest//. La diferencia entre los //optional packages// y las //librerías Java EE// radica en que pueden ser referenciados por cualquier modulo JEE (EAR, JAR, WAR, o archivo RAR) o por directorios desempaquetados. Las //librerías Java EE// solo pueden ser referenciadas por aplicaciones JEE validas. Por ejemplo, las clases de los framework para crear aplicaciones, necesitadas por varias aplicaciones web, pueden ser empaquetadas y desplegadas en un simple JAR, y referenciadas por varios módulos de aplicaciones web del dominio. En este caso, se deben utilizar los //optional packages// en lugar de //librerías JEE//, porque un modulo individual de una aplicación web, puede referencias a un JAR compartido, con las //librerías JEE//, solo la aplicación completa puede referenciar a la librería. Utiliza los //optional packages// cuando necesites compartir una o más clases (empaquetadas en un fichero JAR) entre diferentes módulos JEE. **Shared Library** Las //librerías JEE// compartidas, deben utilizarse cuando necesita que se compartir uno o más módulos EJB, Web o JEE entre diferentes aplicaciones JEE. Utiliza las //librerías JEE// compartidas, para compartir un JAR, si solo necesitas referenciarlo en una o más aplicaciones JEE, y no necesitas cumplir estrictamente la especificación JEE. Para crear una librería compartida JEE, y compartirla entre múltiples aplicaciones tienes: 1. Ensamblar la librería dentro de un modulo o aplicación JEE valido y desplegable. La librería necesita que tener un descriptor de despliegue JEE para el módulo o la aplicación. Es recomendable que se empaquete como una aplicación JEE (EAR). 2. Ensamblar las clases de los //optional package// en un directorio de trabajo. 3. Crear y editar el fichero //META-INF/MANIFEST.MF// especificando el nombre (Extension-Name) y la información de la versión (Specification-Version y Implementation-Version). Ejemplo: Extension-Name: myLibrary Specification-Version: 2.0 Implementation-Version: 9.0.0 4. Empaquetar para la distribución y despliegue ([[http://docs.oracle.com/cd/E24329_01/web.1211/e24368/splitdeploy.htm#i1097308|Deploying Applications Using wldeploy]].). Ejemplo: java weblogic.Deployer -adminurl http://localhost:7001 -username weblogic -password weblogic -deploy -targets myserver1,myserver2 -library /deployments/myLibraryApplication/ Para referenciar a una librería JEE compartida en una aplicación JEE, se utilizan el fichero //weblogic-application.xml// o //weblogic.xml//. Ejemplo: myLibrary 2.0 9.0.0 true Con //true// estamos indicando que se coja la versión exacta, si es //false// (valor por defecto), entonces weblogic establece la librería con mayor versión. ==== Cambiar la versión de JSF 2.1 ==== Como actualizar la version de JSF 2.1 cuando pasamos la librería en la aplicación. false javax.faces.* com.sun.faces.* com.bea.faces.* javax.faces.* com.sun.faces.* com.bea.faces.* META-INF/services/javax.servlet.ServletContainerInitializer META-INF/services/com.sun.faces.spi.FacesConfigResourceProvider ===== Desarrollo de Aplicaciones ===== ==== Diferencias de Componentes ==== === JSF vs Seam JSF === ** -> ** Los elementos //// de JBoss Seam definidos en las etiquetas //// de los ficheros //page.xml// o el fichero //pages.xml// global se sustituye por la etiqueta //// que se define dentro de una etiqueta //// en la propia página XHTML. También se le pueden añadir conversores y validadores. ** -> (JSF 2.1) o (JSF 2.2) ** Los elementos //// de JBoss Seam definidos en las etiquetas //// de los ficheros //page.xml// o el fichero //pages.xml// global se sustituye por la etiqueta //// (JSF 2.1) o por //// (JSF 2.2), que se define dentro de una etiqueta //// en la propia página XHTML. ** @RequestParameter -> @ManagedProperty ** La anotación de JBoss Seam //@RequestParameter// se puede sustituir por la anotación que proporciona JSF 2 //@ManagedProperty//. Realmente la anotación //@ManagedProperty// es más potente y permite injectar cualquier bean manejado por JSF. Pero para obtener los parámetros de una llamada GET, tenemos que utilizar en una expresión el el objeto //param// y después el nombre del parámetro de URL a obtener. @ManagedProperty(value = "#{param.id}") private Integer id; ==== JSF 2 y Problemas con Componentes @ViewScoped ==== **//Why does @PostConstruct callback fire every time even though bean is @ViewScoped?//** No podemos utilizar la propiedad //binding// de componentes JSF en beans de respaldo con ámbito view. Parece que si este bean, tiene un metodo anotado con //@PostConstruct// este se ejecuta en cada acceso, Una solución es hacer el binding con un bean de respaldo de tipo request, e inyectar este bean en el bean con ámbito view. **NOTA**: Parece que a partir de la versión de JSF Mojarra 2.1.18 esta solucionado. **//JSTL c:forEach causes @ViewScoped bean to invoke @PostConstruct on every request//** Los beans de ámbito view, se almacenan en el estado de la vista JSF, que solo esta disponible después de la fase //restore view//. Las etiquestas //JSTL// se ejecutan durante la fase //restore view//, donde los beans de ámbito view no estan disponibles. Lo que provoca la creación de una nueva instancia del bean con ámbito view, que es reemplazada por la instancia real que esta almacenada en el estado de la vista JSF. **NOTA**: Como la anterior, puede que a partir de la versión JSF Mojarra 2.1.18 este solucionado. ==== Diferencia entre y @ManagedProperty ==== Para obtener parámetros en peticiones GET (estan en la URL), podemos utilizar la etiqueta //// o la anotación //@ManagedProperty//. Las ventajas o diferencias son las siguientes. **** * Establece el valor solo durante la fase //update model values// (desde que extiende //UIInput//). * El valor establecido, no esta disponible durante la ejecución de un método anotado con //@PostConstruct//. Pero se puede utilizar la etiqueta //// dentro de la etiqueta //// para realizar una inicialización/precarga basada en este valor (en JSF 2.2 se podra utilizar la etiqueta //// en su lugar). * Permite anidar //// y //// y asociar un ////. * Puede incluirse como parámetro de URL en llamadas GET, utilizando //includeViewParams=true// con //// o ////. * Puede utilizarse en beans //@RequestScoped//, pero es necesario un bean //@ViewScoped// si se quiere que el parametro sobreviva a los errores de validación de los formularios que contiene la vista o utilizar la etiqueta //// en componentes que extienden de //UICommand//. **@ManagedProperty** @ManagedProperty(value = "#{param.id}") private Integer id; * Establece el valor inmediatamente después de que el bean sea creado. * El valor establecido, esta disponible durante la ejecución de un método anotado con //@PostConstruct//. Facilitando la inicialización o precarga basada en ese valor. * No esta disponible para conversion/validation declarativa en la vista. * La propiedad //#{param}// no esta disponible para beans con ámbito mayor de el ámbito de request. Es obligatorio un bean con ámbito//@RequestScoped//. * Si necesitas tener la propiedad #{param} en posteriores solicitudes POST, tienes que utilizar la etiqueta //// en componentes que extienden de //UICommand//. ==== Logging con log4j2 ==== Con la nueva API, podemos utilizar placeholders (evitan la concatenación de Strings y ahorran memoria), como con el //log// de JBoss Seam pero en lugar de utilizar //#0..#n// o //{0}..{n}// se utiliza //{}..{}//. logger.debug("Hi, {} {}", u.getA(), u.getB()); [[http://logging.apache.org/log4j/2.x/log4j-api/apidocs/index.html|La nueva API]] también nos trae marcadores (//[[http://logging.apache.org/log4j/2.x/manual/markers.html|Markers]]//) y trazas de flujo (//[[http://logging.apache.org/log4j/2.x/manual/flowtracing.html|flow tracing]]//). private Logger logger = LogManager.getLogger(MyApp.class.getName()); private static final Marker QUERY_MARKER = MarkerManager.getMarker("SQL"); ... public String doQuery(String table) { logger.entry(param); logger.debug(QUERY_MARKER, "SELECT * FROM {}", table); return logger.exit(); } Los marcadores (//Markers//) permiten identificar entradas de log rapidamente. Los trazas de flujo //Flow Traces// son métodos que se pueden llamar al inicio y fin de un método. En tu fichero de log, podrás ver una gran cantidad de entradas nuevas con nivel de traza: tu flujo de programa es logeado. Ejemplo de trazas de flujo: 19:08:07.056 TRACE com.test.TestService 19 retrieveMessage - entry 19:08:07.060 TRACE com.test.TestService 46 getKey - entry ** Arquitectura de Plugins ** Log4j2 soporta arquitectura de plugins, que permiten extender log4j de una manera sencilla. Puedes construir extensiones con el espacio de nombres de tu elección, solo tienes que indicar al framework donde buscar (puedes añadir varios paquetes, separados por comas). ... Ejemplo de plugin: @Plugin(name = "Sandbox", type = "Core", elementType = "appender") public class SandboxAppender extends AppenderBase { private SandboxAppender(String name, Filter filter) { super(name, filter, null); } public void append(LogEvent event) { System.out.println(event.getMessage().getFormattedMessage()); } @PluginFactory public static SandboxAppender createAppender( @PluginAttr("name") String name, @PluginElement("filters") Filter filter) { return new SandboxAppender(name, filter); } } El método con la anotación //@PluginFactory// sirve como factoría. Los dos argumentos de la factoría, son leídos del fichero de configuración. Se logra mediante las anotaciones //@PluginAttr// y //@PluginElement// utilizadas en los argumentos. Además de //appenders// se pueden crear //Loggers// o //Filters//. [[http://logging.apache.org/log4j/2.x/manual/plugins.html|Mira la documentación de plugins.]] ** Configuración ** La nueva [[http://logging.apache.org/log4j/2.x/manual/configuration.html|configuración de log4j2]] es más sencilla: Mira la sección de //appenders//. Puedes utilizar etiquetas parlantes, por ejemplo, que coinciden con el nombre de un //appender//. No más nombres de clases. Bien, este fichero de configuración es un documento XML que no se puede validar. Si necesitan hacer validación de XML, también se puede utilizar el modo estricto, con lo que se parecerá al antiguo formato: ... Pero, no es todo. Se puede recargar la configuración automáticamente mediante la propiedad //monitorInterval//: ... El valor del intervalo de monitorización es en segundos, con un valor mínimo de 5. Esto significa, que log4j2 puede reconfigurar el logging en caso de que la configuración haya cambiado. Si se utiliza el valor de cero o no se configura, no se detectaran cambios. Lo mejor, es que no se perderán eventos durante la reconfiguración. ** Integración con otros sistemas de log ** Apache log4j 2.0 tiene varias integraciones: Commons Logging, Slf4j. También puedes hacer que las aplicaciones log4j 1.x utilicen log4j2 en segundo plano. ** Loggers y Appenders Asíncronos ** El [[http://logging.apache.org/log4j/2.x/manual/async.html|logging asíncrono]], puede proporcionar una mejora en el rendimiento de la aplicación, ejecutando las operaciones de I/O en un hilo separado. Log4j2 ha mejorado en este área: * **Loggers Asíncronos**. Se han creado con la intención de volver de una llamada a //Logger.log// a la aplicación, lo más rápido posible. Puedes escoger entre configurar todos los logger como asíncronos (mayor rendimiento) o una mezcla entre síncronos y asíncronos (mayor flexibilidad). * **Appenders Asíncronos**. ya existían en Log4j 1.x, pero se han mejorado para volcar a disco al final del lote (cuando la cola esta vacía). Es más eficiente, ya que todos los eventos de log estas siempre disponibles en disco, pero no se necesita tocar el disco en cada evento de log. (Appenders Asíncronos utilizan internamente la clase //ArrayBlockingQueue// y no necesitan de la libreria [[http://lmax-exchange.github.io/disruptor/|disruptor]].) * **Fast File Appenders**. Se pueden utilizar tanto en síncrona como asíncronamente. Son una alternativa a los //Buffered File Appenders//. Estos appenders utilizan un //ByteBuffer + RandomAccessFile// en lugar de //BufferedOutputStream//. Los beneficios son el aumento del rendimiento de la aplicación y la bajada de la latencia en las llamadas de log. El perjuicio es la gestión de errores. Si se produce un error durante el proceso y se lanza una excepción, es menos sencillo para un logger o appender asíncrono señalar el error a la aplicación. Se puede aliviar en parte utilizando un //ExceptionHandler//, pero no cubre todos los casos. Por esta razón, si el logging es utilizado como framework de auditoria, es recomendable utilizar los mecanismos síncronos, y dejar los asíncronos para debug/trace. Ejemplo de configuración mixta de loggers síncronos y asíncronos: %d %p %class{1.} [%t] %location %m %ex%n