Anleitung neuer Service mit PortalPack 3.0.5 Beta, Liferay 6.1 und NetBeans 7.0.1

Hier eine kurze Anleitung, wie man mit PortalPack 3.0.5 Beta, Liferay 6.1 und NetBeans 7.0.1 einen Service baut.

Offen ist noch die DB-Einbindung. Irgendwas stimmt da noch nicht :-/

Unter Tools-Server 'Liferay Portal Server' definieren. Dabei ist Auto Deploy Dir: ...\liferay-portal-6.1.0\deploy und 'Directory Deployment Enabled' gesetzt.

Neues Projekt: - Java Web -> Web Application - NEXT - Project Name. Events - NEXT - Server: Liferay Portal Server - NEXT - Portlet Support aktivieren - Portlet generieren lassen

- FINISH

Jetzt wird das service.xml File angelegt:

Auf dem Events-Projekt rechts klicken und New ... wählen. Den File Type Liferay Plugins -> Service Builder XML wählen. Der Filename ist 'eventsservice' und der Folder ist 'web'.

- FINISH

Jetzt wird der Editor für den eneuen Service automatisch geöffnet:

Der Package Path und der Namespace sind falsch. Also wechseln wir in die XML-Ansicht und passen beides an.

Nun ersetelle ich einen neuen Service für die Events. Dazu klicke ich auf Add (links neben dem Package Path) und erfasse den Enitity Namen 'Event' und die Tabelle 'eventtable' (die Namen haben keine implizite Abhängigkeit untereinander.

Nach dem Add steht die neue Entity 'Event' in der Tabelle links oben. Nun können Columns für ein Event erfasst werden:

Als nächstes könnte ein Finder für Zugriffe über eine oder mehrere der Eventspalten definiert werden. Das mach ich ein anderes Mal.

Als letzter Schritt wird der Service generiert: Klick auf Generate Services (oben links im Services-Editor). Dadurch werden viele Java-Klassen (Service, Datenklassen,...), XMLs und ein ...\Events\service\lib\Events-service.jar erstellt. Die Klassen in ch.osys.events.service.*  sollten nicht von Hand geändert werden, da sie durchs Generieren wieder überschrieben werden.

Die Files in ch.osys.events werden nicht überschrieben durch Generate Services.

Das generierte JAR wird normalerweise ins Portlet WAR integriert. Wenn man will, dass andere Projeket auch diesem Service nutzen können, kann man dies in den Preferences (oben rechts im Editor) setzen.

Jetzt fehlt nur noch das GUI.

Keep it simple:

 <%@page contentType="text/html"%>
 <%@page pageEncoding="UTF-8"%>

 <%-- Uncomment below lines to add portlet taglibs to jsp
 <%@ page import="javax.portlet.*"%>
 <%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%> 

 <portlet:defineObjects />
 <%PortletPreferences prefs = renderRequest.getPreferences();%>
 --%>

 <%@ page import="javax.portlet.*"%>
 <%@ page import="ch.osys.events.service.service.*"%>
 <%@ page import="ch.osys.events.service.model.*"%>
 <%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>

 <portlet:defineObjects />
 <%PortletPreferences prefs = renderRequest.getPreferences();%>

 <table>
  <form method="POST" action="<portlet:actionURL/>">
   <tr>
    <td>Event ID:</td>
    <td><Input type="text" name="id"/></td>
   </tr>
   <tr>
    <td>Datum:</td>
    <td><Input type="text" name="datum"/></td>
   </tr>
   <tr>
    <td>Titel:</td>
    <td><Input type="text" name="titel"/></td>
   </tr>
   <tr>
    <td><Input type="submit"/></td>
   </tr>
  </form>
 </table>
 <H3> Anzahl Events :
  <%
   out.println(EventLocalServiceUtil.getEventsCount());
  %>
 </H3>

Jetzt fehlt noch die Funktionalität hinter dem Submit-Knopf. Dazu füge ich folgendes in ...\Events\src\java\ch\osys\events\Events.java:

public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
 try {
  long id = Long.parseLong(request.getParameter("id"));
  String titel = request.getParameter("titel");
  Event event = EventLocalServiceUtil.createEvent(id);
  event.setId(id);
  event.setTitel(titel);
  event.setDatum(new Date());
  EventLocalServiceUtil.addEvent(event);
  System.out.println("Added");
 } catch (Exception ex) {
  ex.printStackTrace();
 }
}

Fertig!

Nun hab ich noch das Problem mit der DB-Einbindung. Gemäss Fehlermeldung, ist der User nicht berechtigt die Tabelle anzulegen. Ich muss der Sache nachgehen, wenn ich wieder wacher bin (oder 'Zeit habe', was halt zuerst eintritt).

Neues in Liferay 6.1

Neue Funktionen von Liferay 6.1

Die folgende Zusammenstellung von neuen Funktionen von Liferay 6.1, ist nicht abschliessend. Ich hab alles was ich finden konnte, zusammengestellt und werde es in Zukunft noch ergänzen.

Internationalisierung

Titel und Beschreibung von Web Content können mehrsprachig sein (endlich!). Ausserdem gibt's ein paar kleine Verbesserungen bei der Usability. Vokabular und Beschreibungen können ebenfalls mehrsprachig sein.

Verbesserung bei SEO

Durch veränderte Strukturen und verbessertes Handling von Schlüsselworten (Mehrsprachigkeit), soll der Google-Support verbessert werden.
Verbesserungen beim Site Management
Editieren von Site und Page Settings als Popup, statt im Kontrollbereich. Damit bleibt der optische Kontext erhalten. Alle Arten von Sites sind nun einfacher zu erstellen und einer Organisation oder Community zuzuordnen

Verbesserungen beim Publishing

Das Staging soll verbessert worden sein. Da müssen noch eigene Tests folgen, denn bisher war Staging eher ungenügend. Ausserdem sollen verschiedene Varianten der Pages gleichzeitig von verschiedenen Teams gebaut werden können. Weitere Funktionen in diesem Zusammenhang: automatisches Versioning, Preview in die Zukunft, Seiten bin über 100'000 Seiten sollen damit verwaltbar sein. Da bin ich ja echt gespannt...

Ausserdem wird das Publizieren von Content einfacher. Es muss nicht mehr ein Asset Publisher erstellt und konfiguriert werden, sondern man kann content-spezifische Viewer direkt einfügen.

Verbesserungen beim Content

Neu lassen sich verschiedene Content-Typen verknüpfen: z.B. Dokumente mit Events oder Events mit Web Content, ...
Verbesserungen bei der Portlet Verwaltung
Portlet Configs können als eigene Applikationen gespeichert und beim Einfügen von Web Content direkt eingebunden werden.

Dokument Library

Dokument Library bekommt einen neuen Look. Sie sieht aufgeräumt und sauber aus.
Es ist neu möglich verschiedene Repositories (Liferay, SharePoint, CMIS, Documentum, Alfresco) gleichzeitig innerhalb eines gemeinsamen GUI geöffnet zu haben. Diese Repositories können bestehend sein (=müssen also nicht speziell für Liferay angelegt werden).
Über die Defintion von eigenen Dokumenttypen, finden Benutzer einfacher ihre Sachen wieder. Es wird möglich sein, hoch geladene Files mit diversen automatischen und manuellen Meta-Informationen zu versehen.
Die Image Gallery wird in die Document Library integriert.

Taxonomie

Das GUI für die Taxonomie wurde verbessert (=schneller und einfacher). Vokabulare können Asset-spezifisch sein und nicht mehr nur global.
Nun sind auch komplexere Kategorisierungen möglich.

Eigene Applikationen

Es soll Möglichkeiten geben, dass Benutzer sich eigene, einfache Applikationen zusammen klicken können. In diesem Zusammenhang soll es Benutzern möglich sein Wizards zu ertsellen. Ob beides dann wirklich funktioniert und realen Anforderungen gerecht wird, möchte ich erstmal sehen. (<- das tönt zu stark nach Marketing und zu wenig nach Realität ;-)

Mobile

Verbesserter Support für Android und iOS-Geräte, inkl. konfigurierbarer Device Erkennung.

OpenSocial 1.1

OpenSocial 1.1 wird integriert. Dazu gehört Kontakt Mangement, ein Twitter-ähnlicher Dienst, ... . Ausserdem wurden verschiedene bestehende Teile überarbeitet: Blogs, Wiki, Kalender, Message Board, Chat, ... .

Development

Auch für Entwickler hat sich einiges getan:
- LifeRay wird SSO Server (SAML2.0, OAuth)
- RESTful Web Services in Ergänzung zu den bestehenden Technologien (basierend auf Atom Publishing Protocol)
- neue Version der Liferay IDE
- verbesserte Dokumentation: javaDoc, Referenz, Entwickler Handbuch (das ist auch überfällig)
- Visual UI builder auf Basis von Alloy UI
- Workflow Designer für Kaleo
- ...
Version 6.1 von Liveray soll im August 2011 kommen. Ob das eine Beta oder ein Release Candidate ist, weiss ich noch nicht.

