Suite de la série d’articles consacrée à GateIn et aux Portlets (voir article 1). Au menu aujourd’hui, une portlet simple capable d’afficher une liste de messages. L’objectif de cet article est de parler un peu plus du côté Java des Portlets 2.0, avant de revenir à GateIn plus tard.

Une Portlet comme vous allez vous en rendre compte, n’a rien de très visuel. Lorsque l’on pense Portlet au départ, on imagine une petite fenêtre dans une page web, avec des boutons maximiser/réduire/configurer. Or c’est le portail qui donne cet habillage, pas la spécification des Portlets en elle-même.

Nous allons utiliser encore ici ce qu’il y a de plus simple, à savoir des pages JSP sans outils supplémentaires. Nous verrons dans quelques articles comment écrire une Portlet avec JSF 1.2 et comment utiliser le bridge JSF 2.0 de GateIn.

Une portlet c’est avant tout une application web java avec un fichier web.xml. Liferay 5.2 part d’un fichier web.xml, et le décore lors du déploiement dans le conteneur d’application. Cela peut sembler séduisant au premier abord : un fichier web.xml vide complètement anonyme par rapport au portail. Mais il n’y a pas de magie, Liferay se contente de réécrire sa version du fichier web.xml dans le répertoire webapps du conteneur Tomcat.

