Suite de notre série consacrée à GateIn et aux Portails. Aujourd’hui au menu, dernier article de la partie purement Portlet. Nous allons voir comment gérer les préférences d’une Portlet, puis comment envoyer un message pour que d’autres Portlets soient notifiées.

Installation
Comme dans l’article précédent, je vous ai préparé un projet maven avec le code et l’ensemble compilé si vous voulez tester rapidement. Télécharger le fichier portlet_article03.zip et décompressez-le dans un répertoire différent. Vous pouvez ensuite soit lancer le projet IDEA IntelliJ, soit le project Eclipse (mvn eclipse:eclipse).

Le fichier war doit être recopié dans le répertoire webapps de votre installation de GateIn. Vous devez avoir lu le premier article pour savoir comment ajouter une Portlet à GateIn la première fois. Pour le reste, c’est assez simple.

Les Préférences des Portlets
Voici ce que nous allons faire: nous allons déclarer une propriété de configuration afin que le nom du compte Twitter soit configurable. Lorsque la Portlet sera en mode EDIT, vous pourrez configurer le nom du compte Twitter à afficher. Enfin le mode configuration de GateIn vous montrera aussi votre propriété.

La spécification des Portlets vous donne un objet PortletPreferences afin de stocker les paramètres de configuration de la Portlet. Par exemple l’adresse d’un serveur REST distant pour récupérer une liste de médicament (au hasard). Les propriétés d’une Portlet sont spécifiques à chaque utilisateur. Par ailleurs, elles sont sauvegardées lorsque vous arrêtez le serveur. Nous verrons cela tout à l’heure.

Comment utiliser une propriété d’une Portlet
Nous allons tout d’abord regarder ce que j’ai déclaré dans le fichier portlet.xml. La balise portlet-preferences permet de déclarer des couples clés/valeurs, comme un fichier de propriétés. J’ajoute ici une nouvelle propriété « defaultScreenName »

<portlet>
       <description>Twitter Portlet sample 02, this portlet demonstrates how to set and display
           a public portlet render parameter.
       </description>
       <portlet-name>TwitterPortlet02</portlet-name>
       <portlet-class>org.letouilleur.portlet.TwitterPortlet02</portlet-class>
       <supports>
           <mime-type>text/html</mime-type>
           <portlet-mode>view</portlet-mode>
           <portlet-mode>edit</portlet-mode>
       </supports>
       <portlet-info>
           <title>Twitter Portlet 02</title>
           <keywords>demo</keywords>
       </portlet-info>
       <portlet-preferences>
           <preference>
               <name>defaultScreenName</name>
               <value>Letouilleur</value>
           </preference>
       </portlet-preferences>

   </portlet>

Cette propriété sera configurée à « Letouilleur » pour les utilisateurs n’ayant pas encore personnalisé la valeur.

Regardez maintenant le fichier viewPortlet02.jsp. Cette page est la page du mode VIEW de la portlet TwitterPortlet02. Elle affichera le nom du compte. Voici comment je récupère les préférences afin d’afficher le nom du compte Twitter:

<%
       String tweeterAccount=renderRequest.getPreferences().getValue("defaultScreenName", "Anonymous");
%>

   <h4>Latest Twitter statuses from <font color="blue"><%=tweeterAccount%></font></h4>

Comment modifier la propriété ?
La portlet TwitterPortlet02 est déclarée avec 2 états dans le fichier portlet.xml : EDIT et VIEW. Lorsqu’elle bascule en mode EDIT, il est possible de changer le nom du compte Twitter.

Voici la vue de la Portlet en mode VIEW :
article03_view

Voici la Portlet en mode EDIT :
article03_edit

Que se passe-t-il lorsque l’on clique sur le bouton « Soumettre » ? Comme vu dans l’article précédent, cela déclenche la phase Action de la Portlet. Dans la class TwitterPortlet02, regardez le code de la méthode processAction:

