Pluto, jetty i portlety.
Tytułem wstępu, czyli kto i co.
Witajcie.
To mój debiut na j2ee.pl i mam nadzieję, że będzie początkiem dłuższej przygody. W tym poście postaram się opisać jak, w kilku krokach, stworzyć i uruchomić prosty portlet używając mavena2 i kilku jego pluginów. Dlaczego to jest takie fajne? Ponieważ wystarczy wpisać mvn jetty:run i można testować swój portlet. Trwa to kilka sekund, więc oszczędność czasu może być znacząca w porównaniu z restartem jBoss Portal, lub Liferay. Ponieważ pomysłem było napisanie prostego howto, części teoretycznej niestety nie będzie. Nie znajdziecie tutaj co to jest portal/kontener portletów, ani nawet sam portlet. Zainteresowane osoby odsyłam do specyfikacji JSR168 i wszechwiedzącej sieci.
Co będzie potrzebne?
Właściwie tylko maven2 i jakiś edytorek kodu (zakładam, że w miarę nową jave każdy ma). Razem z m2 będziemy używać pluginów jetty i pluto. Jetty jest implementacją serwera webowego, natomiast pluto jest referencyjną implementacją specyfikacji portletów.
Tworzymy projekt.
Do wygenerowania szkieletu projektu wykorzystamy archetyp maven-archetype-portlet:
mvn archetype:create -DgroupId=pl.j2ee.portlet -DartifactId=portlet-example -DarchetypeArtifactId=maven-archetype-portlet
Jeśli zamierzamy używać Eclipse’a, przechodzimy do katalogu projektu i wykonujemy: mvn eclipse:eclipse
Kolejną rzeczą, jaką należy wykonać, jest modyfikacja pom.xml projektu. Proponuję stworzyć oddzielny profil, np. pluto-embedded:
<profile> <id>pluto-embedded</id> [...] </profile>
i w nim dodać wpisy dla pluginów:
<plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> </plugin>
oraz
<plugin>
<groupId>org.apache.pluto</groupId>
<artifactId>maven-pluto-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
Goal assemble posłuży do wygenerowania web.xml z odpowiednią konfiguracją i mapowaniem serwletu org.apache.pluto.core.PortletServlet. Kolejną rzeczą jest konfiguracja pluginu jetty:
<configuration>
<webXml>${project.build.directory}/pluto-resources/web.xml</webXml>
<webDefaultXml>src/main/webapp/WEB-INF/jetty-pluto-web-default.xml</webDefaultXml>
<systemProperties>
<systemProperty>
<name>org.apache.pluto.embedded.portletId</name>
<value>MyPortlet</value>
</systemProperty>
</systemProperties>
</configuration>
Tag <webXml> wskazuje na miejsce, z którego jetty zaczyta sobie deskryptor web.xml-a (wygenerowany wcześniej przez pluto).
Ponieważ pluto korzysta z pliku src/main/webapp/WEB-INF/web.xml do generowania pliku wynikowego, a my nie będziemy potrzebować dodatkowych mapowań, usuwamy to co stworzył nam archetyp i zostawiamy ten plik w postaci:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> </web-app>
Kolejna rzecz, której potrzebujemy, to konfiguracja parametrów kontekstu, filtrów, serwletów, mapowań itp. Najwygodniej jest użyć gotowego pliku jetty-pluto-web-default.xml, który można znaleźć w archiwum maven-jetty-pluto-embedded-1.0.jar, lub w załączonych źródłach projektu.
Przejdźmy więc do edycji pliku portlet.xml. Jego zawartość zawiera większość potrzebnych informacji, ale zawiera też błędy – tag <portlet-class> jest nieprawidłowo stworzony przez archetyp i należy go nieznacznie zmodyfikować wpisując poprawną nazwę klasy portletu. Zmieniamy także wartość tagu <portlet-name> tak, aby odpowiadała property org.apache.pluto.embedded.portletId z pom.xml projektu. Na chwilę jeszcze wróćmy do pom.xml projektu i uzupełnijmy zależności:
<dependency> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty</artifactId> <version>6.1.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.mortbay.jetty</groupId> <artifactId>jsp-2.1</artifactId> <version>6.1.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.bekk.boss</groupId> <artifactId>maven-jetty-pluto-embedded</artifactId> <version>1.0</version> </dependency>
Aby sprawdzić, czy wszystko zrobiliśmy dobrze, przechodzimy do katalogu projektu i wpisujemy:
mvn jetty:run -P pluto-embedded
Gdy uruchomi nam się serwer, wpisujemy w przeglądarce http:localhost:8080/portlet-example/pluto/index.jsp i voilà!
Jeśli komuś nie odpowiada port 8080 na którym słucha serwer, może zmodyfikować konfigurację pluginu. Teraz, gdy już widzimy, że wszystko w miarę fajnie się prezentuje zrobimy prosty formularz powitalny: W pliku normal.jsp zamiast powitania mavena, stwórzmy formularz:
<c:choose>
<c:when test="${not empty param.fullName}">
Hello <c:out value="${param.fullName}"></c:out>
</c:when>
<c:otherwise>
<form action="<portlet:actionURL/>" method="post" id="nameForm">
<table>
<tr><td>First name:</td><td><input name="firstName" type="text" id="firstName"/></td></tr>
<tr><td>Last name:</td><td><input name="lastName" type="text" id="lastName"/></td></tr>
<tr><td></td><td><input name="submit" type="submit" id="submit"/></td></tr>
</table>
</form>
</c:otherwise>
</c:choose>
Następnie w klasie MyPortlet dodajemy prostą metodę:
public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
if(request.getParameter("firstName") != null && request.getParameter("lastName") != null)
response.setRenderParameter("fullName", request.getParameter("firstName") + " " + request.getParameter("lastName"));
}
Podsumowanie.
Ponieważ, jak już wspomniałem, jest to mój pierwszy post na j2ee.pl (dzięki Michał :) ), będę wdzięczny za wszystkie komentarze. Piszcie, co Wam się podobało, co nie i czy takie how-to do czegoś Wam się przydało. Może coś jest niejasne, albo czegoś brakuje…W następnym poście postaram się dodać testy jwebunit-owe i pokazać w jaki sposób można taki formularz potraktować testami jednostkowymi.








September 15th, 2008 at 22:17
witam,
Zauważyłem błąd w linku,powinno być http://localhost:8080/portlet-example/normal.jsp a druga sprawa, że proba uruchomienia ze źródeł kończy sie java.lang.NullPointerException :( Ale fajnie, że temat jest poruszany…