Jetspeed-2: Erste Schritte mit dem JSR 168-konformen Apache-Portal

Mach 2

Michael Lipp

Mit Jetspeed 2.0 steht seit Ende 2005 das JSR 168-konforme Portal der Apache Software Foundation (ASF) zur Verfügung. Doch wie kann Jetspeed-2 für einen Einstieg in die Portal- und Portlet-Entwicklung genutzt werden.

Ganz allgemein waren und sind Portale Einstiegsseiten ins Internet. In ihrer ursprünglichen Form gliedern sie eine Vielzahl von Informationen in Themenbereiche und stellen Suchfunktionen zur Verfügung, um so den Nutzern die Orientierung und Navigation zu erleichtern. Die unterschiedlichen Anforderungen verschiedener Nutzer führten dazu, dass viele Portale die ursprünglich statischen Seiten um Möglichkeiten der Personalisierung ergänzt haben. Besonders im Unternehmenskontext fand eine weitere Dynamisierung der Seiten dadurch statt, dass die Inhalte der dargestellten Themenbereiche sich nach Präferenzen und Berechtigungen des angemeldeten Benutzers richten.
Dabei können die dargestellten Inhalte aus anderen IT-Systemen im Unternehmen stammen. Die Single-Sign-On-(SSO-)Funktionalität eines Portals stellt sicher, dass für den Zugriff auf diese Systeme nach der Anmeldung am Portal keine weiteren Eingaben von Nutzernamen oder Kennwörtern erforderlich sind [1]. Da Inhalte aus anderen Systemen in den seltensten Fällen als HTML-Fragmente zur Verfügung stehen, müssen sie von so genannten Portalanwendungen für die Darstellung im Portal aufbereitet werden. Über die Portalanwendungen bzw. deren Anzeigekomponenten ist neben der Darstellung von Informationen dann auch eine Interaktion mit den angebundenen Systemen möglich.
Aus dieser kurzen Charakterisierung lassen sich bereits die zentralen Komponenten bzw. Dienste eines Portals ableiten. Dazu gehören ein Layout- und Struktur-Management, eine Benutzer- und Rechteverwaltung, SSO-Unterstützung und die Administration der Portalanwendungen. Das Struktur-Management definiert den grundlegenden Aufbau des Portals und die Navigationselemente. Das Layout-Management bestimmt die Zusammenstellung (Aggregation) der einzelnen Portalseiten aus den verfügbaren Inhalten. Für die Einbindung der Portalanwendungen muss das Portal eine Schnittstelle definieren, über die das Portal die darzustellenden Seitenfragmente anfordern (Rendering) bzw. an das Portal gerichtete Benutzeraktionen an die Portalanwendung weiterleiten kann.

Jetspeed-2

Jetspeed-2 [2] implementiert die beschriebene Architektur unter konsequenter Einhaltung eines komponentenorientierten Ansatzes auf Basis des Spring Framework [3]. Zentrales Element ist die Jetspeed Engine mit einer zugeordneten Pipeline, deren Komponenten (Valves) sukzessive unterschiedliche Aspekte der Anfrage bearbeiten. Am Anfang stehen die Prüfung von Zugriffsrechten und die Verarbeitung von Aktionen. Am Ende steht das Anfordern der Seitenfragmente von den Portalapplikationen. Komponenten der Pipeline dekorieren die Fragmente, d.h., versehen sie mit einem Rahmen von Steuerelementen und aggregieren sie entsprechend dem gewählten Layout (z.B. einspaltig, zweispaltig) auf der anzuzeigenden Portalseite. Dekoration und Layout werden bei Jetspeed-2 über Velocity Templates [4] oder JSPs gesteuert und sind über diese konfigurierbar. Verschiedene Arten der Dekoration können parallel definiert werden. Sie sind als Themen (Themes) beim Anlegen einer Portalseite nutzbar.
Als Persistenzdienst nutzt Jetspeed-2 die Apache ObjectRelationalBridge (OJB) [5]. OJB bietet grundsätzlich die gleichen Möglichkeiten wie das bekanntere Hibernate. Hauptgrund für die Auswahl dürfte hier der Wunsch gewesen sein, durchgängig ASF-Komponenten für die Implementierung zu nutzen.
Jetspeed-2 kann über die Website des Projekts portals.apache.org/jetspeed-2/ heruntergeladen werden. Es steht eine Derby- und eine MultiDb-Version zur Verfügung. Erstere integriert eine vorkonfigurierte Derby-Datenbank, Letztere kann eines der von OJB unterstützten Datenbanksysteme (HsqlDB, MySQL, Oracle, Postgres, DB2, Sybase, SQL Server) nutzen. Allerdings muss die jeweilige Datenbank bereits installiert sein und entsprechend den Jetspeed-2-Anforderungen konfiguriert werden. Für ein erstes Kennenlernen ist daher die Derby-Version die bessere Wahl. Mit 70 MB ist der Download nicht gerade klein. Dabei ist aber zu bedenken, dass die Datei neben dem Portal bereits eine Vielzahl von Portalapplikationen enthält.

