Category Archives: J2EE

Automated Releases with Maven and Google App Engine

Google App Engine LogoVersature has been building our applications using Java and deploying them on Google App Engine for some time. It has been a very effective solution for us.

Recently, I wanted to improve our release process by making it more formal and automated. After the usual battle with Maven, I managed to win. :)

Our current build automates the following:

  • Remove the trailing -SNAPSHOT from the version number in the POM
  • Tag the release in Subversion
  • Filter the appengine-web.xml to contain the version number
  • Build and deploy to GAE
  • Increment version number in the POM and add the trailing -SNAPSHOT

All of the above is achieved with two Maven commands: release:prepare and release:perform.

Here is the POM with most of the irrelevant parts removed:

<?xml version="1.0" encoding="UTF-8"?>
<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>
    <version>0-9-0-SNAPSHOT</version>
    <packaging>war</packaging>
 
    <name>Versature Dashboard</name>
 
    <scm>
        <connection>scm:svn:https://REMOVED/trunk</connection>
    </scm>
 
    <repositories>
        <repository>
            <id>google-maven-repo</id>
            <name>Maven Google App Engine Repository</name>
            <url>http://maven-gae-plugin.googlecode.com/svn/repository/</url>
        </repository>
        <repository>
            <id>codehaus</id>
            <name>codehaus</name>
            <url>http://repository.codehaus.org/org/codehaus/groovy/</url>
        </repository>
    </repositories>
 
    <pluginRepositories>
        <pluginRepository>
            <id>maven-gae-plugin-repo</id>
            <name>Maven Google App Engine Repository</name>
            <url>http://maven-gae-plugin.googlecode.com/svn/repository/</url>
        </pluginRepository>
    </pluginRepositories>
 
    <dependencies>
        REMOVED
    </dependencies>
 
    <build>
        <testOutputDirectory>target/test-classes</testOutputDirectory>
        <outputDirectory>${webappDirectory}/WEB-INF/classes</outputDirectory>
        <testSourceDirectory>src/test/java</testSourceDirectory>
 
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>exploded</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <webResources>
                      <resource>
                        <directory>src/main/webapp</directory>
                        <filtering>true</filtering>
                        <includes>
                          <include>**/appengine-web.xml</include>
                        </includes>
                      </resource>
                    </webResources>
                    <webappDirectory>${webappDirectory}</webappDirectory>
                </configuration>
            </plugin>
 
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>gwt-maven-plugin</artifactId>
                <version>${gwt-plugin.version}</version>
                <configuration>
                    <logLevel>INFO</logLevel>
                    <port>${gae.port}</port>
                    <server>com.google.appengine.tools.development.gwt.AppEngineLauncher</server>
                    <runTarget>/REMOVED</runTarget>
                    <style>OBF</style>
                </configuration>
                <executions>
                    <execution>
                        <configuration>
                            <extraJvmArgs>-Xmx1024m -Xms512m</extraJvmArgs>
                            <module>com.versature.dashboard.Dashboard</module>
                        </configuration>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
 
            <plugin>
                <groupId>net.kindleit</groupId>
                <artifactId>maven-gae-plugin</artifactId>
                <version>0.9.2</version>
                <configuration>
                    <unpackVersion>${gae.version}</unpackVersion>
                    <serverId>appengine.google.com</serverId>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>net.kindleit</groupId>
                        <artifactId>gae-runtime</artifactId>
                        <version>${gae.version}</version>
                        <type>pom</type>
                    </dependency>
                </dependencies>
            </plugin>
 
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-release-plugin</artifactId>
                <version>2.2.2</version>
                <configuration>
                    <scmCommentPrefix>[RELEASE] </scmCommentPrefix>
                    <goals>gae:deploy</goals>
                </configuration>
            </plugin>
 
            <plugin>
                <groupId>org.codehaus.gmaven</groupId>
                <artifactId>gmaven-plugin</artifactId>
                <version>${gmaven.version}</version>
                <executions>
                    <execution>
                        <id>sources</id>
                        <goals>
                            <goal>generateStubs</goal>
                            <goal>compile</goal>
                            <goal>generateTestStubs</goal>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>properties</id>
                        <phase>validate</phase>
                        <goals>
                            <goal>execute</goal>
                        </goals>
                        <configuration>
                            <source>
                                project.properties["gae-application.version"] = project.version.toLowerCase()
                            </source>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
 
    <!-- Specify hard-coded project properties here -->
    <properties>
        <gmaven.version>1.3</gmaven.version>
        <gae.version>1.6.2.1</gae.version>
        <gae.port>9090</gae.port>
 
        <webappDirectory>${project.build.directory}/${project.build.finalName}</webappDirectory>
    </properties>
 
    <profiles>
        <profile>
            <id>release-build</id>
            <activation>
                <property>
                    <name>performRelease</name>
                    <value>true</value>
                </property>
            </activation>
 
            <properties>
                <gwt.style>OBF</gwt.style>
            </properties>
        </profile>
    </profiles>
    <groupId>com.versature.dashboard</groupId>
    <artifactId>dashboard</artifactId>
