Portale und Portlets (1) – Grundlagen

Andy Bosch

Portale bieten bereits ohne aufwendige Eigenentwicklung einen großen Funktionsumfang. Mit den standardisierten Java Portlets lassen sich wiederum sehr elegant einzelne Portalbausteine entwickeln – und seitdem Portlet 2.0 verfügbar ist, sind noch weitere Funktionalitäten hinzu gekommen.

Die Portal- und Portlet-Technologie ist kein Hypethema. Vielmehr haben sich diese Technologien langsam, dafür aber sehr kontinuierlich in den letzten Jahren durchgesetzt und Einzug in viele Unternehmen gehalten. Sicherlich, zu den Hochzeiten der dot.com-Ära waren Portale fast so etwas wie ein Garant für hohe Firmenbewertungen und Millioneneinnahmen bei den Investoren. Doch dieses Bild hat sich in den letzten Jahren stark relativiert. Während viele Firmen die damalige Zeit nicht überlebt haben, hat sich die gesamte Portaltechnologie nicht nur gehalten, sondern auch stark weiterentwickelt. Die Portaltechnologie ist eine der wichtigsten Technologien für umfangreiche, komplexe und dynamische Webprojekte.

Die vorliegende Artikelserie führt in die Welt der Portale und Portlets ein. Zunächst wird im ersten Teil auf die Grundlagen von Portalen und Portlets eingegangen und ein kurzer Abriss über die Portlet-Spezifikationen gegeben. In den folgenden Artikeln wird auf die neuen Funktionen der aktuellen Portlet-Spezifikation 2.0 (JSR-286) eingegangen. Im letzten Teil der Artikelserie werden die Vorteile einer Kombination von Portlets und den JavaServer Faces vorgestellt (JSR-301).

Bevor wir uns die Technologie von der technischen Seite anschauen, sollen zunächst die Begriffe „Portal“ und „Portaltechnologie“ geklärt werden. Der Portalbegriff ist an sich nirgendwo spezifiziert oder definiert. Selbst Wikipedia liefert lediglich eine eher allgemeine Einführung dazu. Oftmals wird der Begriff des Portals (fälschlicherweise) für Webseiten eingesetzt, die ein etwas größeres Angebot aufweisen können, sich einem speziellen Thema widmen oder auch redaktionell betreut sind. Schnell ist die Rede von einem „Portal für IT-Berater“ oder dem zentralen „Ferrari-Portal für Europa“. Doch sind diese Webseiten tatsächlich Portale? Nach der Meinung des Autors eher nicht. Vielmehr ist ein Portal ein System, das folgende Charakteristika vorweisen kann:

  • Aggregation von Inhalten und Services
  • Personalisierung
  • Content-Management
  • Single Sign-on
  • Zentrale Security-Aspekte

Diese Liste ist natürlich nicht vollständig, zeigt jedoch eine Anforderung an heutige Portallösungen. Somit versteht sich von selbst, dass nicht jede Website als Portal bezeichnet werden kann. Dagegen kann der Portalauftritt von Google – iGoogle – zu Recht als Portal verstanden werden (Abb.1).

Abb.1: iGoogle

Es ist möglich, sich in iGoogle zu registrieren und anzumelden. Dabei genügt eine Anmeldung in iGoogle für sämtliche darin enthaltenen Funktionen (Kriterium: Single Sign-on). Einmal im Portal angemeldet, können eigene Einstellungen der Portlets (Welche Portlets möchte ich sehen? Welche Informationen sollen sie liefern etc.?) abgespeichert werden. (Kriterium: Personalisierung). In iGoogle sind verschiedenste Dienste zusammengefasst. So können aktuelle Nachrichten von Financial Times Deutschland oder von JAXenter.de angesehen werden, Börsenticker, eine Wettervorhersage oder auch den Witz des Tages (Kriterium: Aggregation von Diensten und Inhalten).

Um solche Portale aufzubauen, muss man natürlich nicht in jedem Projekt auf der grünen Wiese beginnen. Auf dem Markt gibt es mittlerweile zahlreiche Lösungen von kommerziellen Anbietern (IBM WebSphere Portal, Oracle Portal, BEA Web Portal etc.) sowie von Open-Source-Initiativen (JBoss Portal, Liferay Portal, Apache Jetspeed etc). Zwar weisen alle Portalsysteme oftmals ähnliche Funktionalitäten auf, im Detail existieren grundlegende Unterschiede. Es existiert leider (noch) kein Standard für Portale!