Installation und erste Schritte

Die Installation erfolgt durch Aufruf von java -jar Jetspeed2.0-derby-install.jar. Danach muss das Installationsverzeichnis (z.B. „Jetspeed2.0“) angegeben werden. Die angebotenen optionalen Portalapplikationen sollte man zum Kennenlernen mitinstallieren. Die Verzeichnisstruktur der fertigen Installation kommt jedem, der schon einmal mit Tomcat gearbeitet hat, sehr bekannt vor – letztlich ist Jetspeed-2 ein im Tomcat-Container laufendes Servlet. Entsprechend erfolgt auch der Start über den Aufruf von startup.sh (Unix) bzw. startup.bat (Windows) im Unterverzeichnis bin des Installationsverzeichnisses. Das Portal ist dann nach kurzer Wartezeit über http://localhost:8080/jetspeed/portal erreichbar. Je nach gewünschten Rechten kann man eines der vorkonfigurierten Logins admin/admin, manager/manager oder user/user für die Anmeldung nutzen. Nach der Anmeldung als Administrator zeigt das Portal den größten Funktionsumfang (Abb. 1).

Abb. 1: Begrüßungsseite für Administrator-Login

Die Struktur des Portals ergibt sich aus der Verzeichnisstruktur, in der die Portalseiten abgelegt sind. Unterhalb des Registers wird in einer Zeile die aktuelle Position als Breadcrumb-Navigation („Krümelspur“) angezeigt. Die Spur beginnt immer mit der Wurzel des Verzeichnisbaums, der die Portalseiten enthält, und endet mit dem Kurztitel der aktuell angezeigten Seite. Die im Register verfügbaren Reiter entsprechen den auf der aktuellen Ebene verfügbaren Seiten. Im eigentlichen Anzeigebereich befindet sich links ein Navigationsmenü. In dessen Gruppe Folders stehen die auf der aktuellen Ebene verfügbaren Unterverzeichnisse.

Abb. 2: Administration der Portalstruktur

Über Jetspeed Administrative Portlets | Portal Site Manager gelangt man zu einer Baumdarstellung der Verzeichnisstruktur (Abb. 2). Nach Auswahl eines Verzeichnisses kann der Administrator mit [Add Page] eine erste eigene Testseite anlegen. Nach Auswahl der Seite über Root Folder | Testseite ist diese zunächst leer. Wählt man den Editiermodus (stilisierter Stift am rechten Ende der Breadcrumb-Navigation-Zeile), kann die Seite weiter eingerichtet werden (Abb. 3). Über das „+“-Symbol (wiederum am Ende der Breadcrumb-Navigation-Zeile) können die auf der Seite darzustellenden Portlets ausgewählt und anschließend auf der Seite angeordnet werden.

Abb. 3: Erste eigene Seite im Editiermodus
Die im GUI verfügbaren Funktionen für die Administration der Portalstruktur und -seiten wirken auf Konfigurationsdateien im Dateibaum. Die Wurzel des Dateibaums liegt in /webapps/jetspeed/WEB-INF/pages/. Die auf einer Ebene verfügbaren Seiten sind in PSML-Dateien beschrieben (Portal Structure Markup Language). Listing 1 zeigt die Beschreibung der neu angelegten Testseite. Nicht alle Konstrukte von PSML sind über das GUI editierbar. Das Listing zeigt, wie der Titel (angezeigt im Rahmen des Browser-Fensters) und der Kurztitel der Seite (Beschriftung des Reiters) über Metadata Tags internationalisiert werden können.
Am Ende der Seitenbeschreibung können Angaben zu Zugriffsberechtigungen ergänzt werden. Die Angaben im Beispiel-Listing bewirken, dass auch normale Benutzer berechtigt sind, das Seiten-Layout zu editieren. Werden in der Seitenbeschreibung keine Angaben gemacht, so gelten die Angaben in der Datei page.security in der Wurzel des Dateibaums bzw. eingebaute Standardwerte.

Informationen zum Verzeichnis

Die automatische Erstellung des Registers und Navigationsmenüs kann durch eine Datei folder.metadata im Verzeichnis ergänzt werden. Diese Datei beschreibt (ebenfalls in PSML) den Titel des Verzeichnisses im Folder-Bereich des Menüs, die zusätzlichen Menüeinträge und die Zugriffsberechtigungen für das Verzeichnis.

Listing 1 – Testseite.psml

Ein architektonischer Vorteil bei der Nutzung eines Portals liegt darin, dass es das Konzept komponentenorientierter Softwareentwicklung bis an die Benutzeroberfläche bringt. Traditionell endet die klare Aufteilung einer Applikation in Komponenten in der Applikationsschicht. In dieser Schicht können Bausteine noch völlig unabhängig voneinander entwickelt und dann integriert werden. Ist für eine Komponente eine Benutzerschnittstelle verfügbar, kann diese meistens nur für Testzwecke verwendet werden. Zu sehr weicht eine unabhängig realisierte Oberfläche von den Vorgaben für die Gesamtapplikation und von eventuell vorhandenen Oberflächen anderer Komponenten ab. Bestenfalls ist die Oberfläche auf Basis der für die Applikation gewählten Techniken realisiert und kann durch entsprechende Änderungen des Quellcodes angepasst und in die Implementierung der Präsentationsschicht integriert werden.
Verwendet man aber für die Präsentationsschicht einer Applikation ein Portal, ist die Integration von Benutzeroberflächen einzelner Komponenten in die Gesamtapplikation leicht möglich, sofern sie als Portalapplikationen realisiert sind. Voraussetzung ist, dass ein API für die Einbindung der Portalapplikationen in das Portal definiert ist (und eingehalten wird). Für die Java/Java EE-Umgebung spezifiziert der JSR 168 ein solches API sowie ein Dateiformat, in dem die Portalapplikationen bereitzustellen sind. Analog zum Begriff Servlets definiert der JSR 168 eine einzelne Oberflächenkomponente, die auf einer Portalseite dargestellt wird, als Portlet. Eine Portalapplikation besteht aus einem oder mehreren Portlets, die zusammen die gewünschte Funktionalität zur Verfügung stellen. Die Laufzeitumgebung eines Portlets ist der Portlet-Container, der den Lebenszyklus des Portlets verwaltet und Dienste wie persistenten Speicher für (benutzerspezifische) Portlet-Präferenzen zur Verfügung stellt.
Die Unterstützung des JSR 168 ist für Entwickler von Portalapplikationen die wichtigste Neuerung in Jetspeed-2. Jetspeed-2 integriert dazu den Pluto-Portlet-Container der Apache Software Foundation. Pluto ist die Referenzimplementierung des JSR 168 und trägt erheblich dazu bei, dass Jetspeed-2 alle Tests des Technology Compatibility Kit erfolgreich absolviert.

Ein minimales Portlet

Das von einem Portlet zu implementierende Interface enthält lediglich vier Methoden:

  • init(PortletConfig config) ruft der Portlet-Container einmal nach dem Erzeugen des Portlets auf.
  • processAction(ActionRequest request, ActionResponse response) wird vom Portal-Container aufgerufen, wenn der Benutzer eine Aktion im Darstellungsbereich des Portlets anwählt.
  • render(RenderRequest request, RenderResponse response) muss den HTML-Code ausgeben, der den Beitrag des Portlets in seinem aktuellen Zustand zur angezeigten Portalseite bildet. Dabei sollte das Portlet den im Request übergebenen Portlet-Modus (View, Edit oder Help) und den Darstellungs-Modus (normal, maximized oder minimized) berücksichtigen.
  • destroy() ruft der Portal-Container einmalig auf, wenn er das Portlet nicht mehr verwendet.

