Java/Liferay: iCal-Datei erzeugen und ausliefern [UPDATE]

Wer mit Liferay (genauer: Mit einem Portlet) eine iCal-Datei ausliefern will, benötigt zuerst mal iCal4j. Ich brauchte die JARs backport-util-concurrent-3.1 und ical4j-1.0.3, aber vermutlich benötigt man auch noch commons-lang-2.6 und commons-logging-1.1.1, davon habe ich (ältere) bereits durch/für Liferay im Projekt. Die anderen brauchte ich nicht.

Anmerkung: Außerdem habe ich eine leere Datei namens ical4j.properties direkt in src angelegt, um eine Warnung zu unterdrücken.

Um eine Ressource abzurufen, nutze ich die ResourceURL von Liferay, in meinem Fall plus einer Event-ID:

Ein Aufruf der URL landet in der serveResource() meines Portlets, und mündet in der Erzeugung des Files:

ACHTUNG: Wer einen Termin mit Startzeit (und Endzeit) erzeugen will, muss dem VEvent ein (zwei) Objekte vom Typ DateTime statt Date übergeben!

Quellen: Basis, verschiedene iCal4j-Fehlermeldungen, Filename setzen, ICS Mime type, Unterschied Date/DateTime 😉

Wer rausfindet, warum mir beim Validieren ein “Parameter [VALUE] must only be specified once” geworfen wird, bekommt ein Bier! EDIT: Es lag an der jetzt auskommentierten Zeile! Prost!

Liferay: Portlet Lokalisierung [UPDATE]

Laut Liferay-Wiki legt man im Classpath (dort ist es explizit ein Package …/com/my/portlets/p1/…) eine Datei “Language.properties”, plus für jede “foreign language” (=Locale) ein “Language_*.properties” (mit *=locale). Das kann ich so nicht bestätigen: Meine Dateien müssen direkt in classes liegen, also ohne Package. Andernfalls bekomme ich ein

java.util.MissingResourceException: Can’t find bundle for base name Language, locale de_DE

Auf Dateien direkt in classes konnte ich per

zugreifen. Groß-/Kleinschreibung oder der ClassLoader waren bei mir nicht das Problem. Vermutlich muss ich beim Laden das Package mit angeben… allerdings sagt das Wiki das so nicht, und ich bin gerade zu faul 🙂

Achtung: Prinzipiell gibt es eine Fallback-Datei, d.h. wenn ich eine Language.properties und eine Language_de.properties habe, ist Language.properties der Fallback. Aber: Der Fallback wird auf Basis des Locale-Defaults ausgewählt! Sprich: Für Language.properties und Language_de.properties ist auf deutschen Rechnern Language_de.properties der Fallback! Das zu vermeiden, bzw. das auf allen Rechnern einheitlich zu haben, schafft man mit einem

Interessanterweise muss ich die Language.properties auch nicht in der portlet.xml angeben!? Das Wiki spricht von <supported-locale> und <resource-bundle>; bei mir geht es ohne. Vielleicht mache ich hier einfach noch was falsch. Anyway, kurz zum Aufbau der portlet.xml: Wer einen

14:05:30,735 ERROR [PortletLocalServiceImpl:704] com.liferay.portal.kernel.xml.DocumentException: Error on line 12 of document : cvc-complex-type.2.4.a: Invalid content was found starting with element ‘supported-locale’. One of ‘{…}’ is expected.

bekommt, der möge auf die Reihenfolge der Knoten achten – so einfach kann’s manchmal sein 🙂 Zum Beispiel muss <supported-locale> vor <resource-bundle> deklariert werden. Für mich funktioniert die Reihenfolge

Liferay: Friendly URL pattern

Die Doku gibt immer nur das Pattern “d+” (1 oder mehrere Ziffern) an. Interessant kann aber sein, zum Beispiel nur alphanumerische Zeichen zu erlauben. Wikipedia nennt dafür die Klasse [:alpha:], bzw “a”. “a+” funktioniert aber nicht (jede Kombination von “[:alpha:]” übrigens auch nicht). Die Docs des StringParser gibt den benötigten Hinweis: “[a-z]+”

Eine korrekt interpretierte Route lautet also zum Beispiel: