Showing posts with label maven 2. Show all posts
Showing posts with label maven 2. Show all posts

Monday, February 11, 2008

Struts 2 Portlet in WebSphere 5.1

At work I recently wanted to build a Struts 2 Portlet to see if I could deploy it in WebSphere Portal 5.1. As you know, Struts 2 requires Java 5 to run, and as you might also know, WebSphere Portal 5.1 only runs Java 1.4. Retrotranslator to the rescue! I added the retrotranslator-maven-plugin from the Codehaus Mojo project, and set it up to run the translate-war goal:


<build>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>retrotranslator-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<goals>
<goal>translate-war</goal>
</goals>
<configuration>
<classifier>jdk1.4</classifier>
<attach>true</attach>
<advanced>true</advanced>
</configuration>
</execution>
</executions>
</plugin>
</build>


I also had to include a couple of new dependencies introduced by Retrotranslator:


<dependencies>
<dependency>
<groupId>backport-util-concurrent</groupId>
<artifactId>backport-util-concurrent</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>net.sf.retrotranslator</groupId>
<artifactId>retrotranslator-runtime</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>


I had to use the 1.0-alpha-2 version of the plugin, otherwise I got an obscure java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean failure...

Unfortunately, that was not quite enough. When running the portlet, I would get an exception about a missing javax.xml.namespace.NamespaceContext class which XWork aparently needs. It appears that this class is included in the Java 5 libraries, but not with Java 1.4. I found it in the jaxp-api.jar in the Sun Java Web Services Developer Pack 2.0. I placed this jar in the %WAS_HOME%/java/jre/lib/ext folder (I tried putting it in the web application, but that didn't work... Classloading in JEE application servers has always been fun...). I also had to exclude any web application dependencies that included Xerces, Xalan or xml-apis.

No guarantees that this works for you though. But I guess as long as you don't break any of the limitations retrotranslator has, you'll be fine.

Saturday, October 06, 2007

Easy portlet development and reduced roundtrip with the updated Struts 2 portlet archetype

The entry has been updated to reflect the new 2.1.1-SNAPSHOT release

I have just deployed an updated version of the Struts 2 portlet archetype, which is based on Struts 2.1.1. The archetype also includes the jetty-pluto integration which should reduce the roundtrip from development to testing and running quite a lot.

To create a basic Struts 2 portlet with the archetype, run the command

mvn archetype:create
-DgroupId=<groupId>
-DartifactId=<artifactId>
-DarchetypeGroupId=org.apache.struts
-DarchetypeArtifactId=struts2-archetype-portlet
-DarchetypeVersion=2.1.1-SNAPSHOT
-DremoteRepositories=
http://people.apache.org/repo/m2-snapshot-repository

(all on one line)

Just replace <groupId> and <artifactId> with your real groupId and artifactId. Now you can just type mvn jetty:run -P pluto-embedded to run the portlet in pluto. The pluto-embedded profile does the magic of setting up the integration between the maven-jetty-plugin and pluto. To test it, just open a browser and point it to http://localhost:8080/<artifactId>/pluto/index.jsp

I have also included a class called JettyPlutoLauncher (you might recognize it from a previous entry) in the test sources of the generated project. It is simply a class with a main method that can be used to launch the portlet from your IDE. To use it with eclipse simply type mvn eclipse:eclipse -P pluto-embedded, import the project in Eclipse, and select to run the JettyPlutoLauncher class. Then open a browser to the same URL as described above.

This will hopefully get you up and running with Struts 2 portlet development pretty quick!

Sunday, August 05, 2007

maven-jetty-plugin and JSR168 portlets - Part 2

My last post outlined how I made the maven-jetty-plugin work with a maven 2 portlet project. As I mentioned, there were some issues with the approach if you're using Spring in your application. Also, there were some files you needed to include in your project. That's not too big of a problem solving using excludes in your pom so the files are not included in your build, but it's still a bit annoying having them around. And finally, there were no portlet controls, so changing modes and window states were impossible unless you manually created links in your portlet. So the solution had to improve...

The first obstacle to overtake was how to enable the controls for switching modes and window states. I thought this was going to be easy, but trial and (mostly) error should prove me wrong. It became clear to me that the approach of adding the pluto dependencies to the plugin instead of the application caused problems with loading a resource bundle that the pluto taglib required. I solved this temporarily by adding the ToolTips.properties file to the pluto-portal-driver-1.1.4.jar file. Good enough for now. This brought me one step further: The pluto:modeAnchor and pluto:windowStateAnchor tags now rendered correctly, but they required some stylesheets and javascript files that comes with the pluto web application to actually show the controls. This forced me to add a bunch of new files to my application, and it was really starting to pollute my project.

The next task was Spring support. Having Spring on the application- and plugin classpath will cause classloader problems (you'll get ClassCastExceptions since the Spring classes are loaded from two different classloaders). Another problem is that both your application and pluto requires the ContextLoaderListener and the contextConfigLocation context parameter to be set. Basically, to make this work with just maven-jetty-plugin configuration options would require me to split the configuration options into three separate files; a webdefaults descriptor, web.xml and an override descriptor. This is really starting to look bad...

Coming this far, I realized that the current solution wasn't going to be a very good. It would work, but it wasn't good enough. First of all, the classloading issues with the resource bundle and Spring classes convinced me that it was better adding the dependendices to the application instead of the plugin. I also needed to find a solution to the problem with the ContextLoaderListener. And last, I needed to get rid of all the stylesheets, images, javascripts, jsp files and configuration files from the application, into one single artifact that could be included as a dependency to the application. This means that I would have to serve all the required resources from one jar file.

The ContextLoaderListener problem was solved using a custom, jetty specific, context listener that use the internal jetty context classes to modify the context parameters and ensuring that only one context loader listener instance exists. I then added this listener to the webdefaults file, ensuring it is the very first listener that is executed. Quite brutal, but it works...

Identifying and collecting all the required stylesheets, JSP files, images etc into one jar file was easy. The hard part was how to make them available to the pluto driver, when they always were meant to be a part of the running web application... So all lookups/URLs to files like /pluto.css, /images/controls/edit.png, /WEB-INF/pluto-portal-driver-config.xml, and not to forget, the jsp that acts as the entry point to the portlet container (I've named it /pluto/index.jsp), would have to be served from this jar. Taking inspiration from the Struts 2 FilterDispatcher, serving static resources referenced from URLs to the web application was easy using a servlet filter. But how was I going to "intercept" the lookups to the resources in /WEB-INF? And how can one serve a JSP file from within a JAR file? Looking through the source of the RenderConfigServiceImpl (which loads the /WEB-INF/pluto-portal-driver-config.xml file) and the Jasper JspServlet, it appears that they both look up resources using ServletContext.getResource and ServletContext.getResourceAsStream. If I could intercept these calls and look up the resources from the classpath instead, the problem should be solved. So I wrote a wrapper servlet for the JspServlet, and a wrapper context listener for the PortalStartupListener (which in turn initializes the RenderConfigServiceImpl) that just delegates to the wrapped objects, passing them a wrapped instance of ServletContext that looks up the resources it does not find in /WEB-INF with the ClassLoader.getResource and ClassLoader.getResourceAsStream methods instead. Problem solved!

This left me with two resources; the pluto.tld file and the customized webdefaults descriptor. For the pluto.tld file, I just placed it in the META-INF folder of the jar file, and renamed it to taglib.tld. This is discovered by the servlet container automatically when it is referenced through the correct uri in the jsp files using it. One file left; the webdefaults descriptor. After a lot of trial and error (again...) (I even tried extending the maven-jetty-plugin to add a new configuration option, but this proved fruitless as I discovered that it is not possible to extend a maven 2 plugin...), I could not find a solution. So it remains unsolved until the maven-jetty-plugin is modified to look up a webdefaults descriptor by some other means than just a file path (I'll probably create a JIRA issue for this. Update: JIRA issue created). But still, I'm now left with only one jar file added to the dependency of the application, and one webdefaults file that I add to the application itself (and is easily excluded in the pom). I've also added the dependency to a profile, so it's only active when I specify this profile on the command line. It looks like this:


Update: The maven-jetty-pluto-embedded artifact is available in the Maven 2 repositories.



<profiles>
<profile>
<id>pluto-embedded</id>
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<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>MyPortletAsDefinedInPortletXml</value>
</systemProperty>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.bekk.boss</groupId>
<artifactId>maven-jetty-pluto-embedded</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</profile>
</profiles>


Of course, you need the maven-pluto-plugin as well, as described in the previous post. Also, note the system property configuration specifying the id of the portlet to run.

I run this setup using the command mvn jetty:run -P pluto-embedded. Now I'm a lot more happy with the solution. Below is a screenshot how this looks running with the Struts 2 sample portlet application (click the image to enlarge):

maven jetty plugin running embedded with Pluto

You can download the jetty-pluto-web-default.xml file and try it yourself. Just put the xml file in your /WEB-INF folder. All feedback is appreciated.

Tuesday, July 31, 2007

maven-jetty-plugin and JSR168 portlets

Inspired by Don Brown's Developing a Portlet using Eclipse tutorial for Struts 2 and some information I found on the Pluto FAQ, I started playing around with embedding pluto in a Maven 2 project. The goal was to be able to use the maven-jetty-plugin to run and test my portlets with Jetty just by typing mvn jetty:run. That would definitively be a step up to increase developer productivity!

After googling a lot and collecting information from various sources, I managed to get things up and running! Here's the steps needed to get the maven-jetty-plugin to work with your Maven 2 portlet project.

The formula

First of all, this only works with Pluto 1.1.4, which is not currently released, but probably will be soon. The reason is that Pluto 1.1.3 does not work with JSP 2.1. So the first thing to do is to get the Pluto sources from SVN from the pluto-1.1.4 tag and build it according to the istructions. This will install the pluto 1.1.4 artifacts in your local maven repository. Alternatively, I guess you could just add the apache maven staging repository to your pom.xml (which does sound a bit easier when I think of it...)

The next step is to add the maven-pluto-plugin to your pom.xml. This is needed to add the web.xml entries for the wrapper servlets for the portlet.

<plugin>
<groupId>org.apache.pluto</groupId>
<artifactId>maven-pluto-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>


And of course, we need the jetty plugin as well:


<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
</plugin>


Now, we need to add the dependencies needed by the pluto portlet container. I chose to add these to the plugin classpath, but you could also add them to the project dependencies instead. So within the scope of the plugin tag for the jetty plugin, add a section of dependencies:


<dependencies>
<dependency>
<groupId>org.apache.pluto</groupId>
<artifactId>pluto-portal-driver</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.pluto</groupId>
<artifactId>pluto-portal-driver-impl</artifactId>
<version>1.1.4</version>
<dependency>
<dependency>
<groupId>org.apache.pluto</groupId>
<artifactId>pluto-container</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.pluto</groupId>
<artifactId>pluto-taglib</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<<version>2.0.2</version>
</dependency>
</dependencies>


(That's right, there's a Spring dependency in there, which can cause some troubles if you're using Spring already, but let's skip that for now...)

The maven-pluto-plugin generates a web.xml file and puts it in the ${project.build.directory}/pluto-resources/ folder. So we need to customize the configuration of the plugin a bit. So add this to the maven-jetty-plugin definition in the pom.xml:


<configuration>
<webXml>${project.build.directory}/pluto-resources/web.xml</webXml>
</configuration>


Still, that's unfortunately not entirely enough for the jetty plugin. We also need to add a context-parameter, filter, filter-mapping(s) and some servlet context listeners to the web.xml. Now, I don't want to pollute my original web.xml with this stuff, so I considered a couple of options. Either, I could add an overrideweb.xml file, which is added to the web application configuration after the jetty:run goal is invoked, or I could create a new webdefault xml file, which is applied before. After trying both options, I decided to go for the second solution (I'm not going into that now, but it's the only way I could get it to work with Spring in a way I was happy with). Therefore, I extracted the webdefault.xml file from the jetty jar file, and added the required cofigurations:


<!-- Spring configuration file for the portlet container services -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/pluto-portal-driver-services-config.xml</param-value>
</context-param>

<!-- The Spring context loader listener and the startup listener for the dummy portal -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.apache.pluto.driver.PortalStartupListener</listener-class>
</listener>

<!-- The pluto driver that will intercept our JSP "portal" -->
<filter>
<filter-name>plutoPortalDriver</filter-name>
<filter-class>org.apache.pluto.driver.PortalDriverFilter</filter-class>
</filter>

<!-- The filter will intercept our /test-portal/index.jsp file and everything beneath it -->
<filter-mapping>
<filter-name>plutoPortalDriver</filter-name>
<url-pattern>/test-portal/index.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>plutoPortalDriver</filter-name>
<url-pattern>/test-portal/index.jsp/*</url-pattern>
</filter-mapping>

<!-- The container taglibs that invoke our portlet in the portlet container -->
<jsp-config>
<taglib>
<taglib-uri>http://portals.apache.org/pluto</taglib-uri>
<taglib-location>/WEB-INF/tld/pluto.tld</taglib-location>
</taglib>
</jsp-config>


For now, I just put this new webdefault xml file (I named it jetty-pluto-web-default.xml) in the /WEB-INF folder of the application, and added a new configuration option for the jetty plugin:


<configuration>
<webDefaultXml>src/main/webapp/WEB-INF/jetty-pluto-web-default.xml</webDefaultXml>
<webXml>target/pluto-resources/web.xml</webXml>
</configuration>


Almost done now! We need three files from pluto. These are configuration- and taglib files that initialize the portlet container, and instead of listing them here, just download the pluto-portal-driver-config.xml and the pluto-portal-driver-services-config.xml and put them in the WEB-INF folder of your application. Then create a tld folder in the same folder, and download the pluto.tld file to this folder.

The last steps is to create a "dummy portal" entry point. I created a folder named test-portal in the src/main/webapp folder, and created an index.jsp file that acts as the entry point to the portlet container. The index.jsp file looks like this:


<%@ taglib uri="http://portals.apache.org/pluto" prefix="pluto" %>
<pluto:portlet portletId="/struts2-portlet.StrutsPortlet">
<div class="portlet" id="struts2-portlet.StrutsPortlet">
<div class="header">
<h2 class="title"><pluto:title></pluto:title></h2>
</div>
<div class="body">
<pluto:render></pluto:render>
</div>
</div>
</pluto:portlet>


The portletId in the <pluto:portlet> tag is composed of the context root of the web application, and the name of the portlet as defined in the portlet.xml file.

Now, everything should be set up, and you should be able to view your portlet by pointing your browser to http://localhost:8080/<context-root>/test-portal/index.jsp (note that you need to point to the index.jsp file, it will not work just pointing it to /test-portal/ due to the filter mappings).

If you don't want to do all these steps manually, I have created an archived maven project based on the struts2-archetype-portlet, as described in Don's tutorial, and added all the required files and settings.

Conclusion

This might seem like an awful lot of work to get the jetty plugin to work with portlets, but I believe it's worth the effort. I have never been more productive developing portlets than after I got this up and running. And when you have been through this once, just add it to your set of templates/archetypes so you won't have to do it again.

And please, if you find any errors in this article, please drop me a comment so I can correct them.

Update: See part 2 to see how the solution has improved.

Update 2: Pluto 1.1.4 has been released and should be available from the regular maven repositories.