Für die Implementierung von Portlets steht eine abstrakte Basisklasse, das GenericPortlet zur Verfügung. Die Klasse verteilt die Render-Aufrufe auf die drei Methoden doView, doEdit und doHelp. Listing 2 zeigt die Minimalimplementierung eines Portlets. Wie in einem Servlet steht für die Ausgabe des HTML-Fragments ein PrintWriter zur Verfügung. Damit sichergestellt ist, dass der Portal-Container das generierte HTML als Fragment in die erzeugte Seite einbetten kann, dürfen die HTML-Tags base, body, frame, frameset, head, html und title in der Ausgabe nicht verwendet werden.
Damit sich die Darstellung des Fragments harmonisch in die Portalseite einfügt, sollte, wie im Beispiel gezeigt, der HTML-Code nur die im JSR 168 vordefinierten CSS-Klassen verwenden und mit Style-Angaben ergänzen. Nur dann funktioniert die stilistische Anpassung auch der Portlet-Inhalte an das für die Dekoration des Portlets und der Seite gewählte Thema.

Listing 2 – HelloWorld.java

package de.mnl.portlets;

import javax.portlet.GenericPortlet;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.PortletException;
import java.io.PrintWriter;
import java.io.IOException;

/**
* Das Hello World Portlet.
*/
public class HelloWorld extends GenericPortlet {

public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("
Hello World
"); } }

Wie im Java EE-Kontext üblich, gehört zur Java-Klasse ein Deployment Descriptor. Da eine Portlet-Applikation eine Spezialisierung einer Webapplikation ist, benötigen wir zunächst das in Listing 3 gezeigte web.xml. Für unsere Portalapplikation genügt hier die Angabe des display-name.

Listing 3 – web.xml

Portlet Beispiel


Listing
4 – portlet.xml

Hello WorldhelloworldHello World Portletde.mnl.portlets.HelloWorldtext/htmlviewenHello WorldHelloHello World

Wären Portlets vollständig in die Java EE-Umgebung integriert, könnten wir unser Portlet wahrscheinlich wie ein Servlet, einen Filter oder eine JSP im web.xml spezifizieren. Da Portlets aber ein optionaler Zusatz zu Java EE sind, erfolgt ihre Beschreibung in einer eigenen Datei (Listing 4). Portlets haben die üblichen Eigenschaften description, portlet-name und display-name und natürlich eine Implementierungsklasse. Der Portal-Container bekommt darüber hinaus Informationen über die vom Portlet unterstützen Ausgabeformate (hier Text/HTML, denkbar wäre z.B. die zusätzliche Unterstützung von WAP/WML oder VoiceXML) und über die unterstützten Sprachen. Angaben zum Titel vervollständigen die Beschreibung.
Für die Übersetzung von HelloWorld.java müssen wir das Portlet-API in den Classpath mit aufnehmen (Jetspeed2.0/shared/lib/portlet-api-1.0.jar). Danach werden die Klasse und die Deployment-Deskriptoren in ein WAR gepackt (/WEB-INF/classes/de/mnl/portlets/HelloWorld.class, /WEB-INF/web.xml, /WEB-INF/portlet.xml) und die Portalanwendung ist fertig. Um die Anwendung im Portal verfügbar zu machen, genügt es, die WAR-Datei in das Verzeichnis Jetspeed2.0/webapps/jetspeed/WEB-INF/deploy/ zu kopieren. Danach steht das Portlet beim Konfigurieren von Portalseiten zur Verfügung und kann z.B. in unsere Testseite eingefügt werden.

Abb. 4: Das HelloWorld-Portlet

Action URLs von Formularen bzw. Verweisziele, die das Portlet selbst referenzieren, können nicht direkt, auch nicht als relative URLs, ausgegeben werden. Jeder an das Portal gerichtete URL muss Informationen über das Portlet enthalten, auf die sie sich bezieht. Portlets müssen URLs daher vom Portal anfordern und um zusätzliche Parameter ergänzen.

...
PortletURL url = response.createRenderURL();
url.setParameter("zusatztext"," and Univers");
out.println("Zusatztext anzeigen");
...

Das Portal übergibt dem Portlet die Request-Parameter eines Render URL bei nachfolgenden Render-Aufrufen. Damit kann das Portlet den Zusatztext wie folgt ausgeben:

...
String zusatz = request.getParameter("zusatztext");
if (zusatz == null) { zusatz = ""; }
out.println("
" + "Hello World" + zusatz + "
"); ...

Render URLs führen nicht zum Aufruf der processAction-Methode eines Portlets und die mit ihnen verbundenen Parameter können dem Render-Aufruf vom Portal mehrmals übergeben werden. Sie sind daher nur für idempotente Aktionen geeignet. Im Normalfall generieren Portlets Action URLs (response.createActionURL()), die einen einmaligen Aufruf von processAction mit den gesetzten Parametern auslösen. Soll ein Action URL zu einer veränderten Darstellung führen, muss das Portlet in
processAction
-Daten z.B. in einer Datenbank verändern und diese Daten in der Render-Methode berücksichtigen.

Portlets und Bridges

Natürlich ist die Ausgabe von HTML-Code über println ziemlich umständlich. Normalerweise wird ein Portlet daher die Aufgabe der HTML-Erzeugung delegieren, z.B. an eine JSP (allgemein an ein beliebiges Servlet). Die Implementierung von doView besteht dann nur noch aus einem Aufruf:

getPortletContext().getRequestDispatcher("/hello.jsp").include (request, response);

Zur Verwendung innerhalb der JSP werden aus dem RenderRequest und der RenderResponse spezielle Implementierungen von HttpServletRequest und HttpServletResponse abgeleitet. Damit können JSPs weitgehend wie gewohnt implementiert werden. Einige Methoden stehen zwar nicht zur Verfügung, allerdings ist die Verwendung dieser Methoden für ein Portlet auch wenig sinnvoll (z.B. getRealPath(), getInputStream()). Portlet-spezifische, zusätzliche Informationen sind über Request-Attribute javax.portlet… verfügbar. Zur einfachen Verwendung dieser Informationen definiert der JSR 168 eine Portlet Tag Library, die der Portal-Container zur Verfügung stellen muss.
Adapter zu anderen HTML-Generierungstechniken sind als Portlet Bridges verfügbar. Sie werden typischerweise als Implementierungsklassen des Portlet Interface realisiert und über Initialisierungsparameter in portlet.xml konfiguriert. Das Portlet-Bridges-Projekt der ASF [6] stellt Übergänge u.a. zu JavaServer Faces, Struts, PHP und Perl bereit.

Fazit

Jetspeed-2 ist eine vollständige, JSR 168-konforme Portalimplementierung. Die vielfältigen Konfigurationsmöglichkeiten konnten im Rahmen dieses Artikels bestenfalls angedeutet werden. Die Implementierung von Darstellungskomponenten als Portlets stellt keine besondere Herausforderung dar. Schon das einfache Portlet Interface bietet mit der Trennung der Methoden zur Ausführung einer Aktion und der Generierung der Darstellung eine komfortablere Implementierungsbasis als das klassische Servlet Interface. Übergänge zu etablierten Frameworks vereinfachen die Realisierung von Portlets weiter.
Portal-Services wie SSO und Portlet-Präferenzen bieten fertige Lösungen für Aufgaben, denen man bei der Implementierung von konfigurierbaren Oberflächen immer wieder begegnet. JSR 168-konforme Portale wie Jetspeed-2 sind damit eine gute Basis für eine effiziente Implementierung der Präsentationsschicht einer Anwendung. Die Entscheidung für die Nutzung eines Portals und die Auswahl einer bestimmten Implementierung muss dabei selbstverständlich – wie bei allen Komponenten – vor dem Hintergrund der spezifischen Anforderungen des zu realisierenden Projekts getroffen werden.


Dr. Michael Lipp
(mnl@mnl.de) ist Lösungsarchitekt bei einem Systemintegrator. Sein Aufgabenschwerpunkt liegt in der Konzeption und Umsetzung von Lösungsangeboten im Bereich Workflow/BPM auf Basis der Java EE-Archiktektur.

[1] Anja Kirchhof, Thorsten Gurzki, Henning Hinderer, Joannis Vlachakis: Was ist ein Portal?, Frauenhofer Institut Arbeitswissenschaft und Organisation, Whitepaper, 2004

[2] portals.apache.org/jetspeed-2

[3] www.springframework.org

[4] jakarta.apache.org/velocity/

[5] db.apache.org/ojb/

[6] portals.apache.org/bridges/

Geschrieben von
Michael Lipp
Kommentare

Schreibe einen Kommentar

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