[ header = Seite 2: Über Portale zu Portlets ]

Über Portale zu Portlets

Ein typisches Merkmal von Portalen ist, wie bereits beschrieben, die Aggregation von Inhalten und Diensten. In der Regel besteht eine Portalseite aus mehreren Bausteinen. Diese einzelnen Bausteine sind die Portlets, in denen eine Anwendung ablaufen kann. Portlets sind somit (Web-) Anwendungen, die innerhalb eines so genannten Portlet-Containers ablaufen können. Dabei ist ein Portlet-Container der Lebensraum für Portlets, ähnlich wie ein Servlet-Container ein Lebensraum für Servlets ist. Portlets sind im Gegensatz zu Portalen standardisiert. Bereits 2003 wurde der erste Portlet-Standard, der JSR-168, im Rahmen des Java Community Process verabschiedet. Dieser definiert, wie ein Portlet funktioniert, welche Interfaces notwendig sind und wie Funktionalität mit Portlets umgesetzt werden kann. Der JSR-168 behandelt die grundlegenden Fragestellungen für eine Portlet-Entwicklung. Da dieser Standard schon einige Jahre alt ist und auch viele Fragen nicht beantwortet wurden, wurde im Sommer dieses Jahres eine neue Version dieses Standards veröffentlicht: der JSR-286 (wird auch als Portlet 2.0 bezeichnet). Da heutzutage moderne UI-Frameworks wie JavaServer Faces fast unabkömmlich sind, wird aktuell innerhalb des JSR-301 eine Brückenlösung zwischen JSF und Portlets erarbeitet.

Der Portlet-Lebenszyklus

Portlets leben in einem Portlet-Container. Innerhalb dieses Containers durchlaufen Portlets einen fest definierten Lebenszyklus (Abb. 2). Dieser erinnert stark an Servlets, weist jedoch einige Besonderheiten auf.

Abb. 2: Portlet Lifecycle

Werden Portlets in einem Container verfügbar gemacht, wird zunächst die Init-Phase durchlaufen. Hierin können entsprechende Initialisierungsfunktionalitäten aufgenommen werden. Ebenso steht eine Destroy-Phase zur Verfügung, wenn das Portlet außer Betrieb genommen wird. Sowohl die Init- wie auch die Destroy-Phase werden nur einmal durchlaufen, es sei denn, ein Portlet wird nach dem Destroy wieder erneut in Betrieb genommen. Am wichtigsten bzw. auch charakteristisch für Portlets sind die Phasen Render und Action, die beliebig häufig aufgerufen werden können. Hintergrund ist folgender: Portlets sind in der Regel nicht alleine auf einer Portalseite angeordnet, sondern teilen sich den Platz mit anderen Portlets. Jetzt kann auf einer Seite in einem speziellen Portlet eine Aktion angestoßen werden, z.B. ein Submit-Button gedrückt werden. Als Folge muss eine Aktion speziell für dieses eine Portlet ausgelöst werden. Da danach jedoch die komplette Seite neu dargestellt (also gerendert) werden muss (Ajax lassen wir hier bewusst außer Acht), muss dazu jedes Portlet seinen Output neu erzeugen. Aus diesem Grund sind die beiden Phasen als getrennt realisiert. Es muss nicht jedes Mal zunächst eine Aktion und dann ein Rendering angestoßen werden, es kann durchaus nur ein Rendering in einem Portlet aufgerufen werden (ohne Aktion). Per Definition wird eine Aktion in der Action-Phase ausgeführt, die Render-Phase erzeugt lediglich Markup. Die Portlet-API spiegelt genau diesen Lebenszyklus wider.

Ein erstes Portlet