@Override
public void processAction(ActionRequest request, ActionResponse response)
						throws PortletException, IOException {

   if (request.getPortletMode().equals(PortletMode.EDIT)) {
            sendActionEvent(request, response);
   }

   // ....

}

//....

private void sendActionEvent(ActionRequest request, ActionResponse response)
							throws PortletModeException, ReadOnlyException,
								   IOException, ValidatorException {
	// Recupere le parametre envoye par le formulaire HTML
	String screenName = request.getParameter("screenName");

	// Change la valeur de la preference
	PortletPreferences prefs=request.getPreferences();
	prefs.setValue("defaultScreenName",screenName);
	prefs.store();

    // ...

	// back to view mode
	response.setPortletMode(PortletMode.VIEW);
 }

Il est important de bien penser à appeler la méthode store() afin que la nouvelle valeur de la propriété soit stockée par le Portail. Est-ce que vous vous rendez compte que c’est le Portail qui va stocker cette nouvelle valeur ? Si vous n’êtes pas convaincu, arrêter et relancez GateIn, reconnectez-vous avec le même utilisateur, vous verrez que la valeur a été persisté par GateIn.

Il y a quelques détails à connaître : tout d’abord le contenu du PortletPreferences ne peut être modifié que dans la méthode processAction(). Il y a aussi une méthode reset() que vous pouvez appeler pour remettre les préférences à un état stable avant vos changements. Pratique lorsqu’une exception survient.

Il est temps maintenant d’informer les autres Portlets que vous venez de changer le nom du compte Twitter.

Envoyer un événement JSR-286 avec une Portlet
Voici ce que je veux faire : lorsque l’utilisateur change le nom du compte Twitter, j’aimerai que ma Portlet envoie aux autres Portlets la valeur de ce compte. Imaginons une autre Portlet qui par exemple recherche sur des flux RSS en se basant sur le nom d’un compte Twitter, ou d’un tag (comme #devoxx).

Pour envoyer un événement, il faut tout d’abord le déclarer dans le fichier portlet.xml

(fichier portlet.xml)

<event-definition>
    <name>myEvent</name>
    <value-type>java.lang.String</value-type>
</event-definition>

Pour que le Portail surveille notre Portlet TwitterPortlet02, il convient maintenant de dire que cette Portlet peut émettre cet événement. Dans la balise portlet, j’ajoute à la fin un tag « supported-publishing-event »


<portlet>
    <description>Twitter Portlet sample 02, this portlet demonstrates how to set and display
        a public portlet render parameter.
    </description>
    <portlet-name>TwitterPortlet02</portlet-name>
    <portlet-class>org.letouilleur.portlet.TwitterPortlet02</portlet-class>
    <supports>
        <mime-type>text/html</mime-type>
        <portlet-mode>view</portlet-mode>
        <portlet-mode>edit</portlet-mode>
    </supports>
    <portlet-info>
        <title>Twitter Portlet 02</title>
        <keywords>demo</keywords>
    </portlet-info>
    <portlet-preferences>
        <preference>
            <name>defaultScreenName</name>
            <value>Letouilleur</value>
        </preference>
    </portlet-preferences>


    <supported-publishing-event>
        <name>myEvent</name>
    </supported-publishing-event>

</portlet>

Enfin, nous voulons que la portlet TwitterPortlet01 écoute cet événement. Pour cela, voici la définition de la portlet TwitterPortlet01. Nous ajoutons un tag « supported-processing-event » avec le nom du tag.


<portlet>
    <description>Twitter Portlet sample 01, this portlet demonstrates the processAction method.</description>
    <portlet-name>TwitterPortlet01</portlet-name>
    <portlet-class>org.letouilleur.portlet.TwitterPortlet01</portlet-class>
    <expiration-cache>0</expiration-cache>
    <supports>
        <mime-type>text/html</mime-type>
        <portlet-mode>view</portlet-mode>
    </supports>
    <supported-locale>fr</supported-locale>
    <supported-locale>en</supported-locale>

    <portlet-info>
        <title>Twitter Portlet 01</title>
        <keywords>demo</keywords>
    </portlet-info>

    <supported-processing-event>
        <name>myEvent</name>
    </supported-processing-event>

</portlet>

A savoir : si les 2 portlets sont distribuées dans 2 WAR différents, il faut déclarer un element QName afin de qualifier le domaine de l’élément. Par ailleurs l’ordre des tags dans le fichier portlet.xml est déterminant pour GateIn. Si vous souhaitez déclarer qu’une portlet est capable d’émettre comme de recevoir un événement, attention à l’ordre de déclaration dans le fichier portal.xml.

     <supported-publishing-event>
         <name>myEvent</name>
     </supported-publishing-event>


     <supported-processing-event>
         <name>anotherEvent</name>
     </supported-processing-event>

     <supported-processing-event>
         <name>andYetAnotherEvent</name>
     </supported-processing-event>

Envoyer un événement
L’envoi est très simple. Dans la phase d’Action d’une Portlet, il suffit d’appeler la méthode setEvent sur l’object ActionResponse. Regardez le code de la méthode sendActionEvent de TwitterPortlet02, voici comment la valeur du nouveau compte Twitter est envoyé au Portail


        // Send an event
        response.setEvent("myEvent", screenName);

Recevoir un événement
La réception de l’événement par la Portlet TwitterPortlet01 est effectué dans la méthode processEvent, héritée de GenericPortlet. La nouvelle valeur du compte Twitter est lue puis stockée comme nouvelle valeur de myPublicScreenName.

 /**
     * This callback method is triggered when a "myEvent" JSR-286 event
     * is sent to the Portal.
     */
    @Override
    public void processEvent(EventRequest request, EventResponse response) {
        Event event = request.getEvent();
        if (event.getName().equals("myEvent")) {
            String payload = (String) event.getValue();
            //process payload here
            System.out.println("------------------------------------------------------");
            System.out.println(getClass().getName() + " received an event: " + payload);
            System.out.println("------------------------------------------------------");

            // Update the property, the Portal will then call the doView
            // to redisplay the page
            myPublicScreenName=payload;

        }
    }

Après l’appel de la phase Action de cette Portlet, le portail appelle ensuite automatiquement une phase Render, ce qui pour a effet d’appeler la méthode doView de TwitterPortlet01. Je stocke alors la nouvelle valeur dans la session de la Portlet, c’est tout.

    public void doView(RenderRequest request, RenderResponse response)
            throws PortletException, IOException {

        if (WindowState.MINIMIZED.equals(request.getWindowState())) {
            return;
        }


        // Set the last value of myPublicScreenName
        request.getPortletSession().setAttribute("myPublicScreenName",myPublicScreenName);

        if (WindowState.NORMAL.equals(request.getWindowState())) {
            normalView.include(request, response);
        } else {
            maximizedView.include(request, response);
        }

    }

Enfin pour terminer, l’affichage de la nouvelle valeur s’effectue dans la page « normal.jsp » à la fin de la page:


    <% String publicParam =(String)portletSession.getAttribute("myPublicScreenName");%>
  <% if (publicParam != null && !publicParam.equals("")) { %>
      The other Portlet is configured to display <strong><%=publicParam%></strong>
  <% } %>

Le résultat final
Voici une suite de captures d’écran, afin de vous montrer le résultat :

Etape 1:
article03_portlet_step01

Etape 2:
article03_portlet_step02

Etape 3:
article03_portlet_step03

Conclusion
Dans ce troisième article nous avons vu comment lire et éditer les préférences d’une Portlet. Nous avons ensuite vu comment créer un message, l’envoyer et enfin le consommer dans une autre Portlet. Les prochains articles seront moins bas niveaux que celui-ci mais j’ai pensé qu’il serait intéressant de vous montrer les bases des Portlets 2.0

Voir aussi les 2 anciens articles:
Premiers pas avec GateIn, comment installer une Portlet
GateIn, découverte d’une Portlet simple

Une pensée sur « GateIn: gestion des Préférences et communication entre Portlets (article 3) »

Les commentaires sont fermés.