</project>

If you run into an error similar to this one:

com.google.appengine.tools.admin.AdminException: Unable to update app: Error posting to URL: https://appengine.google.com/api/appversion/create?app_id=versature-dashboardhr&version=0-8-1-SNAPSHOT&
400 Bad Request
Error when loading application configuration:
Unable to assign value '0-8-1-SNAPSHOT' to attribute 'version':
Value '0-8-1-SNAPSHOT' for version does not match expression '^(?!-)[a-z\d-]{1,100}$'

It is because GAE only accepts lowercase letters, digits and hyphens in version names. (Because those version names become URLs.) I solved this by using a snippet of Groovy (Using the GMaven plugin.) code to automatically create a property with all lowercase letters before filtering it into the appengine-web.xml. So version 0-8-0-SNAPSHOT becomes 0-8-0-snapshot:

1
project.properties["gae-application.version"] = project.version.toLowerCase()

And that’s it, it Just Works™. Gotta love Maven!

DrunkenBlog: Behind the Red Shed, with Jonathan ‘The Wolf’ Rentzsch

In this post on DrunkenBlog, Jonathan Rentzsch gives a terrific interview. Notably, he discusses Apple’s enterprise software development gem, WebObjects, which I’ve always wanted to know more about.

Anyone know if there is a downloadable developer’s version somewhere?

Update: Yes, you can download a 1 month evaluation copy from http://connect.apple.com/.

Trails Makes Tapestry Smell Good

I should now say something witty about Kool-Aid here…

I’m in the process of reading the Trails tutorial by this guy (Trails’ creator) and I am very enthused about the idea: I’ve always felt that code-generation is being overly used in J2EE development. I believe, as do others, that if you can generate it, you should be able to handle it at runtime. (There are exceptions to this rule, of course.) Java has an exceptional reflection API, we should use it. Also, Spring allows much of the work to be done via AOP. But I’m rambling a little here.

The major exception to my dislike of code generation has always been page templates. These are just dumb pieces of text, so you either need to build them by hand or generate them. I’ve never really understood what Tapestry was about until I started reading about Trails and realized that it was allowing us to push object oriented design all the way into the template layer of our applications.

They features of Trails, like allowing us to override the presentation of a specific field without building a template for the entire form and lack of code generation, are really exciting and will provide some great ideas for my current side project.

Those familiar with Plone development will see some similarities here.

A.

Top Ten Technology Predictions

I try hard not to link blog, but this post on Cameron Purdy’s blog, /dev/null, is great. I’ll save you the anxiety:

And a drum roll, please ..

1 – At the 2005 TSS Symposium, Rod Johnson will not be able to resist saying the word “Spring.” Yup, it’s like trying not to think of pink elephants — impossible once you get that in your head. Spring, spring, spring, spring. La tee dah, spring spring spring. Take that, Linda. Spring-diddy-spring spring. Spring.

grin

Maven vs Ant Reloaded

Some time ago, I posted a short entry on Maven vs Ant. Since then, I have continued to use Ant while periodically taking yet another look at Maven.

This week, I came across this post on Otaku talking about keeping your Ant builds maintainable using <import> and <macrodef>. Greater maintainability seems to be one of the reasons Maven was created: allowing you to avoid creating build target spaghetti by describing the project and applying standard goals. These new Ant features can provide this maintainability, while keeping all the flexibility we’ve grown accustomed to.

Cedric’s post then led me to this comment thread on techno.blog(“Dion”) where a good discussion is taking place.

Finally, I can no longer remember how I got there, but dependancy management tools for Ant came up. TSS has an Inversoft‘s Verge project and a post on Mallim Ink pointed me to Jayasoft’s Ivy project. Both projects look very interesting; I think I will try out Ivy shortly.

Update: Colin writes about Ivy and seems very positive.

NailGun Released

Martian Software was talking about NailGun way back in January of 2003 when I emailed them asking about it. I received a message today from Marty Lamb:

If you are receiving this, you have expressed an interest at some point
in a notification when NailGun is available.