Ein erstes einfaches Portlet erhält man, wenn eine Klasse das Interfaces javax.portlet.Portlet implementiert. Dieses Interface definiert Methoden für die oben erwähnten Lebenszyklusphasen. Die erwähnten Action- und Render-Phasen werden durch die Methoden render und processAction abgebildet. Ebenso stellt das Interface die Methoden init und destroy bereit. In der Praxis wird jedoch äußerst selten das Portlet-Interface direkt implementiert. Vielmehr wird die Convenience-Klasse javax.portlet.GenericPortlet verwendet, die ebenfalls durch die Spezifikation festgelegt ist. Darin sind bereits alle notwendigen Methoden implementiert und mit nützlichen Basisfunktionen ausgestattet. Üblicherweise leitet ein eigenes Portlet von GenericPortlet ab und überschreibt die relevanten Methoden. So existieren z.B. schon Methoden für die einzelnen Window States und Portlet Modes, sodass sehr komfortabel eine Methode doView, doEdit oder doHelp verwendet werden kann, anstatt in der selbst implementierten render-Methode dies extra auswerten zu müssen. In Listing 1 ist ein einfaches Portlet abgebildet, das lediglich einen Willkommenstext ausgibt.

public class HelloWorld extends GenericPortlet{

@Override
protected void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println( "Hallo neue Portlet Welt" );
writer.println( "<br><br>" );
writer.println( "Herzlichen Glückwunsch zum ersten Portlet !!!" );
writer.println( "<br><br>" );
}
}

Neben der Portlet-Klasse ist für ein Deployment in einem Portlet-Container zudem ein entsprechender Deployment-Deskriptor notwendig. Der Deskriptor wird durch eine Datei portlet.xml realisiert, die parallel zur web.xml im WEB-INF-Verzeichnis der Anwendung abgelegt ist. Dieser gibt an, mit welchem Namen das Portlet angesprochen werden kann, wie die Portlet-Klasse lautet, welche Portlet Modes unterstützt werden und vieles mehr. Abbildung 2 zeigt den Ausschnitt aus einem Deployment-Deskriptor. Ansonsten ist ein Portlet-Projekt analog zu einem Webprojekt aufgebaut.

<?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>HalloWelt Beispiel</description>
<portlet-name>HalloWeltPortlet</portlet-name>
<portlet-class>de.jsfportlets.sample.portlet.HelloWorld</portlet-class>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<portlet-info>
<title>Hallo Portlet Welt</title>
</portlet-info>
</portlet>
</portlet-app>

[ header = Seite 3: Portlets und JSP ]

Portlets und JSP

Die ersten Beispiele von Portlets direkt mit der Portlet-API erinnern natürlich zunächst an die frühen Anfänge der Servlet-Programmierung. Html-Markup wird in der Java-Klasse implementiert. Dies ist natürlich nicht gerade eine moderne Weise der Markup-Generierung und Seitenerzeugung. In der Portlet-Spezifikation ist daher eine Verwendung und Integration von JavaServer Pages (JSP) vorgesehen. Erster Ansprechpartner für den Portlet-Container bleibt zunächst eine Portlet-Klasse. Diese kann für die Markup-Erzeugung an eine JSP delegieren. Damit lässt sich sehr schön ein Model-View-Controller-Muster umsetzen. Die Portlet-Klasse bildet den Controller, der für die Anzeige an die zuständige JSP (View) delegiert.

protected void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
PortletContext context = getPortletContext();
PortletRequestDispatcher dispatcher
= context.getRequestDispatcher( "/simple.jsp" );
dispatcher.include( request, response );
}

<%@ taglib uri="http: //java.sun.com/portlet" prefix="portlet" %>

<portlet:actionURL var="submitUrl" />
<form method="POST" action="${submitUrl}">
Ihr Name: <input type="text" name="name" value="${name}" />
<br/>
<input type="submit" />
</form>

In Listing 4 wird das Markup in einer JSP erzeugt. Dabei wird eine spezielle Tag Library, die Portlet Taglib, verwendet. Mit der Portlet Tag Library kann auf Portlet-spezifische Funktionalität zugegriffen werden. So erzeugt das Tag eine Url, mit der auf eine Action-Phase verwiesen wird. Damit wird im Portlet bei Abschicken des Formulars die processAction-Methode ausgeführt, anschließend wird die doView-Methode aufgerufen und das neue Markup generiert. Ist eine entsprechende processAction-Methode in der Portlet-Klasse nicht implementiert, wird eine PortletException geworfen.

