Download Tema 3: Especificación de portlets Java - Anexo: JSR 286
Document related concepts
no text concepts found
Transcript
Tema 3: Especificación de portlets Java – Anexo: JSR 286 JSR 286 (1) JSR 286 es la versión 2.0 de la especificación de portlets Java La versión final de la especificación saldrá a lo largo del 2008 Principales características Compatibilidad hacia atrás El contenedor de portlets debe soportar Servlets 2.4 Es posible utilizar JSP 2.0 y JSTL 1.1 Mecanismos de coordinación entre portlets Es una extensión de la versión 1.0 Eventos y parámetros públicos de renderización Anotaciones Para los métodos que procesan peticiones de acción, renderización y eventos JSR 286 (2) Principales características (cont) Filtros de portlets Soporte para servir recursos Similar a los filtros de servlets Permite soportar interacciones AJAX Mejora el soporte para la gestión de la caché de las respuestas de los servlets Sincronizada con WSRP 2.0 Más información Especificación http://jcp.org/en/jsr/detail?id=286 Stefan Hepper, Oliver Köth, “What’s new in the Java Portlet Specification V2.0 (JSR 286)” http://www.ibm.com/developerworks/websphere/library/techar ticles/0803_hepper/0803_hepper.html JSR 286 (y 3) Nos centraremos especialmente en Mecanismos de coordinación entre portlets Especialmente en comunicación basada en eventos, y en menor medida en parámetros públicos de renderización Anotaciones Ilustraremos estos conceptos con un ejemplo Ejemplo (1) Una sencilla “mashup” formada por tres portlets Stock Symbol Finder My Stock Quotes Muestra las cotizaciones de los símbolos bursátiles añadidos por el usuario a sus preferencias Permite buscar la cotización de un símbolo bursátil My Stock Headlines Permite buscar símbolos bursátiles a partir de palabras clave del nombre de la empresa Muestra noticias de los símbolos bursátiles añadidos por el usuario a sus preferencias Permite buscar noticas de un símbolo bursátil Muestran la misma información en estado de ventana normal y maximized Capa modelo simplificada y simulada en los tres portlets Ejemplo (2) La búsqueda de símbolos bursátiles (Stock Quote Finder) está integrada con la funcionalidad de los portlets My Stock Quotes y My Stock Headlines Para cada símbolo bursátil resultante de la búsqueda (Stock Symbol Finder), se incluyen dos enlaces: “Buscar” y “Añadir a preferencias” Ambos enlaces generan un evento que es consumido por My Stock Quotes y My Stock Headlines En respuesta al evento del enlace “Buscar” , My Stock Quotes y My Stock Headlines muestran información de ese símbolo bursátil En respuesta al evento del enlace “Añadir a preferencias” , My Stock Quotes y My Stock Headlines añaden el símbolo bursátil a las preferencias Ejemplo (3) Click en “Buscar” (SMJ0) Ejemplo (4) Ejemplo (5) Click en “Añadir a preferencias” (SMJ0) Ejemplo (6) Ejemplo (y 7) Observación La mashup ofrece una funcionalidad similar a la del portlet Stock Quote Adicionalmente Proporciona búsqueda de símbolos bursátiles Integra la búsqueda de símbolos bursátiles con la funcionalidad de los portlets My Stock Quotes y My Stock Headlines Los portlets son más sencillos que el portlet Stock Quote La funcionalidad se ha descompuesto en portlets más pequeños Stock Symbol Finder – searchStockSymbol.jsp ... <c:forEach var="stockSymbol" items="${stockSymbols}" varStatus="status"> <portlet:actionURL var="searchStockSymbolURL"> <portlet:param name="javax.portlet.action" value="SearchStockSymbol"/> <portlet:param name="stockSymbol" value="${stockSymbol.symbol}"/> <portlet:param name="companyKeywords" value="${companyKeywords}"/> </portlet:actionURL> <portlet:actionURL var="addStockSymbolToPreferencesURL"> <portlet:param name="javax.portlet.action" value="AddStockSymbolToPreferences"/> <portlet:param name="stockSymbol" value="${stockSymbol.symbol}"/> <portlet:param name="companyKeywords" value="${companyKeywords}"/> </portlet:actionURL> ... Stock Symbol Finder – StockSymbolFinderPortlet (1) private final static QName SEARCH_STOCK_SYMBOL_EVENT = new QName("http://es.udc.portlets/events", "SearchStockSymbol"); private final static QName ADD_STOCK_SYMBOL_TO_PREFERENCES_EVENT = new QName("http://es.udc.portlets/events", "AddStockSymbolToPreferences"); // ... @ProcessAction(name="SearchStockSymbol") public void sendSearchStockSymbolEvent(ActionRequest request, ActionResponse response) throws PortletException, IOException { response.setRenderParameter("companyKeywords", request.getParameter("companyKeywords")); response.setEvent(SEARCH_STOCK_SYMBOL_EVENT, request.getParameter("stockSymbol")); } Stock Symbol Finder – StockSymbolFinderPortlet (y 2) @ProcessAction(name="AddStockSymbolToPreferences") public void sendAddStockSymbolToPreferencesEvent( ActionRequest request, ActionResponse response) throws PortletException, IOException { response.setRenderParameter("companyKeywords", request.getParameter("companyKeywords")); response.setEvent(ADD_STOCK_SYMBOL_TO_PREFERENCES_EVENT, request.getParameter("stockSymbol")); } Stock Symbol Finder – portlet.xml (1) <?xml version="1.0" encoding="UTF-8"?> <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0"> <portlet> <description> A portlet allowing to search stock symbols by company name </description> <portlet-name>StockSymbolFinderPortlet</portlet-name> ... Stock Symbol Finder – portlet.xml (2) <supported-publishing-event> <qname xmlns:x="http://es.udc.portlets/events">x:SearchStockSymbol</qname> </supported-publishing-event> <supported-publishing-event> <qname xmlns:x="http://es.udc.portlets/events">x:AddStockSymbolToPreference s</qname> </supported-publishing-event> </portlet> Stock Symbol Finder – portlet.xml (y 3) <event-definition> <qname xmlns:x="http://es.udc.portlets/events">x:SearchStockSymbol</qname> <value-type>java.lang.String</value-type> </event-definition> <event-definition> <qname xmlns:x="http://es.udc.portlets/events">x:AddStockSymbolToPreference s</qname> <value-type>java.lang.String</value-type> </event-definition> </portlet-app> Anotación ProcessAction El procesamiento de las peticiones de acción se podría haber implementado al estilo de la versión 1.0 Redefinir processAction + if’s para tomar decisión Anotación ProcessAction En la versión 2.0, la implementación de processAction en GenericPortlet intenta delegar el procesamiento de la petición de acción en un método anotado con ProcessAction, cuyo elemento name especifique el valor del parámetro javax.portlet.action Evita tener que redefinir processAction como una colección de if’s Los métodos anotados con ProcessAction se deben declarar como void <methodname> (ActionRequest, ActionResponse) throws PortletException, java.io.IOException; Definición de eventos Sincronizada con WSRP portlet.xml Los eventos se definen (event-definition) dentro de portlet-app El portlet tiene que declarar los eventos que publica (supported-publishing-event) y los que desea recibir (supported-processing-event) El tipo del valor del evento debe ser serializable (java.io.Serializable) y poder mapearse a XML vía JAXB (para eventos remotos) Un evento puede ser una estructura de datos compleja (e.g. un Transfer Object) Envío de eventos Un evento se puede enviar durante el procesamiento de una petición de acción o una petición de evento (se explica más adelante) Las interfaces ActionResponse y EventResponse extienden a la interfaz StateAwareResponse, que incluye el método void setEvent(QName name, Serializable value) El evento no se envía en este momento, sino que se añade a la respuesta (ActionResponse o EventResponse, dependiendo del tipo de petición) Para especificar el nombre del evento se utiliza javax.xml.QName Representa un nombre cualificado Forma parte del API de Java SE My Stock Quotes – MyStockQuotesPortlet (1) @ProcessEvent(qname="{http://es.udc.portlets/events}SearchStockSymbol") public void processSearchStockSymbolEvent(EventRequest request, EventResponse response) throws PortletException, IOException { Event event = request.getEvent(); String stockSymbol = (String) event.getValue(); // FIXME: in Liferay Portal 5.0.1 RC, getPortletMode always // returns PortletMode.VIEW. if (request.getPortletMode().equals(PortletMode.VIEW)) { response.setRenderParameter("stockSymbol", stockSymbol); response.setRenderParameter("command", "SearchStockQuote"); } } My Stock Quotes – MyStockQuotesPortlet (y 2) @ProcessEvent( qname="{http://es.udc.portlets/events}AddStockSymbolToPreferences") public void processAddStockSymbolToPreferencesEvent( EventRequest request, EventResponse response) throws PortletException, IOException { Event event = request.getEvent(); String stockSymbol = (String) event.getValue(); // FIXME: it does not work in Liferay Portal 5.0.1 RC. // "stockSymbol" is not added to preferences, even though // JSR 286 (section PLT.17.1) allows to modify them when // processing an event. addStockSymbolToPreferences(request, stockSymbol); } My Stock Quotes – portlet.xml (1) <?xml version="1.0" encoding="UTF-8"?> <portlet-app ...> <portlet> <description> A portlet allowing to monitor stock quotes </description> <portlet-name>MyStockQuotesPortlet</portlet-name> ... <!-- FIXME: disabled. In Liferay Portal 5.0.1 RC, the portlet's markup (in "view" mode) is not refreshed after sending an event to a portlet if its markup is cached. JSR 286 (section PLT.22.1) forces the portlet container to discard the portlet's cached markup after sending it an event. <expiration-cache>1200</expiration-cache> --> My Stock Quotes – portlet.xml (2) ... <supported-processing-event> <qname xmlns:x="http://es.udc.portlets/events">x:SearchStockSymbol</qname> </supported-processing-event> <supported-processing-event> <qname xmlns:x="http://es.udc.portlets/events">x:AddStockSymbolToPreference s</qname> </supported-processing-event> </portlet> My Stock Quotes – portlet.xml (y 3) <event-definition> <qname xmlns:x="http://es.udc.portlets/events">x:SearchStockSymbol</qname> <value-type>java.lang.String</value-type> </event-definition> <event-definition> <qname xmlns:x="http://es.udc.portlets/events">x:AddStockSymbolToPreference s</qname> <value-type>java.lang.String</value-type> </event-definition> </portlet-app> Anotación ProcessEvent El procesamiento de las peticiones de acción se podría haber implementado redefiniendo processEvent Conjunto de if’s para procesar cada evento Anotación ProcessEvent La implementación de processEvent en GenericPortlet intenta delegar el procesamiento del evento en un método anotado con ProcessEvent, cuyo elemento qname especifique el nombre del evento Evita tener que redefinir processEvent como una colección de if’s Los métodos anotados con ProcessEvent se deben declarar como void <methodname> (EventRequest, EventResponse) throws PortletException, java.io.IOException; Procesamiento de una petición de acción que devuelve un evento (1) Si una petición de acción devuelve un evento, el contenedor Invoca processEvent sobre todos los portlets consumidores de dicho evento Idem si processEvent también devuelve un evento Invoca render sobre todos los portlets cuyo contenido no esté cacheado o sean receptores del evento Procesamiento de una petición de acción que devuelve un evento (y 2) Portal Contenedor Portlet 1 1: Interacción (acción) sobre el portlet 1 1.1: processAction El usuario está actuando sobre una página que contiene los portlets 1, 2, ... N [consumidor del evento] 1.2: processEvent ... [consumidor del evento] 1.N+1: processEvent [consumidor del evento || respuesta no en caché] 1.N+2: render ... [consumidor del evento || respuesta no en caché] 1.2N+1: render ... Portlet N Parámetros públicos de renderización (1) Los parámetros públicos de renderización son otro mecanismo de coordinación entre portlets Un portlet puede declarar en portlet.xml los parámetros de renderización que desea compartir con otros portlets Esos parámetros se denominan parámetros públicos de renderización Al igual que los eventos, disponen de un nombre cualificado Se recuperan (request.getParameter) y establecen (response.setParameter) como cualquier otro parámetro de renderización Cuando un portlet le da valor a un parámetro de renderización que es público, el contenedor incluirá dicho parámetro en las invocaciones a render de los portlets que han declarado que desean compartirlo Son una opción eficiente y cómoda (no hay necesidad de hacer programación adicional) cuando varios portlets comparten un mismo conjunto de parámetros de renderización (parámetros públicos de renderización) Parámetros públicos de renderización (2) Ejemplo Portlet Weather: muestra el tiempo a partir de un código postal (parámetro zipCode) Portlet Map: muestra una ubicación geográfica en un mapa a partir de un código postal (parámetro zipCode) Portlet Tourist Information: muestra información turística a partir de un código postal (parámetro zipCode) Si los tres portlets declaran el parámetro zipCode como parámetro público de renderización, cuando el usuario introduzca el código postal en cualquiera de los tres portlets, los otros dos actualizarán su salida de acuerdo a ese código postal (porque el contenedor les pasa automáticamente ese parámetro) Parámetros públicos de renderización (3) Ejemplo: portlet.xml en el portlet Weather <?xml version="1.0" encoding="UTF-8"?> <portlet-app ...> <portlet> <portlet-name>WeatherPortlet</portlet-name> ... <supported-public-render-parameter> zipCode </supported-public-render-parameter> </portlet> <public-render-parameter> <identifier>zipCode</identifier> <qname xmlns:x="http://example.com/params">x:zipCode</qname> </public-render-parameter> </portlet.app> Parámetros públicos de renderización (y 4) El mecanismos de eventos Es un mecanismo general de comunicación En respuesta a un evento, el portlet puede modificar estado (e.g. cambiar preferencias, actualizar una base de datos, realizar una operación no idempotente, etc.), establecer parámetros de renderización o enviar un nuevo evento El dato del evento puede ser un tipo complejo El mecanismo de parámetros públicos de renderización Es un mecanismo cómodo y eficiente para el caso particular de portlets que comparten un conjunto de parámetros de renderización Otros aspectos del ejemplo (1) Anotación RenderMode La implementación de doDispatch (que es llamado por render) en GenericPortlet primero intenta delegar la petición en un método anotado con RenderMode, cuyo elemento name especifique el modo a tratar (view, edit o help Si no lo encuentra, delega en doView, doEdit o doHelp en función del modo La anotación no aporta mucho sobre la alternativa de los métodos doXXX El código de los ejemplos utiliza la anotación RenderMode por consistencia con el uso del resto de anotaciones Los métodos anotados con RenderMode se deben declarar como void <methodname> (RenderRequest, RenderResponse) throws PortletException, java.io.IOException; Otros aspectos del ejemplo (2) Anotación RenderMode (cont) Ejemplos @RenderMode(name="view") public void processViewMode (RenderRequest request, RenderResponse response throws PortletException, IOException { // ... } @RenderMode(name="edit") public void processViewMode (RenderRequest request, RenderResponse response throws PortletException, IOException { // ... } @RenderMode(name="help") public void processViewMode (RenderRequest request, RenderResponse response throws PortletException, IOException { // ... } Otros aspectos del ejemplo (3) JSP 2.0 Se usan expresiones JSP en las páginas JSP en cualquier situación y no sólo con los tags de JSTL Se usan páginas JSP (notación clásica) y no documentos JSP Código JSP más sencillo El markup que se devuelve es HTML y no XHTML, por lo que resulta más cómodo usar la notación clásica Librerías de tags JSTL 1.1 y librería de tags del API de portlets (versión 2.0) commonHeader.jsp (en cualquiera de los tres portlets) <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="portlet" uri="http://java.sun.com/portlet_2_0" %> Otros aspectos del ejemplo (y 4) Problemas con Liferay Portal 5.0.1 RC FIXMEs de las transparencias anteriores Además, cuando se interactúa con un portlet, no se conservan los parámetros de renderización del resto de portlets (lo que contraviene a la especificación) El problema se observa rápidamente en los portlets My Stock Quotes y My Stock Headlines, que tienen deshabilitada la caché (como especifica uno de los FIXMEs anteriores)