Well, it's available.

If it's been so long that you don't remember what it is, NailGun is a
client, server, and protocol for running Java programs within a
persistent JVM, eliminating the JVM startup time.  I appreciate your
patience with the project as I have been swamped with other priorities
for some time now.

Although there are no known issues, there is still some work to be
done.  Most importantly, I need to compile Windows and OSX binaries for
the client.  If you can provide any assistance with this I'd be most
grateful.

More information, a quick start manual, javadocs, and downloads are
available from http://www.martiansoftware.com/nailgun.  There's also
information for joining the NailGun mailing list.  The fact that you are
receiving this message does NOT mean you have been added to the list.

This is a one-time mailing.  If it's unwelcome, you have my sincere
apologies.

- Marty

--
Marty Lamb
Martian Software, Inc.
mlamb at martiansoftware dot com

I’m quite excited about NailGun for use in writing trivial command-line Unix scripts in Java. Going to download it and build a Mac OS X binary while I’m at it too.

Update: Runs nicely on my system, now to explore a bit.

OJUG on August 26th, 2004

I attended this past week’s OJUG meeting in Ottawa, which was very useful. Patrick Linskey, CTO of SolarMetric (developers of Kodo JDO) and co-author of Bitter EJB. He discussed JDO 2.0 JSR 243.

I am very interested in the next version of JDO as I’ve used Hibernate with great success and am looking for something similar, but standards based.

Some implementations of JDO 1.0 and 2.0 are listed at JDO Central. Kodo JDO 3.2 Beta has many of the JDO 2.0 features.

Some of my notes from the presentation:

  1. The big problem in the OR/M world is not the M, but rather the remoteness of data being manipulated
  2. JDO is an Abstract API for Object Persistence
  3. OR/M is an old, well understood problem. It has been solved many times and there is probably little room for real innovation. This is the counter for those that believe that a specification stifles innovation. Isn’t there room for innovation at the API level?
  4. Provides portability between relational and non-relational datastores
  5. Can support J2ME if you provide a Java Collections implementation since J2ME does not provide one
  6. You shouldn’t see the JDO API very often. Most of your data access happens through your object model. You will only see the API for queries & deletions. (Supposing your container is handling transactions.)
  7. Very much tries to do things the Java Way
  8. There is no such thing as POJO persistence
  9. Regarding some Java OR/M implementations that use object proxies: proxies are not the real objects. This will bite you in unusual places. The example is that EmployeeProxy does not extend PersonProxy.
  10. The current problem with bytecode manipulation is that there is no standard to prevent multiple tools from stepping on each other
  11. Gavin King is no longer on the JDO 2.0 committee
  12. No more “autocommit” support!
  13. Uses named queries. You can override a named query with a custom piece of SQL for each targeted database, if necessary
  14. Kodo has a cool workbench
  15. We all should watch TSS
  16. Primary key support: transparent (implementation specific), application identity or simple identity and non-durable
  17. SolarMetric has a disconnected operation and synchronization product
  18. No criteria API, but third party tools can provide this by generating JDOQL. Neither is there find-by-example, but this can also be implemented externally

We all went over to the Mayflower II for beer and conversation after the meeting. A good time was had by all.

Cheers,

A.

Looking for Enterprise Java Developers

We are looking for two Java developers for a project starting shortly. Please do not bother to apply if you do not meet the following criteria:

  • Portfolio of code; or

  • Demonstratable involvement in an Open Source Java project; and

  • Experience with tools such as Ant Subversion and XDoclet; and

  • Experience with UNIX integration and development;

Update: This is for a consulting firm that is waiting to hear whether they have been selected for a medium sized project. They want to have potential team members selected in advance.

Update: This project has not been given funding.

Thanks.

A.

Maven vs Ant

Updated: Since I’ve noticed quite a few Google hits on this entry, I thought I’d post some more information.

I’ve finally figured out what Maven is all about. (No one seems to say it outright.) This enlightenment comes after writing a previous post

The basic difference is fundamental: where Ant allows you to build your own targets to do anything you wish, Maven takes your description of your project (directory structure, etc) and uses standard, pre-written, tasks (goals in Maven-speak) to achieve the usual build needs.

Maven has a bunch of built-in plugins and goals. You can write your own using Jelly.

I’ll be updating this post with some more info shortly. (Ok, so I guess it took a while. My conclusion seems to be staying with Ant, particularly with the addition of new extensions.)

Some relatively clean information is available here

JJar

JJAR promises to be a tool/service that the Java community sorely needs. We are all too familiar with Jar hell.

From the site:

A distributed repository consisting of jars from various projects (which we call packages) as well as version and dependency information about those packages. This logical repository consists of a central main repository, and any number of sub-repositories, each responsible for a given project (or projects.)

A toolset to allow the navigation and fetching from this repository, as well as direct access to repository information, such as project dependencies.

The general idea is that you setup a repository for your jars, including full dependancy information, which then allows you to use the Ant task as noted here

However, I see very little activity on this project. CVS has nothing interesting in over 2 years. Anyone know its status?

I do intend to test it this week, even though it seems inactive. (Probably because of Maven

Tighter Integration of JAXB & JAX-RPC

Working with the XML specifications for Java has always been a pleasure for me. Yes, some criticise them fiercely, however I feel they are mostly adequate for t he task.

I recently encountered a problem with JAXB; the specification requires two behaviours which I find to cause integration hassles:

  1. You must use ObjectFactory to get new beans,
  2. ObjectFactory creates beans with null references

Both issues crop up when using JAXB with a container such as PicoContainer, Spring or anything else that expects to be able to instantiate empty beans without special knowledge.

The second issue becomes a difficulty when using JAXB beans with “dot notation”. For example, you cannot simply create an empty bean and then try and set a property like car.engine.timing since the reference to engine is null until you create an Engine object and assign it. Would it be more appropriate to recursively populate the bean?

George Datuashvili mentioned on the JAXB mailing list:

“In future JAX-RPC 2.0 will be based on JAXB 2.0, and since JAX-RPC already requires EJB bindings, your issue will have to be resolved by JAXB or JAX-RPC working groups.”

That thread also talks about using java.lang.Proxy, which I find very interesting.

JBoss 3.2.2 and the Java Web Services Developer Pack

While attempting to deploy an EJB jar on a fresh installation of JBoss 3.2.2 I received the following error: (Sorry about the long lines.)

java.lang.NoSuchMethodError: org.apache.bcel.generic.InstructionFactory.createNewArray(Lorg/apache/bcel/generic/Type;S)Lorg/apache/bcel/generic/Instruction;

Looked like a version mismatch to me, which would be wierd because JBoss should be using the version of Apache BCEL that shipped with it, no? But what if we have a traitor among us?

I quickly remembered all the cruft that the Java Web Services Developer Pack wanted me to install in the JRE’s endorsed directory, might something there be the culprit?

Indeed, it seems that xsltc.jar contains a version of BCEL. (A rant for another day: even if it makes people do more deployement work, please do not include dependancies in your jars.) I believe that some versions of the Xalan jar also include BCEL, so beware.

Solution: I hope this doesn’t have any side-effects, but you can solve the immediate problem by copying the version of BCEL that ships with JBoss 3.2.2 into your endorsed directory. The BCEL jar is probably located at $JAVA_HOME/server/default/lib/bcel.jar and you want to put it in $JAVA_HOME/jre/lib/endorsed.

How little things can become time-sinks.

Packaging Taglibs

Keeping track of the tld files for a framework or API is an error-prone process, very much so when using a framework like Struts or JSTL that has multiple tag libraries .

A better solution is to package the TLD files along with the rest of the library’s classes and other resources. This is actually mandated by the JSP specification, but who reads specs anyway. IBM developerWorks has a great series on JSP best practices, or which one of the articles explains this technique:

http://www.ibm.com/developerworks/java/library/j-jsp09023/

The short explanation is to put the TLD files in the META-INF directory of the jar file and reference them in your deployement descriptor like so:


<taglib>
<taglib-uri>http://www.newInstance.com/taglibs/site-utils</taglib-uri>
<taglib-location>/WEB-INF/lib/newInstance-taglib_1-1.jar</taglib-location>
</taglib>

Some of the other articles in the series are worthwhile as well.

In addition to this simple use of advanced jar packaging, there is a multitude of other abilities that are completely ignored, I will post some more on this subject this week.

Choosing an Application Framework

Since I do not believe that Struts is the be all and end all of application frameworks, I’ve been looking around at the competition. There are quite a few. Since I believe that this IoC (Inversion of Control) thing is a Good Thing, I’ve restricted my search to those frameworks that manage not only the “actions” of an application but also it’s components.

Currently, there is the following:

I’ve been hearing some Bad Things about WebWork lately, nothing substantiated though.

Another possibility is too do something homegrown on top of PicoContainer.

In then end, I realise that it is a very difficult topic. But I have a plan: I want to put together an evaluation sheet for frameworks. Please email me your thoughts and I will condense them into another posting.