Window States und Portlet Modes

Portlets weisen zwar viele Ähnlichkeiten zu Servlets auf, es gibt jedoch auch sehr deutliche Unterschiede. Während eine Webanwendung basierend auf der Servlet-Technologie im Normalfall immer Markup erzeugt, das seitenfüllend ist, haben Portlets nur einen bestimmten Bereich einer Portalseite zur Verfügung. So kann mit den Portlet Window Controls der Platzbedarf eines Portlets beeinflusst werden. Durch die Spezifikation sind die Window States minimized, maximized und normal vorgegeben. Wie genau diese drei States umgesetzt sind, bleibt dem Portal überlassen. In der Regel ist im minimized State lediglich der Fenstertitel zu lesen, alles andere wird ausgeblendet. Bei maximized werden alle anderen Portlets der Seite minimiert und dem betreffenden Portlet der maximal verfügbare Platz zugestanden. Normal ist der standardmäßige, übliche Platzbedarf, der meist durch ein Portal-Skin oder Theme vorgegeben wird.

Abb. 3: Minimierte Fenster in iGoogle

Eine weitere Besonderheit von Portlets ist der Portlet Mode. Standardmäßig befinden sich Portlets immer im View-Mode: Das Portlet stellt sich dar und kann Aktionen verarbeiten. Soll das Portlet jedoch konfiguriert werden (z.B. die Eingabe einer Postleitzahl für ein Wetter-Portlet), kann diese Einstellung im Edit-Modus vorgenommen werden. Für die Anzeige der Wettervorhersage wird für einen Benutzer das Portlet so konfiguriert, dass er die Anzeige für seine Stadt nach dem Login in das Portal erhält. Dies ist übrigens auch ein sehr schönes Beispiel für Personalisierung: Jeder Benutzer kann seine Portlets auf seine Bedürfnisse hin anpassen und konfigurieren. Auf Window States und Portlet Modes kann (und sollte natürlich) programmatisch reagiert werden. Beispielsweise kann in der doView-Methode abgefragt werden, welchen Platzbedarf man ausfüllen darf. Über den Aufruf request.getWindowState() wird ermittelt, in welchem Window State sich das Portlet aktuell befindet. Daraufhin kann ein entsprechendes Markup erzeugt werden. Für die Portlet Modes bietet das GenericPortlet bereits Methoden für die Standard-Portlet-Modes an. Es kann eine doView- oder eine doEdit-Methode überschrieben werden, die das entsprechende Markup zurückliefert. Zusätzlich muss in der portlet.xml angegeben werden, dass auch der Edit-Modus verfügbar ist (der View-Modus ist obligatorisch für alle Portlets).

[ header = Seite 4: Render-Parameter ]

Portlet vs. Portlet-Applikation
Häufig werden die Begriffe Portlet und Portlet-Applikation synonym verwendet. Dies ist jedoch nicht korrekt. Ein Portlet bezeichnet eine Klasse, die das Portlet-Interface implementiert und somit als Portlet fungieren kann. Unter einer Portlet-Applikation wird das gesamte Webprojekt verstanden, inklusive Deployment-Deskriptoren und sonstigen Ressourcen. Eine Portlet-Applikation wird in der Regel als war-Datei deployt. Innerhalb einer Portlet-Applikation kann es durchaus mehrere Portlets geben, die alle in der portlet.xml definiert sein müssen.

Render-Parameter