Mockito: Lessons Learned

Ich möchte hier einige der Dinge sammeln, die mir bei der Arbeit mit Mockito immer wieder passieren oder Details, die ich mir merken möchte. Vielleicht hilft's ja auch Anderen ...

Typen-Definition bei der Deklaration von Methoden-Aufrufen

Beispielsweise bei verify() und when() muss angegeben werden, welche Parametertypen übergeben werden. Dies braucht Mockito, um die Methoden-Signatur zu erkennen. Ausserdem kann man statt einem Typ auch direkt einen Wert mitgeben. Dies ist zum Beispiel sinnvoll, wenn man einen Wert beim Aufruf der zu testenden Methode mitgibt, der unverändert an die gemockte, tieferliegende Schicht übergeben werden soll.

Beispiel 1:

Mockito.verify(fsDaoMock).setStatus(1L, 1L, Status.ACTIVE, CallerToken.USER);

Hier verwende ich konkrete Werte, um zu prüfen, ob genau dieser Aufruf gemacht wurde.

Beispiel 2:

Mockito.verify(fsDaoMock).setStatus(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(Status.class), Mockito.any(CallerToken.class));

Hier verwende ich nur Typen und definiere jeweils keine Werte.

Wichtig: Wenn ich diese beiden Ansätze mischen will (also zum Teil konkrete Werte und beim Rest 'nur' Typen definieren), muss ich das so machen:

Mockito.verify(fsDaoMock).setStatus(Mockito.anyLong(), Mockito.anyLong(), Mockito.eq(Status.ACTIVE), Mockito.eq(CallerToken.USER));

Alles andere führt zu Laufzeit-Fehlern.

Mocking eines privaten Attributes unter Spring

Ich möchte eine Klasse testen, die über Dependency Injection (@AutoWired) ein DAO bekommt. Natürlich sollen die DAO-Methoden nicht aufgerufen werden.

Die Deklaration des DAO ist folgendermassen:

@Autowired private FileStoreDao fsDao;

Es wäre aus Architekturüberlegungen inakzeptabel direkten Zugriff auf fsDao zu gewähren (z.B. getter oder Aufweichen des Zugriffsmodifiers). Spring hat eine Util-Klasse, die in diesem Fall weiterhilft:

FileStoreServiceImpl fileStoreServiceImpl = new FileStoreServiceImpl(); FileStoreDao fileStoreDaoMock = Mockito.mock(FileStoreDao.class); ReflectionTestUtils.setField(fileStoreServiceImpl, "fsDao", fileStoreDaoMock);

Testing-Support in Maven 3

Grundsätzlich unterscheidet man ja zwischen Unit-Tests und Integrations-Tests. Unit-Test testen das Verhalten einzelner Klassen, während Integrations-Tests das Zusammenspiel mehrerer Klassen testen. Üblicherweise (bzw. richtigerweise) sind Unit-Tests schnell und werden bei jedem Build durchgeführt und Integrations-Tests laufen länger und werden nur zu "speziellen" Gelegenheiten (also beispielsweise in nightly builds) durchlaufen. In Maven gibt es Support für diesen Unterschied unter Verwendung des failsafe-Plugins:

<dependency>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.8.1</version>
    <scope>test</scope>
</dependency>

Zur Unterscheidung zwischen den beiden Test-Arten wird der Klassenname herangezogen: UnitTest-Klassen enden in *Test und Integrationstests in *IT. Bei einem Clean and Build in NetBeans (entspricht  mvn install) werden alle UnitTests durchgeführt. Durch mvn failsafe:integration-tests (bzw. einen entsprechenden Menupunkt, der sich in NetBeans einfach erzeugen lässt) werden die Integrationstests durchgeführt.

Passworte

Im Bereich von Passworten gibt es viele Missverständnisse. Heutzutage ist wohl den meisten Leuten bewusst, dass der Name des Partners oder des Haustieres eine sehr schlechte Wahl für ein sicheres Passwort ist. Die übliche Antwort - speziell von uns Techies - sind Passworte wie ?bJn92$!. Solche Passworte sind zwar relativ sicher, aber niemand kann sie sich merken. Das nützt dann auch relativ wenig. Was kann hier getan werden?

Ich möchte systematisch an diese Fragestellung heran gehen und das Feld von hinten aufrollen. Wieso braucht es sichere Passworte? Damit niemand auf unsere privaten Daten wie Mails, Kundenkonten u.ä. zugreifen kann. Bei diesen Daten gibt es grosse Unterschiede: einzelne Bereiche sind besonders schützenswert (Bank, Mail, ...), dafür werden besonders sichere Passworte gebraucht. In anderen Bereichen, wo die Daten weniger missbrauchsgefährdet sind und weniger Schaden entstehen kann, müssen Passworte auch nicht ganz so sicher sein.

Die Sicherheit eines Passworts ergibt sich aus der Zeitdauer, die benötigt wird, es zu knacken. Wie werden Passworte geknackt? Da gibt es hauptsätzlich drei Varianten:

1. Fragen: der einfachste und erschreckenderweise auch sehr häufig erfolgreiche Ansatz ist, einfach die Person nach ihrem Passwort zu fragen. Sehr häufig rücken Personen - ohne sich viel dabei zu überlegen - auf eine direkte Frage mit ihrem Passwort heraus. Drum: NIEMALS sein Passwort jemand anderem mitteilen oder aufschreiben. Auch Passworte per Mail verschicken ist KEINE gute Idee.

2. Lexikon-basierte Suche: wenn die erste Variante nicht möglich ist oder nicht funktioniert hat, nimmt der Angreifer eine Wörterliste zur Hilfe und probiert ob eines der Worte als Passwort verwendet wurde. Drum: niemals nur ein Wort, welches direkt in einem Wörterbuch steht, als Passwort verwenden. In diesem Zusammenhang sind die jährlich veröffentlichten Listen mit den am meisten verwendeten Passworten interessant. Sein eigenes Passwort sollte nicht auf einer dieser Listen stehen, denn diese fliessen natürlich auch in diese Suche ein.

3. Brute Force (=rohe Gewalt): als ultimo ratio testet der Angreifer einfach alle möglichen Buchstaben-Kombinationen durch, bis er den Account geknackt hat. Damit ist zwar grundsätzlich jedes Passwort knackbar, aber das dauert ab einer gewissen Wortlänge viel zu lange. Das macht Passworte, wie ?bJn92$! nicht sicherer als andere Zeichenketten mit acht Zeichen. Grundsätzlich gilt: je länger das Passwort, umso viel länger dauert die Dauer, bis es geknackt ist.

Für die Variante zwei und drei schreibt der Angreifer ein kleines Computerprogramm, welches ihm stundenlanges Tippen abnimmt.

Zuerst ein Blick auf die Variante zwei: Mit einer kurzen Kombination von Worten lässt sich eine sehr hohe Sicherheit erreichen, wenn der Angreifer den Brute Force-Weg wählt. Aber auch bei lexikon-basierter Suche sind die kombinatorischen Varianten riesig:

Bei einer Lexikongrösse von 120'000 Einträgen gibt es bei einem Passwort bestehend aus zwei Worten bereits 14'400'000'000 Kombinationen. Bei einem Passwort bestehend aus drei Worten gibt es bereits 1'728'000'000'000'000 Milliarde Kombinationen.

Bei der Annahme, dass 1000 Anfragen pro Sekunde gemacht werden können (was die wenigsten Webdienste mitmachen, ohne die Verbindung zu kappen) würde es gut 166 Tage dauern, um ein Passwort bestehend aus 2 Worten mit lexikon-basierter Suche zu knacken. Bei drei Worten sind es schon knapp 55'000 Jahre.