Concernant GateIn, notre fichier web.xml déclare un PortletApplicationListener et un ServletWrapper. Le fichier web.xml d’une portlet sera différent pour chaque portail : Apache Pluto, Jahia, Liferay et donc GateIn. C’est une des limites de la portabilité des portlets. Peut-être que la solution du fichier web.xml vide pour Liferay est la voie à suivre, je ne sais pas.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
                         "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
	<display-name>texpress-portlet</display-name>

	<listener>
		<listener-class>org.exoplatform.services.portletcontainer.impl.servlet.PortletApplicationListener</listener-class>
	</listener>

	<servlet>
		<servlet-name>PortletWrapper</servlet-name>
		<servlet-class>org.exoplatform.services.portletcontainer.impl.servlet.ServletWrapper</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>PortletWrapper</servlet-name>
		<url-pattern>/PortletWrapper</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>PortletWrapper</servlet-name>
		<url-pattern>/PortletWrapper/*</url-pattern>
	</servlet-mapping>
</web-app>

Voyons maintenant ce qui est vraiment du domaine des Portlets, le fichier portlet.xml. Placé dans le répertoire WEB-INF, ce fichier permet de déclarer la liste des Portlets contenues dans l’archive. Pour notre exemple nous allons pour l’instant déclarer qu’une seule portlet Java :

<?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="1.0">

	<portlet>
		<description xml:lang="EN">Twitter Portlet sample 01, this portlet demonstrates the processAction method</description>
		<portlet-name>TwitterPortlet01</portlet-name>
		<portlet-class>org.letouilleur.portlet.TwitterPortlet01</portlet-class>
		<supports>
			<mime-type>text/html</mime-type>
			<portlet-mode>view</portlet-mode>
		</supports>
		<portlet-info>
			<title>Twitter Portlet 01</title>
			<keywords>demo</keywords>
		</portlet-info>
	</portlet>

</portlet-app>

La portlet TwitterPortlet01
J’aimerai écrire une Portlet capable d’afficher les 10 derniers tweets de mon compte Twitter. A terme je veux pouvoir configurer le nom de la personne que je regarde, et je veux aussi pouvoir informer d’autres Portlets lorsque je change le nom du compte Twitter. Dans un premier temps nous allons simplement compiler et déployer notre Portlet sur GateIn. Si vous ne l’avez pas encore lu, lisez mon article précédent sur GateIn afin d’apprendre à déployer une Portlet sur GateIn.

Je vous ai préparé un petit projet maven avec une portlet toute simple pour cet article. Téléchargez le fichier zip ici et décompressez-le dans un répertoire.

Compilez le projet avec Maven 2.2.1, et Java 6. Et enfin recopiez le fichier WAR vers le répertoire webapps de GateIn. Après avoir ajouté la Portlet dans une nouvelle page, voici ce que vous devez obtenir à l’écran :
gatein_portlet01

Pour ajouter la portlet, relisez l’article de la semaine dernière

Notre portlet a un bouton Submit qui va récupérer mes derniers messages sur Twitter. Pour l’instant, nous allons simuler cette étape, et simplement afficher une liste envoyée par la Portlet. Ouvrez le code Java de la class TwitterPortlet01 et regardons ensemble la fin du fichier.

  @Override
    public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
        java.util.List<String> tweets = new ArrayList<String>();
        tweets.add("Premier Tweet");
        tweets.add("Deuxième Tweet");
        tweets.add("Troisième Tweet");

        request.getPortletSession().setAttribute("tweets", tweets);

    }

Là où une Servlet dispose d’une méthode doGet ou doPost, une Portlet s’abstrait du protocole et déclare 2 phases. Une phase de rendu et une phase d’action. La phase de rendu correspond simplement à un affichage de la portlet. La phase d’action est activée lorsque vous envoyez un formulaire par exemple à partir de la partie Web de l’application. Enfine une phase de rendu est toujours lancé après une phase d’action. Dans notre cas, la méthode doView est appelé lors de la phase « Render ». Ensuite lorsque vous cliquez sur « Get tweets », la phase « Action » est déclenchée et nous passerons dans la méthode processAction. Celle-ci place dans la session de la portlet une liste de String, et la phase de « Render » est appelée, ce qui provoque l’affichage de la liste dans le fichier normal.jsp. Nous verrons plus loin comment déclarer des attributs de rendus publics, et comment aussi envoyer des événements entre Portlet. Pour l’instant, tout ce que nous faisons est relativement simple.

Il est possible d’utiliser aussi des annotations avec les Portlets 2.0. Il est donc possible d’ajouter une annotation @ProcessAction(name=’theActionName’) afin de dispatcher automatiquement un appel entrant vers une méthode. Dans le cas où une méthode est annotée avec ProcessAction, il faut par contre retirer la méthode générique processAction de GenericPortlet, faute de quoi aucun appel ne sera effectué vers votre méthode annotée.

Du côté de la JSP
Ouvrez maintenant la page « normal.jsp » situé dans le répertoire web-apps. Tout d’abord on notera la présence d’une nouvelle taglib pour les Portlets 2.0, qui permet de déclarer automatiquement un certain nombre d’objets pratiques.

<%@ page import="java.util.List" %>
<%@ page pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<portlet:defineObjects/>
<div id="content">
 <img src="<%=renderResponse.encodeURL(renderRequest.getContextPath())%>/logo.jpg" alt="Logo" align="top"/>
    <h2>GateIn Twitter Portlet</h2>
    <h4>Latest Twitter statuses from Letouilleur</h4>
    <%
        List<String> tweets = (List<String>) portletSession.getAttribute("tweets");
        if (tweets != null) {
            out.println("<ul>");
            for (String tweet : tweets) {
                out.print("<li>");
                out.print(tweet);
                out.println("</li>");
            }

            out.println("</ul>");
        }
    %>

    <portlet:actionURL var="myAction" portletMode="view"/>

    <form action="<%=myAction%>" method="post">
        <input type="submit" value="Get Tweets from Letouilleur"/>
    </form>
</div>

Le tag <portlet:defineObject> permet de déclarer automatiquement un certain nombre d’objets pour notre page JSP. Dans notre exemple cela permet de construire l’URL de l’image du logo du blog le Touilleur Express :

<img src="<%=renderResponse.encodeURL(renderRequest.getContextPath())%>/logo.jpg"
            alt="Logo"
            align="top"/>
 

Nous pouvons aussi récupérer la session de la portlet afin de retrouver notre liste de messages

List<String> tweets = (List<String>) portletSession.getAttribute("tweets");
...

Pour construire l’URL de la FORM il suffit d’utiliser le tag actionURL comme dans cet exemple:

   <portlet:actionURL var="myAction" portletMode="view"/>

   <form action="<%=myAction%>" method="post">

Enfin voici le résultat lorsque l’on clique sur le bouton Submit :

gatein_portlet_action

Conclusion
J’ai présenté un exemple simple dans cet article en vous expliquant le principe des 2 phases des Portlets, ainsi que l’utilisation de la taglib des Portlets. Nous verrons dans un prochain article comment gérer encore plus de fonctionnalités des Portlets avec GateIn. Le prochain article sera disponible la semaine prochaine, voici une capture d’écran pour vous faire patienter:

]portlet_article03
Le prochain article sera publié le 27 novembre.

A bientôt

Le code source de l’article est disponible à cette adresse.

3 réflexions sur « GateIn : découverte d'une Portlet simple (article 2) »

  1. En fait web.xml peut rester vide, ici tu utilises le fait qu’on supporte les anciens web.xml d’eXo Portal, mais dans GateIn on a ajoute le module deja utilise dans JBoss Portal qui permet de faire de la magie (Sans reecrire le fichier 😉 )

Les commentaires sont fermés.