The Holy Java

Building the right thing, building it right, fast

Archive for April, 2009

Lotus Notes 8.x under Linux: No window shows up, Tips for upgrading to LN8.5

Posted by Jakub Holý on April 30, 2009

Since recently when I started Lotus Notes 8.0.2 as another user via sudo, it has started with the splash screen, asked for a password nad displayed a progress bar but as soon as the startup finished and the splash screen disappeared it hasn’t open the main window. The process was running but there was no visible manifestation of it.

After a long time and an upgrade to LN 8.5 I’ve figured out that perhaps there was something wrong with the configuration. The reason to think so is that LN8.5 exhibited exactly the same problem but for all users. Later I’ve discovered that there were some configuration files like /etc/notes/ and /etc/ibm-hannover.conf left from the previous version though I uninstalled it (maybe these aren’t created during the installation but during first startup). After their deletion and LN8.5 reinstall it more less started to work.

Upgrading Lotus Notes 8.0.2 to 8.5

Based on my experience I’d recommand the following steps when upgading 8.0.2 to 8.5:

  1. Uninstall LN 8.0.2 (I installed mine from .deb packages created by converting .rpm packages by alien).
  2. Remove  /etc/notes/ and /etc/ibm-hannover.conf.
  3. Move $HOME/lotus/ somewhere else so that when you run LN for the 1st time it works in a clean environment. You can move it back when you get LN working.
  4. Install LN8.5 – now there are .deb packages. You will need to install ibm_lotus_notes-8.5.i586.deb first for the others depend on it.
    • Some people recommend to change /bin/sh to point to /bin/bash. That’s a good idea also for other IBM software, for instance I was long unable to install Rational Software Developer 7.x for a mysterious problem caused by having /bin/sh pointing to dash (a bash-like thing used by default under Ubuntu).
    • Some people recommend installing additional fonts otherwise LN may use just one ugly font.
  5. Start it by running /opt/ibm/lotus/notes/notes from the command line.
    1. It should print some output and after a while open a new terminal window with license. Scroll till its end using Enters, accept by typing 1 [Enter].
      • Maybe it isn’t necessary to go to the license’s end but once I’ve accepted it already when it opened but it somehow hasn’t worked out.
      • Under Xfce the license window hasn’t opened. Switching to Gnome fixed the problem. If you try to run notes again, it will print some logs and end, close to its end you could see the warning that the license hasn’t been accepted.
      • You may need to try several times to get the license window. But be patient, it takes the installer few (10s of) seconds to open it.
    2. LN finishes without actually doing something. You need to run it again (/opt/ibm/lotus/notes/note) to actually start it. (Still it sometimes happens to me that running it does nothing and I have to run it again.) It should open the new user dialog. Give it what it wants to get the main window open.
  6. Close LN. Now you’ve verified that it does indeed run.
  7. Move the newly created $HOME/lotus/ somewhere and move (or copy) back your original mail file.
  8. Start LN. Again you will be asked for a license confirmation (since you have a new lotus folder, it doesn’t rember you accepting it already) etc.

My environment

  • Ubuntu 9.0.4 (recently upgraded from 8.0.4 when the problem first appeared).
  • LN 8.5

Resources

Posted in Tools | Comments Off

How I managed to deploy a JSF/Seam portlet to JBoss after all

Posted by Jakub Holý on April 20, 2009

Deploying a custom JSF/Seam portlet to JBoss Portal Server isn’t as easy as you’d expect, either manually or using Eclipse with JBoss Tools. I’ll share with you what I learned about this.

Introduction

See the previous Seam Tutorial 1.1 and 1.2 to learn what SW versions I use, how to configure a server in Eclipse etc. The issues with JBoss Tools, JBoss Portal, and Seam/RichFaces depend pretty much on their respective version and can change significantly even with a minor version change.

Including:

  • jboss-portlet-bridge-1.0.0.B6

In the blog JBoss Portlet support in Eclipse you may learn more about creating portlets for JBoss in Eclipse and issues with various versions of JBoss Tools.

Deploying a portlet via Maven 2

JBoss provides Maven archetypes for creating Seam portlets and also tasks for deploying them to a portal server, either an existing one or a newly downloaded one. This is described in the development guide but not sufficiently.

Note: You need maven 2.0.9 or higher.

  1. run$ mkdir /tmp/jboss; cd /tmp/jboss
  2. run$ mvn archetype:generate
    -DarchetypeGroupId=org.jboss.portletbridge.archetypes
    -DarchetypeArtifactId=seam-basic
    -DarchetypeVersion=1.0.0.B6
    -DgroupId=eu.ibacz.seamtutorial2
    -DartifactId=seamproject
    -DarchetypeRepository=http://repository.jboss.org/maven2/

    (accept all defaults)
  3. cd /tmp/jbossrun/seamproject
  4. edit /tmp/jboss/seamproject/web/pom.xml
    • Running mvn install would fail because of missing org.jboss.portletbridge:portletbridge-api:jar:1.0-SNAPSHOT for  eu.ibacz.seamtutorial2.web:seamproject:war:1.0-SNAPSHOT.
    • => replace <version>${project.version}</version> with <version>${portletbridge.version}</version> for artifactId portletbridge-api in /tmp/jboss/seamproject/web/pom.xml
  5. run$  mvn install
    This will create a WAR package and install it into the local maven repository.
  6. run$ cd /tmp/jboss/seamproject/ear
  7. run$  mvn -Plocal-portal cargo:start
    This uses the Maven plugin cargo to start a local JBoss Portal. It must be run from the ear/ folder because ear/pom.xml defines the necessary settings.
  8. Set the JDK to use if needed – JBoss requires JRE 1.5. and has troubles under 1.6. You may define the JRE to use by adding a property like
    <cargo.java.home>/path/to/jdk1.5.0_17/jre</cargo.java.home>

    to the other cargo properties in ear/pom.xml
    Indication of the problem: an error like below in jboss startup log:
    [INFO] [talledLocalContainer] Caused by: java.lang.UnsupportedOperationException: setProperty must be overridden by all subclasses of SOAPMessage
    - Strangely jboss still reports jre 1.6 after setting this property but the error disappears:
    [INFO] [talledLocalContainer] 10:14:54,415 INFO  [ServerInfo] Java version: 1.6.0_07,Sun Microsystems Inc.

    Output:
    [INFO] [cargo:start]
    [INFO] [talledLocalContainer] Parsed JBoss version = [4.2.3]
    [INFO] [talledLocalContainer] JBoss 4.2.3 starting…

    [INFO] [talledLocalContainer] 10:01:34,211 INFO [Server] JBoss (MX MicroKernel) [4.2.3.GA (build: SVNTag=JBoss_4_2_3_GA date=200807181417)] Started in 2m:34s:75ms

  9. (in new window) run$ mvn cargo:deploy -Plocal-portal
    [INFO] [cargo:deploy]
    [INFO] [talledLocalContainer] Parsed JBoss version = [4.2.3]
    [INFO] [stalledLocalDeployer] Deploying [/POWEROLAP/jboss/seamproject/ear/target/seamproject-1.0-SNAPSHOT.ear] to [/POWEROLAP/jboss/seamproject/ear/target/installs/jboss-portal-2.7.0.GA-bundled/jboss-portal-2.7.0.GA/server/default/deploy]...
    (Some related logs are added also to the window where we started jboss.)
  10. Go to http://localhost:8080/portal You should see a tab called “seamproject” in the portal.

The bug report DOC-13317 describes the shortcomings of the documentation for this.

Manual deployement of a Seam portlet created with Eclipse/JBoss Tools

How to create a Seam portlet in Eclipse with JBoss Tools and deploy it to JBoss Portal.

Create a new Seam portlet project

Note> There are multiple ways to create a Seam Portlet project.

New > Project > Dynamic Web Project >

  1. Page Dynamic Web Project:
    • Target runtime: jboss 4.3.2 portal 2.7.1,
    • Dynamic Web Module version: 2.5
    • Configuration “JBoss Seam Portlet Project v2.0″; if you haven’t it on the selection list, click [Modify...] and select the facets Seam, JBoss Portlets and all under it (JBoss Core Portlet, JBoss JSF Portlet, JBoss Seam Portlet), Java, Dynamic Web Module.
    • Click Next >
  2. Page Web Modules: keep the defaults.
  3. Page JBoss Portlet Capabilities: keep the defaults (Enable implementation library, Libraries provided by server runtime).
  4. Page JSF Capabilities: keep the defaults (Server supplied JSF implementation, …).
  5. Page Seam Facet: set the Seam runtime and Database as we did in the other projects of my Seam/RichFaces tutorials (TODO link).
  6. Page JBoss Portlet Capabilities: Portletbridge Runtime: select e.g. jboss-portal-2.7.1/server/default/deploy/jboss-portal.sar/lib .

Add a portlet to the project

New > Other… > JBoss Tools Web > Portlet > JBoss JSF/Seam Portlet (there is also a plain Java Portlet).

Accept all defaults. This will create a portlet called seamPortlet that will display the page home.xhtrml.

Deploy the portlet

One we have created s Seam portlet we would like to be able to deploy it to JBoss Portal. Here we will learn how to deploy it manually, that means by exporting it from Eclipse as a WAR file and installing that to the server. If you try that you will fail. Below I describe the necessary steps to get the exported WAR working under JBoss.

By comparing the SeamBooking example portlet that you can find in the portlet bridge download package and my Seam portlet exported from Eclipse I’ve discovered the following differences.

  • SeamBooking’s META-INF/ contains a persistence.xml (likely some JPA stuff).
  • SeamBooking’s jboss-portlet.xml defines links to 2 RichFaces JavaScript files and 1 CSS file.
  • SeamBooking’s jboss-object.xml has the property theme.renderSetId=emptyRenderer .
  • My portlet exported from Eclipse contains many libraries in WEB-INF/lib/ but not e.g. any portletbridge stuff.

Deploy the exporeted WAR to JBoss and start it.

Attempt I – failure:

  1. Missing portletbridge class:
    Cause: Unable to find class 'org.jboss.portletbridge.application.PortletViewHandler'

    &l
    t;li>Missing datasource.

Solution:

  1. Copy portletbridge-impl.jar and portletbridge-api.jar to the WAR’s WEB-INF/lib/.
  2. Copy
    /resources/*-ds.xml to deploy/.

Attempt II – failure:

ERROR [LifeCycle] Cannot start objectorg.jboss.portal.portlet.container.PortletInitializationException: The portlet seamPortlet threw a runtime exception during init
Caused by: java.lang.ClassCastException: javax.portlet.faces.GenericFacesPortlet cannot be cast to javax.portlet.Portlet
    at org.jboss.portal.portlet.impl.jsr168.PortletContainerImpl.start(PortletContainerImpl.java:254)

Solution: Remove all portal*, portlet*.jar including portlet-api.jar (contains javax.portlet.Portlet.class), excluding. portletbridge.

Attempt III – portlet running:

No there are no more exceptions and when JBoss Portal starts, you will see there the tab “seamPortlet” with your portlet.

However when you go to the tab to see your portlet there will be another exception:

ERROR [InternalPortletContentProvider] Portlet invoker exception during portlet window renderingorg.jboss.portal.portlet.PortletInvokerException: javax.servlet.ServletException
Caused by: java.lang.NoSuchMethodError: org.ajax4jsf.context.ViewResources.processHeadResources(Ljavax/faces/context/FacesContext;)V

Solution: Replace libs with richfaces-api-3.3.0.GA.jar richfaces-impl-3.3.0.GA.jar richfaces-ui-3.3.0.GA.jar

Attempt VI – everything finally works.

Seam portlet deployment from Eclipse with JBoss Tools

This is something I haven’t managed so far :-(

Posted in Portlets | Tagged: , , , , , , , , , , | 2 Comments »

Developing portlets for Liferay in Eclipse

Posted by Jakub Holý on April 20, 2009

In this blog I’d like to tell you how to use Eclipse with Liferay to develop portlets with the ability to change a class or a JSP in Eclipse and have that immediatelly reflected on the server (hot deployment).

Environment

  • Liferay Portal 5.2.2 running on Tomcat 5.5.27.
  • Eclipse IDE for Java EE Developers, version Ganymede 3.4.1.
  • (optional) Eclipse Maven plugin m2eclipse 0.9.6.

A note about Eclipse and Maven projects

My web project is actually also a Maven project because we use Maven for building our projects. That means that it has a specific directory structure (src/main/webapp, target/classes, etc.) and that it includes a pom.xml that defines its dependencies on other artifacts, usually JAR libraries. Thanks to the m2eclipse plugin, Eclipse is aware of these dependencies and makes them available to the project during development and deployment.

With the m2eclipse plugin you get the nice feature that if your web application project depends on an artifact produced from another Eclipse project then if you change something in this project you depend upon, Eclipse detect it and pushes the change to the web application deployed on a server.

Normally with maven alone you would need to run mvn install or mvn package on the library project and either copy the produced .jar manually to the deployed webapp’s WEB-INF/lib or do a full rebuild (mvn package) and redeploy of the web app.

Preparing the portlet project for hot deployment to Liferay

Normally you deploy a WAR with portlets by putting them in the Liferay’s hot deploy directory (<liferay>/deploy). It notices that, processes the WAR, and deploys it to Tomcat. However since Eclipse knows nothing about Liferay and can only deploy to Tomcat itself in the normal way, that means by copying the exploded WAR to <liferay>/tomcat-5.5.27/webapps/, we need to do the Liferay’s modifications by ourselves and also modify the way that Eclipse does the deployment. Liferay does monitor Tomcat’s webapps/ directory and will detect a change to an application and redeploy it however this deployment doesn’t include all the operations that are performed when deploying via its hot deploy directory.

Configuring Eclipse

1. Define a Server Runtime Environment for Liferay

  1. Window > Preferences > Server > Runtime Environments > Add… .
  2. Select Apache Tomcat 5.5.
  3. For the Tomcat installation directory browse to or type <liferay>/tomcat-5.5.27 (replace <liferay> with you liferay installation directory, of course).
  4. Name it e.g. “Liferay 5.2.2@Tomcat 5.5.27″.

2. Define a Server instance for Liferay

  1. Window > Show View > Other… > Server > Servers.
  2. Right-click somewhere in the view Servers > New > Server:
    • Server type Tomcat v5.5 Server.
    • Server runtime environment: select the one defined in the previous step (Liferay 5.2.2@Tomcat 5.5.27).

3. Adjust the server’s configuration

In the view Servers, double-click on the newly created server, which will open its configuration. Do the following modifications:

  • In Server Locations change “Use workspace metadata” to “Use Tomcat installation”.
    • Notice: If you have any projects deployed to the server, this section is greyed-out and cannot be edited. Remove all projects from the server, publish, perhaps restart and you should be able to modify this settings.
  • In Server Locations change Deploy path from wtpwebapps to webapps. (Maybe this isn’t necessary but I wanted to be sure I won’t create any troubles for the Liferay’s monitoring.)
  • In Timeouts perhaps increase the Start timeout to some period long enough, e.g. 300 s. (My Liferay usually starts in ~ 70s but once it took over 200 s.)
  • During server startup, if you get

    Exception in thread “main” java.lang.OutOfMemoryError: PermGen space

    then click Open launch configuration in the server’s configuration and add something like -XX:MaxPermSize=128m to Arguments > VM arguments.

Now you should be able to run the server, deploy your portlet webapp to it (view Servers > right-clik the server > Add and Remove Projects …) and see your portlets in the Liferay portal (login, Add application > find it under the category you’ve defined in your liferay-display.xml > add it to a page).

When you deployed the application to the server, you should have been able to see in the log (i.e. in the Eclipse’s Console view) that Liferay has detected it and deployed the portlets. There should be a line like

INFO [PortletHotDeployListener:303] 1 portlets for <your webapp’s name> are available for use

telling you that your portlet is deployed and ready to use.

Adjusting the portlet project

When you add you portlet to a portal page, you will be most likely surprised to see there
The requested resource (/example-portlet/MyPortlet/invoke) is not available.
instead of the expected portlet content. (Of course it will differ if your project/webapp context root isn’t example-portlet and the portlet’s name isn’t MyPortlet.)

Google won’t reveal any solution but I’ll will :-). Try to deploy the application first from Eclipse (which you’ve just done) and then in the regular way by exporting it as a WAR file from Eclipse and putting it into <liferay>/deploy/ and waiting for Liferay to pick it up and deploy it to Tomcat. Then compare the two resulting directories from Tomcat’s webapps/ folder. Thus you will learn what you will need to modify. Or simply keep on reading :).

Adjust web.xml

Liferay needs to have a servlet defined for each portlet. The error above (The requested resource (/example-portlet/MyPortlet/invoke) is not available.) indicates that a servlet MyPortlet is missing. So we will add it together with the proper servlet mapping:

web.xml modification:

<servlet>
        <servlet-name>MyPortlet</servlet-name>
        <servlet-class>com.liferay.portal.kernel.servlet.PortletServlet</servlet-class>
        <init-param>
            <param-name>portlet-class</param-name>
            <param-value>eu.ibacz.example.MyPortlet</param-value> <!--replace with your portlet class -->
        </init-param>
        <load-on-startup>0</load-on-startup>
    </servlet>
        ....
    <servlet-mapping>
        <servlet-name>MyPortlet</servlet-name>
        <url-pattern>/MyPortlet/*</url-pattern>
    </servlet-mapping>

Add portlet TLD

We will likely (though I’m not 100% sure about this) need to replicate yet another change done by Liferay and that is adding it’s TLD for portlet 2.0 and a link for it to web.xml. Liferay adds taglibs also for all its other taglibs but I suppose you don’t need them. (I suppose you develop a JSR 286 portlet but you could do the same for a JSR 168 portlet by using its specific uri and tld file.)

1. Copy liferay-portlet.tld to WEB-INF/tld/liferay-portlet.tld. Get it from the Liferay-deployed WAR or find in somewhere under <liferay>.

2. Add a taglib declaration to web.xml:

        <taglib>
            <taglib-uri>http://java.sun.com/portlet_2_0</taglib-uri>
            <taglib-location>/WEB-INF/tld/liferay-portlet.tld</taglib-location>
        </taglib>

Adding Liferay libs

You will likely need to add at least the Liferay library
<liferay>/tomcat-6.0.18/webapps/ROOT/WEB-INF/lib/util-taglib.jar
to your projet’s WEB-INF/lib. If you ommit that you may, when accessing the portlet, get for example one of the following errors:

 javax.portlet.PortletException: javax.servlet.ServletException: java.lang.NoClassDefFoundError: com/liferay/taglib/portlet/DefineObjectsTag
JasperException: Impossible de charger ou d'instancier la classe TagExtraInfo: com.liferay.taglib.portlet.ActionURLTei

That’s all, folks!

That’s all! Your portlet should work now (tough Eclipse may require Tomcat restart for that). Enjoy!

About the portlet project

Selected files of the project’s WAR:

  • WEB-INF/
    • lib/
      • util-taglib.jar
    • tld/
      • liferay-portlet.tld
    • classes/
      • eu.ibacz.example.MyPortlet.class
    • liferay-display.xml
    • liferay-plugin-package.properties
    • liferay-portlet.xml
    • portlet.xml
    • web.xml
  • myPortlet_view.jsp

eu/ibacz/example/MyPortlet.java:

package eu.ibacz.example;

import java.io.IOException;
import javax.portlet.*;

public class MyPortlet extends GenericPortlet {
	
	@Override
	protected void doView(RenderRequest request, RenderResponse response)
			throws PortletException, IOException {		

		PortletRequestDispatcher dispatcher = getPortletConfig().getPortletContext().getRequestDispatcher(
				"/myPortlet_view.jsp");
		if (dispatcher != null) {
			//dispatcher.forward(request, response); // this displays an empty page instead of the JSP?!
			dispatcher.include(request, response);	// this works
		} else {
			throw new IllegalStateException("Failed to get a PortletRequestDispatcher, can't forward to the JSP");
		}
	}
}

liferay-display.xml:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE display PUBLIC "-//Liferay//DTD Display 5.2.0//EN" "http://www.liferay.com/dtd/liferay-display_5_2_0.dtd">
<display>
  <category name="My Experiments">
    <portlet id="MyPortlet">My Test Portlet</portlet>
  </category>
</display>

liferay-plugin-package.properties (I suppose this actually isn’t need or could be empty):

portal.dependency.jars=commons-logging.jartags=portlet

liferay-portlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 5.2.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_5_2_0.dtd">
<liferay-portlet-app>
       
    <portlet>
        <portlet-name>MyPortlet</portlet-name>
        <instanceable>true</instanceable>
    </portlet>
    
    <role-mapper>
        <role-name>administrator</role-name>
        <role-link>Administrator</role-link>
    </role-mapper>
    <role-mapper>
        <role-name>guest</role-name>
        <role-link>Guest</role-link>
    </role-mapper>
    <role-mapper>
        <role-name>power-user</role-name>
        <role-link>Power User</role-link>
    </role-mapper>
    <role-mapper>
        <role-name>user</role-name>
        <role-link>User</role-link>
    </role-mapper>
    
</liferay-portlet-app>

portlet.xml:

<?xml version='1.0' encoding='UTF-8' ?>
<portlet-app xmlns='http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd' version='2.0'>    
    
    <portlet>
        <description></description>
        <portlet-name>MyPortlet</portlet-name>
        <display-name>MyPortlet</display-name>
        <portlet-class>eu.ibacz.example.MyPortlet</portlet-class>        
        <expiration-cache>0</expiration-cache>
        <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>VIEW</portlet-mode>
        </supports>
        <portlet-info>
            <title>MyPortlet</title>
            <short-title>MyPortlet</short-title>
        </portlet-info>
    </portlet>
    
</portlet-app>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>

<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>My Test Portlet Webapp</display-name>
    <description/>
    

    <servlet>
        <servlet-name>JHPokusy</servlet-name>
        <servlet-class>com.liferay.portal.kernel.servlet.PortletServlet</servlet-class>
        <init-param>
            <param-name>portlet-class</param-name>
            <param-value>eu.ibacz.studna.PokusnyPortlet</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
    </servlet>
        
    <servlet-mapping>
        <servlet-name>JHPokusy</servlet-name>
        <url-pattern>/JHPokusy/*</url-pattern>
    </servlet-mapping>
    
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <jsp-config>                
        <taglib>
            <taglib-uri>http://java.sun.com/portlet_2_0</taglib-uri>
            <taglib-location>/WEB-INF/tld/liferay-portlet.tld</taglib-location>
        </taglib>
   </jsp-config>

</web-app>

myPortlet_view.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%>

<h1>MyPortlet is alive!</h1>

Known issues

Omission of .properties during deploy

Sometimes Eclipse omits to copy .properties files to the server. I don’t know whether it’s Eclipse problem or my Eclipse Maven plugin problem. I don’t know why because .settings/org.eclipse.wst.common.component does contain <wb-resource deploy-path=”/WEB-INF/classes” source-path=”/src/main/resources”/>. I’ve open the bug report MECLIPSE-556 regarding this.

Enforcing a particular JDK version

If you use the maven enforcer plugin to enforce a particular version of Java, like this:

<plugin>
		<groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-enforcer-plugin</artifactId>
		<configuration>
				<rules>                                                
						<requireJavaVersion>
								<version>[1.5,1.6)</version>
								<message>...</message>
						</requireJavaVersion>
				</rules>
		</configuration>
		<executions>
				<execution>
						<id>enforce-versions</id>
						<goals>
								<goal>enforce</goal>
						</goals>
				</execution>
		</executions>
</plugin>

then you may have troubles building your Maven project with Eclipse if running Eclipse under another JVM version. For example my default system JVM used also for Eclipse is 1.6 but for a particular project I need 1.5. When you try to build the project, it will fail with

Build errors for jpivot-portlet-liferay-classes; org.apache.maven.lifecycle.LifecycleExecutionException:
 Internal error in the plugin manager executing goal 'org.apache.maven.plugins:maven-enforcer-plugin:1.0-beta-1:enforce':
 Mojo execution failed.

I’ve tried the following to force Maven to use JVM 1.5 for building the project:

  1. Set the JRE System Library in Project – Properties – Java Build Path – Libraries.
  2. Set the Eclipse’s command line option -vm to point to the desired JVM in eclipse.ini:
    -vm /usr/lib/jvm/java-1.5.0-sun
  3. Set JAVA_HOME to point to the desired JVM prior to starting Eclipse:
    bash$ export JAVA_HOME="/usr/lib/jvm/java-1.5.0-sun/jre"bash$ ./eclipse
  4. Setting PATH to point to 1.5 JVM prior to startin Eclipse:
    bash$ export PATH="/usr/lib/jvm/java-1.5.0-sun/bin:$PATH"bash$ ./eclipse

Of those only nr. 4, setting the PATH, had the desired effect of running Eclipse and thus also the Maven build under the required JVM 1.5. The conclusion is that you must run Eclipse using the same JVM you want to use for Maven builds.

There is the bug report MNGECLIPSE-1091 regarding this problem with many votes but no resolution or workaround.

Why not to use m2eclipse

A nice post (6/2009) lists some reasons why not to use m2eclipse for Maven-Eclipse integration:

  1. No real support for separate output folder.
  2. It uses the Maven Embedder, which is not Maven but more of an experiment.
  3. It wants to use the JDK associated with the JRE that launched Eclipse.

According to Brian Fox, the upcoming M2e 0.9.9 should address this issues.

Another reader , Benedikt, recommends solutions:

  1. Of course you can change the output-folder by modifying your pom.xml to have separate output-folders for your class-files.
  2. You can tell the plugin which maven installation it should use and it doesn’t break anything if you do so.
  3. If you don’t use the internal maven builder then maven will use the JRE configured under “Installed JREs”.

So maybe its usable after all? Or you may also give try to Eclipse IAM (former Q4E), the new Maven-Eclipse integration, currently v. 0.1.0. It seems to be yet no as mature as m2eclipse, see a comparison.

Additional notes

You may want to follow the instructions on Liferay site and use Liferay in a development mode by using special portal.properties that prevent some caching etc. (Add -Dexternal-properties=$CATALINA_BASE/webapps/ROOT/WEB-INF/classes/portal-developer.properties to <liferay>/tomcat-5.5.27/bin/catalina.sh.)

You may also want to try to install JBoss Tools into your Eclipse and use its Servers view, which also supports Tomcat and may be better than the standard one.

Another interesting SW – Eclipse Portal Pack for developing JSR168 and JSR286 portlets with Eclipse, currently v2.0M1.

An alternative: the Liferay way

The upcoming book Liferay in Action by R. Sezov describes how to set up portlet development environment for Liferay 6 using either Eclipse or NetBeans in its chapter two. He recommands to create and deploy a portlet using the Ant-based Liferay Plugins SDK and use an IDE only to import and develop the portlet while invoking ant deploy for the deployment. I don’t know wheter that supports hot deployment of only changed files (provided that it matters at all) and of course it has a completely different structer than Maven assumes, complicating if not rendering it impossible to use Maven.

Posted in eclipse, Portlets | Tagged: , , , , | 15 Comments »

Using ScribeFire to publish to JRoller.com

Posted by Jakub Holý on April 20, 2009

To get the Firefox extension ScribeFire (v.3.2.3) to publish to jroller.com you may set you account as follows:

  1. Address of you blog: e.g. http://jroller.com/page/holy
  2. Blog system: MetaWeblog API (though there is also en experimental support of Roller)
    • Of course you must first allow the MetaWeblog API in your blog’s settings
  3. URL of API server: http://www.jroller.com/roller-services/xmlrpc
  4. The username and password you use to log in to JRoller.

I wish this was documented somewhere in the official JRoller documentation (is there any?!) so that I wouldn’t need to aste my time trying to figure it out.

Actually using ScribeFire 3.2.3 may not be such a good idea after all. I’ve just found it has some nasty problems with not escaping and un-escaping < and > (at least inside <pre>) and doesn’t really understand that <p> should be closed when a <h2> is created :-(

Posted in Tools | Comments Off

[DRAFT] Maven “change” project extending a non-maven web project

Posted by Jakub Holý on April 10, 2009

Disclaimer: I’m rather new to Maven and thus my solution is likely not the best one. I welcome any improvement suggestions. 

My current project here at IBA CZ extends a legacy non-maven web project and I had to devise how to organize the extension modules and other new modules depending upon them. The final goal was to create a portlet face for this servlet-only web application that is written in JSP and a strange presentation framework and then create specific portlets for specific needs.

Key factors and motivations:

  1. The source WAR project is not under our control.
  2. The source WAR project has been imported into an external maven repository but only with a minimal Maven POM without any definitions of dependencies etc.
  3. I need to extend this WAR to work in our specific environment (Liferay portal) and to satisfy our specific requirements, which will require some but hopefully not many modifications of its source codes and other resources.
  4. I want to be able to migrate my changes easily to a new version of the source WAR.
  5. I want to use Maven because its our preferred build tool, integrates well with our Continuous Integration (CI) server (Hudson), and – last but not least – handles dependencies so that I can execute svn co http://ibacz.eu/my/project && cd project && mvn package to build a working, deployable package.

My idea was to create only a "change" project, which would only include our changes to the original WAR (additions/deletions/modifications) and merge it with the original project fetched from its maven repository to create a final deployable artifact. Then I’d create other artifacts depending on this.

The source artifacts

As I’ve said, the source application – jpivot.war – is maven agnostic but is imported into an external Maven repository (http://repository.pentaho.org/artifactory/).

Web app artifact: jpivot.war

The web application that we want to customize. It doesn’t include any classes directly – they’re in WEB-INF/lib/jpivot.jar.

Its pom.xml:

<?xml version="1.0" encoding="UTF-8"?><project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.tonbeller</groupId>
<artifactId>jpivot</artifactId>
<packaging>war</packaging>
<version>1.8.0-081008</version>
<description>Auto generated POM</description>
</project>

Classes artifact: jpivot.jar

The same jar as in  jpivot.war/WEB-INF/lib/jpivot.jar but as a standalone maven artifact, also without any dependencies definitions. Its pom.xml:

<?xml version="1.0" encoding="UTF-8"?><project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.tonbeller</groupId>
<artifactId>jpivot</artifactId>
<version>1.8.0-081008</version>
<description>Auto generated POM</description>
</project>

Handling dependencies: jpivot-libs-combined.jar

For compilation and comfortable development of our change and other projects we will certainly need the source project’s dependencies. Unfortunately they’re not listed in its maven POM and it would be a tedious task to do that. Also we do not control the WAR’s POM and it’s likely that some of the dependencies also aren’t mavenized, which gives us a nice recursive trouble.

Therefore I’ll go for the simplest solution and combine all libraries’ classes from jpivot.war/WEB-INF/lib/*.jar excluding jpivot.jar (for it has already its own imported maven artifact) into a single "uberjar" jpivot-libs-combined.jar and deploy it to the company-wide thirdparty maven repository.

An Ant build.xml that merges all JARs except of jpivot.jar from the working directory together:

<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="jpivot-libs-combined" default="combine" basedir=".">
<target name="combine">
<zip destfile="jpivot-libs-combined.jar">
<zipgroupfileset dir="." includes="*.jar" excludes="jpivot.jar"/>
<fileset dir="." excludes="*.jar"/>
</zip>
</target>
</project>

A pom.xml that shall be included with the combined JAR:

<?xml version="1.0" encoding="UTF-8"?><project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.tonbeller</groupId>
<artifactId>jpivot-libs-combined</artifactId>
<version>1.8.0-081008</version>
<dependencies>
<dependency>
<!-- Dummy dependency to show what has this been generated from -->
<groupId>com.tonbeller</groupId>
<artifactId>jpivot</artifactId>
<version>1.8.0-081008</version>
<type>war</type>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
<description>
Dependencies extraced from jpivot.war/WEB-INF/lib (excluding jpivot.jar that already has a maven artefact) and merged into a single .jar.
</description>
</project>

Commands to create the uberjar and install it into a maven repository:

/tmp$ unzip /path/to/jpivot.war WEB-INF/lib
/tmp$ ant -f /path/to/the/build.xml
/tmp$ mvn install:install-file -Dfile=jpivot-libs-combined.jar -DgroupId=com.tonbeller -DartifactId=jpivot-libs-combined -Dversion=1.8.0-081008 -Dpackaging=jar -DgeneratePom=true

Now we should deploy the artifact to the company-wide Maven repository for thirdparty stuff and replace the pom.xml generated by the install command with the one provided above.

Our artifacts

Finally the artifacts that we do develop.

A root POM

I like a parent POM for my artifacts that defines common configuration including properties, repositories and SW versions.


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <parent>
        <artifactId>ibacz-root-pom</artifactId>
        <groupId>eu.ibacz.maven</groupId>
        <version>1.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>eu.ibacz.pbns</groupId>
    <artifactId>pbns-root-pom</artifactId>
    <packaging>pom</packaging>
    <name>PBNS - Root project</name>
    <version>0.0.1-SNAPSHOT</version>
    <description/>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-enforcer-plugin</artifactId>
                <executions>
                    <execution>
                        <id>enforce-versions</id>
                        <goals>
                            <goal>enforce</goal>
                        </goals>
                        <configuration>
                            <rules>
                                <requireMavenVersion>
                                    <version>2.0.9</version>
                                </requireMavenVersion>
                                <requireJavaVersion>
                                    <version>1.5</version>
                                </requireJavaVersion>
                            </rules>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>pentaho</id>
            <name>iba copy of pentaho repo at http://repository.pentaho.org/artifactory</name>
            <url>http://w3.ibacz.cz/nexus/content/repositories/pentaho</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>thirdparty</id>
            <name>Third party repository</name>
            <url>http://w3.ibacz.cz/nexus/content/repositories/thirdparty</url>
        </repository>
    </repositories>

    <properties>
        <wcf.version>1.8.0-070305</wcf.version>
        <jpivot.version>1.8.0-081008</jpivot.version>
        <jpivot.source.version>1.8.0-081008snapshotsrc</jpivot.source.version>
    </properties>

</project>

The "change" artifacts

As mentioned, these reflect the source artifacts and contain changes to them.

jpivot-classes-customized [jar]

Depends on jpivot.jar and contains classes changed from the original jar. They’re combined together for deployment, overriding original classes with the modified ones.

The combination and overriding is done by using the maven-dependency-plugin and its undeploy goal to unpack jpivot.jar to the target compilation prior to running the compile phase, which will thus override original jpivot’s classes with our modified ones.


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <parent>
        <artifactId>pbns-root-pom</artifactId>
        <groupId>eu.ibacz.pbns</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>eu.ibacz.pbns</groupId>
    <artifactId>jpivot-classes-customized</artifactId>
    <name>Customized JPivot Classes</name>
    <version>1.8.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.tonbeller</groupId>
            <artifactId>jpivot</artifactId>
            <version>${jpivot.version}</version>
            <type>jar</type>
            <scope>provided</scope> <!-- don't propagate further as it will be merged into this project's jar -->
        </dependency>
        <dependency>
            <groupId>com.tonbeller</groupId>
            <artifactId>jpivot-libs-combined</artifactId>
            <version>${jpivot.version}</version>
            <scope>compile</scope> <!-- with 'provided' it doesn't get as a transitive dep. of this project's dependants. -->
        </dependency>
    </dependencies>
    <description>modified classes of jpivot.jar</description>
    <build>
        <finalName>jpivot-classes-customized</finalName>
        <plugins>
            <plugin>
                <!--
                    Merge this project's classes with the original jpivot.jar. You can
                    safely ignore reports about duplicates - this happens for classes
                    that we override here.
                -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.1</version>
                <executions>
                    <execution>
                        <id>unpack</id>
                        <phase>process-resources</phase> <!-- To run before compile and this be overriden by compiled classes -->
                        <goals>
                            <goal>unpack</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>com.tonbeller</groupId>
                                    <artifactId>jpivot</artifactId>
                                    <version>${jpivot.version}</version>
                                    <type>jar</type>
                                </artifactItem>
                            </artifactItems>
                            <!--excludes>**/AClassIDontLike.class</excludes> -->
                            <outputDirectory>${project.build.outputDirectory}</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

jpivot-web-customized [war]

Depends on and includes jpivot-classes-customized.jar and depends on jpivot.war, contains changed and new resources and is merged with jpivot.war replacing its jpivot.jar with our jpivot-classes-customized.jar during packaging.

The combination and overriding is done by using overlays of the maven-war-plugin. We also exclude jpivot.jar and replace it with our dependency jpivot-classes-customized.jar (which mixes the original jar with our changes).

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>eu.ibacz.pbns</groupId>
<artifactId>jpivot-web-customized</artifactId>
<packaging>war</packaging>
<version>1.8.0-SNAPSHOT</version>
<name>jpivot-web-customized Maven Webapp</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.tonbeller</groupId>
<artifactId>jpivot</artifactId>
<version>${jpivot.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>eu.ibacz.pbns</groupId>
<artifactId>jpivot-classes-customized</artifactId>
<version>1.8.0-SNAPSHOT</version>
</dependency>
</dependencies>
<description>Our modification of the original jpivot 1.8.0 webapp. This project should only include the classes, JSPs etc. that we do change.
A package is generated by combining this with the original war.</description>
<parent>
<artifactId>pbns-root-pom</artifactId>
<groupId>eu.ibacz.pbns</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<build>
<finalName>jpivot-web-customized</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1-alpha-2</version>
<configuration>
<!--
exclude jpivot.jar, replace it with jpivot-classes-customized.jar
-->
<packagingExcludes>**/jpivot-libs-combined-*.jar</packagingExcludes>
<overlays>
<overlay>
<groupId>com.tonbeller</groupId>
<artifactId>jpivot</artifactId>
<excludes>
<exclude>WEB-INF/lib/jpivot.jar</exclude>
<!-- Mondrian stuff we do not needed. -->
<exclude>WEB-INF/mondrian.properties</exclude>
<exclude>WEB-INF/datasources.xml</exclude>
</excludes>
</overlay>
</overlays>
</configuration>
</plugin>
</plugins>
</build>
</project>

New dependant artifacts

jpivot-portlet-liferay-classes [jar]

Classes necessary to implement a jpivot portlet working under the Liferay portal (5.2.2).

Depends on jpivot-classes-customized.jar for compilation only. It depends also on some Liferay libraries that have been imported into our thirdparty maven repository.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>pbns-root-pom</artifactId>
<groupId>eu.ibacz.pbns</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>eu.ibacz.pbns</groupId>
<artifactId>jpivot-portlet-liferay-classes</artifactId>
<name>JPivot Liferay Portlet Classes</name>
<version>1.8.0-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>eu.ibacz.pbns</groupId>
<artifactId>jpivot-classes-customized</artifactId>
<version>1.8.0-SNAPSHOT</version>
<type>jar</type>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.3</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.portlet</groupId>
<artifactId>portlet-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.liferay</groupId>
<artifactId>portal-kernel</artifactId>
<version>5.2.2</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.liferay</groupId>
<artifactId>portal-service</artifactId>
<version>5.2.2</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.liferay</groupId>
<artifactId>portal-impl</artifactId>
<version>5.2.2</version>
<type>jar</type>
<scope>provided</scope>
</dependency>

<!--
Actually included in jpivot's libs, but made explicit here; Apache
FOP for printing
-->
<dependency>
<groupId>fop</groupId>
<artifactId>fop</artifactId>
<version>0.20.5</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
</dependencies>
<description>Classes for a jpivot portlet ready for Liferay</description>
<build>
<finalName>jpivot-portlet-liferay-classes</finalName>
</build>
</project>

bns-portlets [war]

A set of JPivot portlets, usually consisting of JSPs, CSSs, and JSs.

Extends further jpivot-web-customized and is merged with this WAR during packaging, same as jpivot-web-customized itself is merged with jpivot.war. Only it doesn’t include any changes but only additions.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>eu.ibacz.pbns</groupId>
<artifactId>bns-portlets</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>BNS Portal Portlets</name>

<dependencies>
<dependency>
<groupId>eu.ibacz.pbns</groupId>
<artifactId>jpivot-web-customized</artifactId>
<version>1.8.0-SNAPSHOT</version>
<type>war</type>
</dependency>
<dependency>
<groupId>eu.ibacz.pbns</groupId>
<artifactId>jpivot-portlet-liferay-classes</artifactId>
<version>1.8.0-SNAPSHOT</version>
<type>jar</type>
</dependency>
</dependencies>
<description>
Portlets for BNS Portal panels based on our modified JPivot and jpivot liferay portlet support.
</description>
<parent>
<artifactId>pbns-root-pom</artifactId>
<groupId>eu.ibacz.pbns</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<build>
<finalName>bns-portlets</finalName>
<plugins>
<plugin>
<!-- Merge this WAR with the jpivot war stuff. -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1-alpha-2</version>
<configuration>
<!-- Exclude the transitive jpivot libs dependency - the WAR has it. -->
<packagingExcludes>WEB-INF/lib/jpivot-libs-combined-*.jar</packagingExcludes>
<overlays>
<overlay>
<groupId>eu.ibacz.pbns</groupId>
<artifactId>jpivot-web-customized</artifactId>
</overlay>
</overlays>
</configuration>
</plugin>
</plugins>
</build>
</project>

The build process summarized

  1. jpivot-classes-customized is compiled and merged with the original jpivot.jar into a single archive.
  2. jpivot-web-customized is merged with the original jpivot.war, replacing its WEB-INF/lib/jpivot.war with the already built jpivot-classes-customized.jar. The output is a standalone and deployable standard web application.
  3. jpivot-portlet-liferay-classes is packaged in the standard way and the produced JAR includes only its own classes.
  4. bns-portlets is merged with our already built jpivot-web-customized.war to produce a deployable portlet application.

A development project for IDEs

The "change projects" are not complete on their own and are therefore not very suitable for use for development in an Integrated Development Environment (IDE). If we used an IDE to work on a change web project, it would complain about missing TLDs and other resources from the WAR to be merged in and it wouldn’t be able to deploy it thus loosing the advantage of hot deploy.

The proposed solutions is as follows:

  1. Build the final, complete bns-portlets.war (cd bns-portlets; mvn package).
  2. Import the WAR as a project into an IDE.
    • Eclipse: File – Import – Web – WAR file.
    • NetBeans: Unpack the WAR somewhere then File – New Project – Java Web – Web Application with Existing Sources – go to the unpacked directory.
  3. You should have defined a Liferay runtime environment for the server. If not, you will need to add classpath entries for the Liferay libraries it uses to be able to compile it.
  4. Delete WEB-INF/lib/jpivot-portlet-liferay-classes.jar.
  5. // If WEB-INF/classes hasn’t precedence over lib/ then delete classes that we’ve modified from jpivot-classes-customized.jar.
  6. Add 2 new source folders that are linked to the source folders of the jar projects, namely one to jpivot-classes-customized/src/main/java/ and the other to jpivot-portlet-liferay-classes/src/main/java/ .
    • Eclipse: Project – Properties – Java Build Path – Source – [Link Source]
  7. Develop.
    • Now you can modify the sources if needed and commit their modifications to SVN. Because we actually work on the original projects’ directories, the proper svn metadata will be picked up and the changes will be commited to the respective projects.
      • Unfortunately Eclipse ignores the SVN information of the linked sources. To be able to commit etc. them you’ll need either to use another svn client or have the projects owning the sources open in Eclipse. An alternative is may be to drop the links and define project dependency.
    • If you need to modify another source code or resource file, copy it first to the approrpiate change project from the original jpivot.war or jpivot.jar’s sources.

All changes will be commited to the corresponding SVN projects so this is ok but there is now the risk that a developer will do something in this development project, commit it to SVN, but forgets to build and deploy the corresponding real project’s artifact. Well, this is a risk we have to live with. Such an omission could be detected by our continuous integration server (indicated by a failed build) and perhaps we could add a test which verifies that deployed artifacts aren’t older than the corresponding SVN project.

Known limitations and issues

Next steps

Continuous integration with Hudson.

Conclusion/summary

TODO

Posted in Tools | Comments Off