Startseite > Techblog > Artikel mit dem Tag: portlet
rbo

Wie in meinem letzten Beitrag angekündigt, wollte ich mich tiefergehend mit den Möglichkeiten des Grails Portlet Plugins beschäftigen. Da die Dokumentation nicht besonders aussagekräftig ist, galt es zunächst herauszufinden, ob man nicht nur Deskriptoren und Portlet Views generieren sondern auch Domain-Objekte im Portlet verwenden kann.

Dafür habe ich zu Testzwecken ein Domainobjekt mit dem Namen Blogpost erstellt:

grails create-domain-class de.communardo.liferay.grails.portlet.Blogpost

Die Domain Klasse Blogpost bekam schnell ein paar Properties:

package de.communardo.liferay.grails.portlet
class Blogpost {
    String title
    String author
    String content
}

Danach fix die Views generiert, als Vorlage für den Portlet View:

grails generate-portlet-views de.communardo.liferay.grails.portlet.Blogpost

Den folgenden Teil habe ich in die view.gsp für das Portlet übernommen:

<h1>Blogpost List</h1>
<div class="list">
	<table>
		<thead>
			<tr>
				<g:sortableColumn property="id" title="Id" />
				<g:sortableColumn property="author" title="Author" />
				<g:sortableColumn property="content" title="Content" />
				<g:sortableColumn property="title" title="Title" />
			</tr>
		</thead>
		<tbody>
		<g:each in="${blogpostInstanceList}" status="i" var="blogpostInstance">
			<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
				<td><g:link action="show" id="${blogpostInstance.id}">${fieldValue(bean:blogpostInstance, field:'id')}</g:link></td>
				<td>${fieldValue(bean:blogpostInstance, field:'author')}</td>
				<td>${fieldValue(bean:blogpostInstance, field:'content')}</td>
				<td>${fieldValue(bean:blogpostInstance, field:'title')}</td>
			</tr>
		</g:each>
		</tbody>
	</table>
</div>

Danach habe ich die Liste mit Blogposts in der renderView Closure der Portlet Klasse mit den vorhandenen Blogposts befüllt:

def renderView = {
    [ blogpostInstanceList: Blogpost.list()]
}

Für die Testdaten kam die bootstrap.groovy wie gerufen:

class BootStrap {
    def init = { servletContext ->
        new Blogpost(author:"Ralf Borchers",title:"Lifray Potlets mit Grails", content:"Es geht...").save()
    }
    ...
}

Dadurch werden die Daten beim Starten der Anwendung standardmäßig in einer HSQL DB gespeichert.

Damit war die Vorbreitung schon abgeschlossen und mein Portlet konnte redeployed werden:

grails war

Daraufhin war das Portlet kaputt und warf eine IllegalstateException:


java.lang.IllegalStateException: Root context attribute is not of type WebApplicationContext: com.liferay.portal.spring.context.PortalApplicationContext@10e35d5: display name [Root WebApplic
ationContext];

Ursache dafür scheint zu sein, dass das Hot Deployment von Spring Portlets nicht so richtig sauber funktioniert. Siehe auch hier. Nach dem Neustart startete das Portlet fehlerfrei und ich konnte stolz meinen Test-Blogposts im Portlet betrachten.

Zusammenfassend lässt sich sagen, dass man für komplexere Portlets eine Realisierung in Form eines Grails Portlets in Erwägung ziehen sollte. Man profitiert von vielen Features des Grails Frameworks und kann die Produktivität bei der Portletentwicklung sicher enorm steigern.

Kommentar Feed Trackback URL
rbo

Seit meinem letzten Grails Projekt verfolge ich aufmerksam jede Neuigkeit zum Thema Groovy und Grails. Aber auch die Entwicklung von Portlets für den freien Portal Server Liferay liegt im Bereich meines Interesses. Als ich dann auf  groovyblogs.org (empfehlenswerte Quelle!) laß, dass ein Grails Plugin released wurde, mit dem man Portlets für Liferay erstellen kann, war klar, dass ich das ausprobieren muss. Die Vorstellung davon, Portlet- und Deploymentdeskriptoren nicht alle händisch erstellen zu müssen, Actions sowie Views generieren zu lassen und dazu noch in Groovy entwickeln zu können erschien mir durchaus als vielversprechend.

Doch als Erstes mussten die Hürden einer Installation und eines lauffähigen Deployments genommen werden, was ich im Folgenden dokumentieren möchte:

1. Liferay ab Version 5.2 installieren

2. Grails ab Version 1.1.1 installieren

3. Umgebungsvariable für Liferay setzen:
LIFERAY_HOME=/your_path_to/liferay-portlet-5.2.1

4. Grails Application erstellen:

grails create-app demoportlets

5. In App Verzeichnis wechseln und Portlet Plugins installieren:

grails install-plugin portlets
grails install-plugin portlets-liferay
grails install-plugin liferay-exploded

6. Portlet erstellen: Hierbei sollte man darauf achten, keine Großbuchstaben im Namen (z.B. demoportlet) zu verwenden, da die gsp`s zur Laufzeit in einem Verzeichnis ohne Großbuchstaben gesucht werden.

grails create-portlet demoportlet

Ergebnis dieses Befehls ist, dass im Verzeichnis “portlets” eine lauffähige Portletklasse mit dem Namen DemoPortlet.groovy mit folgendem Inhalt liegt:

import javax.portlet.*

class DemoportletPortlet {

def title = 'Portlet Title'
def description = '''
Description about the portlet goes here.
'''
def displayName = 'Display Name'
def supports = ['text/html':['view', 'edit', 'help']]

// Liferay server specific configurations
def liferay_display_category = 'MyCategory'

def actionEdit = {
//TODO Define action phase
portletResponse.setPortletMode(PortletMode.VIEW)
}

def renderEdit = {
//TODO Define render phase. Return the map of the variables bound to the view
['mykey':'renderEdit called']
}

def actionView = {
//TODO Define action phase
}

def renderView = {
//TODO Define render phase. Return the map of the variables bound to the view
['mykey':'renderView called']
}

def actionHelp = {
//TODO Define action phase
portletResponse.setPortletMode(PortletMode.VIEW)
}

def renderHelp = {
//TODO Define render phase. Return the map of the variables bound to the view
['mykey':'renderHelp called']
}
}

7. Ich hatte das Problem, dass beim Generieren der Views ein Fehler flog, weil native2ascii nicht gefunden werden konnte. Das kann man beheben, in dem man JAVA_HOME auf ein JDK zeigen lässt. Alternativ kann man folgende Option in der config.groovy ausschalten um den Fehler zu umgehen:

grails.enable.native2ascii = false

8. Views generieren – netter Befehl, um edit.gsp, view.gsp und help.gsp vorzugenerieren:

grails generate-portlet-views demoportlet

9. Bauen und Deployen: An der Stelle hatte ich die größten Probleme, da auf meinem Rechner standardmäßig Java 1.6 läuft, Liferay jedoch seine eigene JRE mit der Version 1.5 mitbringt. Deswegen lautet meine Empfehlung: Bauen mit Java 1.5!

grails war

Danach kann man das fertige war-File aus dem App-Verzeichnis nach “liferay/deploy”  kopieren, was bei einem laufenden Liferay dazu führen sollte, dass das Portlet automatisch deployed wird.

Alternativ kann man zum Deployen auch das Liferay Exploded Plugin verwenden, was bei mir aber leider nicht funktioniert hat und beim Deployen mit einem Fehler quittiert wurde:

grails liferay-deploy
und folgend grails liferay-update

Nach dem Deployen sollte man das Portlet in der Kategorie “MyCategory” finden und auf einer beliebigen Seite instantiieren können.

DemoPortlet

DemoPortlet

Getestet habe ich das Deployment in Liferay Version 5.2.1 und 5.2.3, was dank Java 1.5 auch für beide Versionen funktioniert hat.

Für das ganze Prozedere habe ich am Ende doch länger gebraucht als erwartet und war einige Male kurz davor  aufzugeben. Jetzt bin ich aber wieder zuversichtlich und werde mich demnächst damit befassen, was man denn nun alles von der Grails-Funktionaliät im Portlet verwenden kann. Das Portlet selber bringt immerhin 23 MB auf die Waage und enthält sämtliche Libraries die Grails auch sonst so benötigt, wie Core, Crud, Gorm, Webflow etc. Das lässt zumindest hoffen, dass man auch Domainobjekte im Portlet verwenden kann.

Links:

http://grails.org/plugin/portlets
http://grails.org/plugin/portlets-liferay
http://grails.org/plugin/liferay-exploded

MyCategory

Kommentar Feed Trackback URL

Tag Cloud

Unsere Themen

Kommentare

  • Niels Jaeckel: Hallo Ralf, wir haben heute das Benno auf die Version 1.1.3 aktualisiert. Dort funktioniert die...
  • Patrick: Super und Vielen Dank für diesen Artikel!! War genau das, was ich gesucht habe und hat mir sehr geholfen
  • hanjo: whileprintingrecords; {Gruppierfeld}=Previous({Grupp ierfeld}) Gruppierfeld natürlich. Bug im Editor, hat die...
  • hanjo: Bedingte Unterdrückung Detailbereich wie beschrieben. Bedingte Unterdrückung Gruppenkopf 1b:...
  • Niels Jaeckel: Hallo Ralf, wir haben es noch nicht mit dieser Benno-Version getestet. Allerdings steht das Update auf...

Twitter