Auf die Unterscheidung von Render- und Action-Phase wurde bereits hingewiesen. Sie haben in den Beispielen gesehen, dass beide Phasen unabhängig voneinander aufgerufen werden können. Beide Phasen können basierend auf einer Benutzeraktion (z.B. Klick eines Buttons) nacheinander aufgerufen werden. Es kann jedoch auch sein, dass lediglich die Render-Phase angestoßen wird. Wird allerdings eine Aktion verarbeitet, auf die in der folgenden Render-Phase reagiert werden soll, müssen eventuell Informationen von der Action-Phase in die Render-Phase gelangen. Wichtig für das Verständnis der Portlet-Technologie ist, dass beide Phasen als absolut getrennt betrachtet werden müssen. Zwar gibt es in der Action-Phase ein ActionRequest- und ein ActionResponse-Objekt. Aber Attribute, die über Methoden wie setAttribute gesetzt werden, stehen nicht in der Render-Phase in den RenderRequest- und RenderResponse-Objekten zur Verfügung. Es muss somit ein Mechanismus gefunden werden, um Werte von der Action-Phase in die Render-Phase zu transportieren. Eine Möglichkeit wäre sicherlich (wenn auch eine sehr aufwändige), die Daten in der Action-Phase in die Datenbank zu schreiben. In der Render-Phase könnten diese Daten gelesen und angezeigt werden. Eine weitere Möglichkeit wäre ein Austausch der Daten über die Session. Darauf wird im nächsten Abschnitt eingegangen. Die einfachste Möglichkeit jedoch ist die Verwendung von so genannten Render Parametern. Über den Aufruf von actionResponse.setRenderParameter(„yourname“, „Max Müller“) wird in der Action-Phase ein Parameter für die folgende Render-Phase eingestellt. In der Render-Phase kann über request.getParameter(„yourname“) darauf zugegriffen werden. Render-Parameter sind somit ein sehr einfaches Konstrukt, um zwischen den Phasen Werte zu transportieren. Allerdings haben Render-Parameter auch Einschränkungen. Es können lediglich Strings als Render Parameter gesetzt werden bzw. String Arrays. Zudem kann nur das gleiche Portlet die Parameter lesen. Eine Übermittlung der Render-Parameter an andere Portlets ist nicht möglich (hier liefert der JSR-286 mit Public-Render-Parametern eine entsprechende Erweiterung).

Portlet-Session Daten, die während einer Benutzersitzung (Session) gehalten werden sollen, können natürlich auch in der Portlet-Welt in einer Portlet-Session gespeichert werden. Eine Portlet-Session erhält man z.B. in einer Action-Phase über renderRequest.getPortletSession(). Die Portlet-Session hat gegenüber einer Servlet-Session ein paar Besonderheiten. Zum einen hat jedes Portlet seine eigene PortletSession. Dies bedeutet, dass auch, wenn mehrere Portlets auf einer Portalseite angeordnet sind, jedes Portlet seine eigene Portlet-Session hat. Es gibt jedoch einen Sonderfall, wenn nämlich mehrere Portlets in einer Portlet-Applikation enthalten sind. Diese können über den Application-Scope der Portlet-Session Daten austauschen. So kann in einem Portlet über portletSession.setAttribute(„fullname“, fullname, PortletSession.APPLICATION_SCOPE) ein Wert in den Application-Bereich der Portlet-Session eingestellt werden und in einem anderen Portlet über portletSession.getAttribute(„fullname“, PortletSession.APPLICATION_SCOPE) darauf zugegriffen werden. Dieses Verfahren bildet häufig die Basis für IPC (Inter Portlet Communication). Es ist das einzige Verfahren, das mit dem JSR-168 möglich war. Zwar gab es in einigen Portalprodukten noch andere APIs für einen Informationsaustausch unter Portlets, diese waren jedoch proprietär und nicht standardkonform. Auch an dieser Stelle liefert der JSR-286 zusätzliche Möglichkeiten.

Fazit Portale bieten heutzutage einen mächtigen Satz an Funktionen, um anspruchsvolle Webanwendungen zu realisieren, ohne dabei grundlegende Anforderungen selbst umsetzen zu müssen. Mit den Vorteilen einer standardisierten Portlet-Technologie können zudem sehr einfach einzelne Portlets für ein Portal entwickelt werden. Die Portlet-Entwicklung lehnt sich dabei stark an die Servlet-Technologie an, sodass ein Einstieg für Webentwickler sehr einfach gelingen kann.

Geschrieben von
Andy Bosch
Andy Bosch
Andy Bosch (andy.bosch@jsf-academy.com) ist Trainer und Berater im Umfeld von JSF und Portlets. Auf seiner Onlinetrainingsakademie www.jsf-academy.com stellt er regelmäßig Trainingsvideos zu JSF, CDI und Portlets bereit. Er ist Autor mehrerer Bücher zu JSF und hält regelmäßig Vorträge auf nationalen und internationalen Konferenzen.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.