Hier ein paar Beispiele zur Variante drei für die Sicherheit von Passworten beim Einsatz des Brute-Force Ansatzes (berechnet mit http://howsecureismypassword.net/):

PasswortBrute Force
Sonne1 Sekunde
Strasse1 Stunde
Passwort2 Tage
?bJn92$!46 Tage
meine Bankca 18 Jahre
tolles Passwort      6 Milliarden Jahre

Was lernen wir daraus? Ein Passwort muss nicht unbedingt möglichst viele Sonderzeichen enthalten und dadurch quasi unbrauchbar werden. Es lassen sich also auch ohne Hieroglyphen Passworte bilden, die nur mit massivem Einsatz von Computern und Zeit geknackt werden können.

Noch besser ist es Worte aus dem Wörterbuch mit Slang- oder Dialektausdrücken zu kombinieren. Dann kann man es sich zwar gut merken, aber die lexikon-basierte Suche wird erfolglos bleiben. Beispiele

PasswortBrute Force
nur en Tescht2 Millionen Jahre
s’bescht Passwort      18 Billionen Jahre

Noch ein wichtiger Punkt: da viele Leute dasselbe Passwort für viele ihrer Accounts verwenden, können mit einem geknackten Passwort diverse Accounts kompromittiert sein.

Es ist mir klar, dass die oben angegebenen Zeitdauern für's Knacken der jeweiligen Passworte abhängig von Art und Menge der verwendeten Rechner sind. Aber ob es 18 Billionen Jahre oder nur 18'000 Jahre dauert mein Passwort zu knacken ist mir ziemlich egal ;-)

Testen mit TestNG und Mockito

Die Frage beim Schreiben von Testklassen ist ja, wie sicher gestellt wird, dass eine Applikation umfassend mit Tests abgedeckt ist und mit welchen Mitteln dies getan und überprüft wird. Für TestNG gibt es viele Tutorials und auch konzeptionell birgt es wenig Überraschungen. Mockito andererseits ist mässig dokumentiert und bringt einen komplett anderen Ansatz mit. Deswegen möchte ich hier meine Erkenntnisse zu Mockito zusammenstellen:

Integration von Mockito in Testklassen

Ich bin eigentlich kategorisch gegen statische Imports, da sie den Code unleserlich machen und mit dem Support heutiger IDEs unnötig sind. Bei Testklassen bin ich allerdings zum Schluss gekommen, dass static Imports der Klassen aus dem Testframework zu kompakterem Code führen können und durch die Isolation der Testklassen klar ist, woher die entsprechenden Methoden kommen.

Wann schreibe ich welche Art von Tests?

Bei Klassen, die auf anderen selbstgeschriebenen Klassen basieren, verwende ich primär Mockito um das Verhalten einer Klasse innerhalb ihrem Kontext zu beschreiben und zu testen. Dabei ist es wichtig nur die direkt referenzierten Klassen zu mocken. Für Tests der Importparameter ist TestNG gut geeignet.

Kurz: das Verhalten eines Subsystems oder Methoden mit komplexen Abläufen (if, switch, ...) werden mit Mockito getestet; für alle anderen Tests gibt es TestNG.

Verwendung von Mockito

Mit Mockito lassen sich Klassen und Interfaces mocken (Ausnahme sind statische Klassen und final-deklarierte Klassen). Da es, wie bereits gesagt, kein gute Dokumentation zu Mockito gibt (wer etwas kennt, soll es mir doch bitte zeigen), stelle ich in verschiedenen Artikeln meine Erfahrungen und Erkenntnisse zusammen.

JavaDoc zur Version 1.8.5 ist hier.

Ich fange mit der Klasse Mockito, bzw der Annotation @Mock an:

Beide Varianten dienen dazu eine bestehende Klasse oder ein Interface zu mocken, d.h. mit einer temporären Implementierung zu versehen, die nur während der Gültigkeit des Objekts in Tests ansprechbar ist und deren Methoden nichts tun. In Beispielen sieht man häufig, dass bestehende Java-Klassen gemockt werden. Das ist natürlich nicht praxisnah; normalerweise mockt man eigene Klassen.

Bevor ich auf die >20 statischen Methoden dieser zentralen Klasse in einem separatem Artikel eingehe, möchte ich kurz verwandte Klassen positionieren.

Die Klasse BDDMockito ist eine Variation von Mockito. Diese unterstützt Behaviour getriebene Entwicklung; damit ist gemeint, dass die Klasse den Use-Case des Kunden präzis und nahe seiner Sprache abbildet. Beim Durchführen der Tests wird geprüft, ob das gewünschte Verhalten abgebildet wird.

Die Annotation @Captor scheint für einen bestimmten Testcase ausgelegt zu sein, den ich aber noch nicht verstanden habe.

Eine weitere Annotation in diesem Zusammenhang ist @Spy. Dies lässt sich auch mit Mockito.spy(...) abbilden. Diese Funktionalität ermöglicht es ledigliche Teile von Klassen zu mocken, während andere 'normal' laufen. Bei Klassen, die nur statische Methoden enthalten, kann das funktionieren. Sinn macht es wohl nur in sehr sepezielle Fällen. Besser ist's wohl @Spy zu vergessen.