Matt RaibleMatt Raible is a Web Developer and Java Champion. Connect with him on LinkedIn.

The Angular Mini-Book The Angular Mini-Book is a guide to getting started with Angular. You'll learn how to develop a bare-bones application, test it, and deploy it. Then you'll move on to adding Bootstrap, Angular Material, continuous integration, and authentication.

Spring Boot is a popular framework for building REST APIs. You'll learn how to integrate Angular with Spring Boot and use security best practices like HTTPS and a content security policy.

For book updates, follow @angular_book on Twitter.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

How to use GWT 2.0 with Maven and Generate SOYC Reports

One of the most interesting features coming in GWT 2.0 is code splitting and the ability to use GWT.runAsync() to reduce the size of your application's initial download. This week, I learned how to use GWT 2.0 with my GWT 1.6/Maven project. Below are instructions on how to build and use the latest GWT with Maven.

  • Checkout GWT and setup GWT_TOOLS.
  • Set a GWT_VERSION environment variable to 2.0.0-SNAPSHOT (export GWT_VERSION=2.0.0-SNAPSHOT).
  • Build GWT with the ant command.
  • After building completes, install the GWT artifacts into your local Maven repository using the following commands:
    mvn install:install-file -DgroupId=com.google.gwt \
    -DartifactId=gwt-user -Dversion=2.0.0-SNAPSHOT \
    -Dpackaging=jar -Dfile=build/lib/gwt-user.jar
    
    mvn install:install-file -DgroupId=com.google.gwt \
    -DartifactId=gwt-servlet -Dversion=2.0.0-SNAPSHOT \
    -Dpackaging=jar -Dfile=build/lib/gwt-servlet.jar
    
    mvn install:install-file -DgroupId=com.google.gwt \
    -DartifactId=gwt-dev -Dversion=2.0.0-SNAPSHOT \
    -Dclassifier=mac -Dpackaging=jar -Dfile=build/lib/gwt-dev-mac.jar
    
    mkdir temp
    tar -zxf build/dist/gwt-mac-2.0.0-SNAPSHOT.tar.gz -C temp
    cd temp/gwt-mac-2.0.0-SNAPSHOT
    zip -0 gwt-mac-2.0.0-SNAPSHOT.zip lib*.jnilib
    cd ../..
    
    mvn install:install-file -DgroupId=com.google.gwt \
    -DartifactId=gwt-dev -Dversion=2.0.0-SNAPSHOT \
    -Dclassifier=mac-libs -Dpackaging=zip \
    -Dfile=temp/gwt-mac-2.0.0-SNAPSHOT/gwt-mac-2.0.0-SNAPSHOT.zip
    
    Thanks to Jason for his help with this script.
  • Modify the pom.xml of your GWT project to use the the gwt-maven-plugin from Codehaus. Of course, you'll need to modify the <runTarget> to fit your project.
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>gwt-maven-plugin</artifactId>
        <version>1.1</version>
        <configuration>
            <runTarget>org.appfuse.gwt.mvc.${entry.point}/${entry.point}.html</runTarget>
        </configuration>
        <executions>
            <execution>
                <goals>
                    <goal>compile</goal>
                    <goal>test</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    
  • Modify your dependencies to match the ones below. With the Codehaus plugin, dependencies are much more concise.
    <dependency>
        <groupId>com.google.gwt</groupId>
        <artifactId>gwt-servlet</artifactId>
        <version>${gwt.version}</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>com.google.gwt</groupId>
        <artifactId>gwt-user</artifactId>
        <version>${gwt.version}</version>
        <scope>provided</scope>
    </dependency>
    
  • Add <gwt.version>2.0.0-SNAPSHOT</gwt.version> to the properties section of your pom.xml.
  • At this point, you should be able to compile your project with mvn gwt:compile and run it in hosted mode using mvn gwt:run.

Generate SOYC Reports
In Google's code splitting documentation, it mentions The Story of Your Compile (SOYC). From the documentation:

To obtain a SOYC report for your application, there are two steps necessary. First, add -soyc to the compilation options that are passed to the GWT compiler. This will cause the compiler to emit raw information about the compile to XML files in an -aux directory beside the rest of the compiled output. In that directory, you will see an XML file for each permutation and a manifest.xml file that describes the contents of all the others.

The second step is to convert that raw information into viewable HTML. This is done with the SoycDashboard tool.

The first step is not currently possible with the gwt-maven-plugin, so I created a patch for it.

If you patch the gwt-maven-plugin and install it locally, make sure and change the version in your pom.xml to 1.2-SNAPSHOT.

To use the SoycDashboard tool, you'll need to install the gwt-soyc-vis.jar.

mvn install:install-file -DgroupId=com.google.gwt \
-DartifactId=gwt-soyc-vis -Dversion=2.0.0-SNAPSHOT \
-Dpackaging=jar -Dfile=build/lib/gwt-soyc-vis.jar

Now you can generate SOYC reports with mvn gwt:compile -Dgwt.compiler.soyc=true. You can also add <soyc>true</soyc> to the <configuration> section of the gwt-maven-plugin.

The second step (converting the raw information into viewable HTML) is possible using java from the command-line, or by using the exec-maven-plugin. Here's the (lengthy) command-line version:

java -Xmx1024m -cp /Users/mraible/.m2/repository/com/google/gwt/gwt-soyc/2.0.0-SNAPSHOT/gwt-soyc-2.0.0-SNAPSHOT.jar:/Users/mraible/.m2/repository/com/google/gwt/gwt-dev/2.0.0-SNAPSHOT/gwt-dev-2.0.0-SNAPSHOT-mac.jar com.google.gwt.soyc.SoycDashboard -resources ~/.m2/repository/com/google/gwt/gwt-soyc/2.0.0-SNAPSHOT/gwt-soyc-2.0.0-SNAPSHOT.jar -out target/soyc-report target/extra/org.appfuse.gwt.mvc.MVC/soycReport/stories0.xml.gz target/extra/org.appfuse.gwt.mvc.MVC/soycReport/dependencies0.xml.gz target/extra/org.appfuse.gwt.mvc.MVC/soycReport/splitPoints0.xml.gz

In this example, I'm using the files from stories0.xml.gz, dependencies0.xml.gz, splitPoints0.xml.gz. In the soycReport output directory, there's 5 of each these files and I'm not sure what the difference between reports is. Hopefully someone on the GWT team can elaborate. The exec-maven-plugin version is as follows:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.1</version>
    <configuration>
        <executable>java</executable>
        <arguments>
            <argument>-cp</argument>
            <argument>
                ${settings.localRepository}/com/google/gwt/gwt-soyc/2.0.0-SNAPSHOT/gwt-soyc-2.0.0-SNAPSHOT.jar:${settings.localRepository}/com/google/gwt/gwt-dev/2.0.0-SNAPSHOT/gwt-dev-2.0.0-SNAPSHOT-${platform}.jar
            </argument>
            <argument>com.google.gwt.soyc.SoycDashboard</argument>
            <argument>-out</argument>
            <argument>target/soyc-report</argument>
            <argument>-resources</argument>
            <argument>
                ${settings.localRepository}/com/google/gwt/gwt-soyc/2.0.0-SNAPSHOT/gwt-soyc-2.0.0-SNAPSHOT.jar
            </argument>
            <argument>${project.build.directory}/extra/org.appfuse.gwt.mvc.MVC/soycReport/stories0.xml.gz</argument>
            <argument>${project.build.directory}/extra/org.appfuse.gwt.mvc.MVC/soycReport/dependencies0.xml.gz</argument>
            <argument>${project.build.directory}/extra/org.appfuse.gwt.mvc.MVC/soycReport/splitPoints0.xml.gz</argument>
        </arguments>
    </configuration>
</plugin>

After configuring this plugin in your project, you should be able to run mvn gwt:compile exec:exec and open the generated report (at target/soyc-report/SoycDashboard-index.html). Currently, there doesn't seem to be much documentation on SOYC. Fred Sauer's recent presentation talks a bit about SOYC and GWT.runAsync(), but that's about it.

To figure out how to use GWT 2.0 with Maven, I used my GWT MVC Example project. The first SOYC report I generated said the initial download was 108,967 KB. To integrate GWT.runAsync(), I modified all the project's controllers so their handleEvent() methods changed from this:

public void handleEvent(AppEvent event) {
    onViewHome(event);
}

To this:

public void handleEvent(final AppEvent event) {
    GWT.runAsync(new RunAsyncCallback() {
        public void onFailure(Throwable throwable) {
            Window.alert(throwable.getMessage());
        }

        public void onSuccess() {
            onViewHome(event);
        }
    });
}

When I generated a new SOYC report, the initial download size was reduced to 56,718 KB. Furthermore, I was able to see that my "Leftovers code" consisted of 63,175 KB. I'm sure there's better ways to split my project using GWT.runAsync(), but I'm happy to see I was able to reduce the initial download by 50%.

If you'd like to try GWT 2.0, you can can download my gwt-mvc example project. To build/run this project, you'll need to 1) build and install GWT, 2) patch gwt-maven-plugin and 3) run mvn gwt:compile exec:exec to generate the SOYC report. In an ideal world, the gwt-maven-plugin can be enhanced to generate the SOYC report (rather than using the exec-maven-plugin). In the meantime, I think it's pretty cool that you can try out GWT 2.0 features while they're still being developed.

Posted in Java at Jun 25 2009, 11:45:04 PM MDT 11 Comments

Optimizing a GWT Application with Multiple EntryPoints

Building a GWT application is an easy way for Java Developers to write Ajax applications. However, it can be difficult to release a GWT application to production before it's finished. One of the most important things I've learned in Software Development is to get a new application into production as soon as possible. Not only does getting it from dev → qa → prod verify your process works, it also can do a lot to test the viability of the new application.

One of the biggest issues with GWT applications is size. The project I'm working on compiles Java to JavaScript and creates ~570K *.cache.html files (one for each modern browser). These files end up being around 180K gzipped. I believe this is an OK size for an entire application. However, if you're going to release early, release often with GWT, chances are you'll just want to release one feature at a time.

When the first feature was completed on my project, the *.cache.html files were around 300K. Rather than using branches to release to QA and UAT, bug fixes and new features were developed on trunk. Unfortunately, the QA and UAT process took several weeks longer than expected so by the time the feature was ready to release, the *.cache.html files had grown to around ~570K. The reason the file had grown so much was because it included all of the other features.

Earlier this week, while running to a dentist appointment, I thought of a solution to this problem. The basic idea was to optimize the compilation process so only the to-be-released feature was included. Even better, the solution didn't require more modularization. The results:

Before: *.cache.html -> 569K, gzipped 175K
After: *.cache.html -> 314K, gzipped 100K

According to my calculations, that's a 56% reduction in size. How did I do it?

  1. Created a new FeatureName.java EntryPoint with only the to-be-released features imported.
  2. Created a new FeatureName.gwt.xml that references the new EntryPoint.
  3. Copied old (kitchen-sink) EntryPoint.html to FeatureName.html and changed the reference to the nocache.js file.
  4. Created a Maven profile that allows using -PFeatureName to build a FeatureName-only module.

One downside to doing things this way is it's possible to create a WAR that has the same name and different features. Surely the Maven Overlords would frown upon this. Since this is just a temporary solution to release features incrementally, I'm not too worried about it. A possible workaround is to create different WAR names when a feature's profile is activated. I believe the true "Maven way" would be to make the "kitchen sink" application into a JAR and have several WAR modules with the different EntryPoints. Seems a bit complicated to me.

Other than this Maven publishing issue, the only other issue I can foresee is keeping the two EntryPoints and HTML files in synch. Then again, the separate files allow a feature to be customized for the release and can be deleted when its no longer needed.

What do you think? Do you know of a better way to compile a GWT application so it only contains certain features?

Posted in Java at Mar 25 2009, 04:00:37 PM MDT 12 Comments

Modularizing GWT Applications with GWT-Maven

Last week, I spent some time modularizing the GWT application I'm working on. By modularizing, I mean splitting the code from one GWT module into a "core" and "webapp" module. The reason for doing this was so the "core" module could be used by another GWT application. Creating GWT Modules is fairly straightforward, but it wasn't as intuitive as expected when using the gwt-maven-plugin.

The hardest part of moving the code was figuring out how to run tests in the new "core" module. After getting it all working, it seems easy enough. Hopefully this post will make it easy for others. Here's the steps I'd recommend:

  1. Convert your GWT project into a multi-module project where you have a top-level pom.xml and two sub-modules (e.g. gwt-core and gwt-webapp).
  2. Do the normal single-to-multi-project Maven stuff like declaring the <parent> element in the modules and moving plugins/dependencies to the top-level pom.xml.
  3. Refactor your gwt-webapp project to push down all shared classes (and their tests) to gwt-core.
  4. In the gwt-core project, include *.xml and *.java in your JAR so GWT can extract/compile the source code when building gwt-webapp.
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.java</include>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
    
  5. In gwt-core/src/main/java, create a Core.gwt.xml that references the modules you'd like to use in all your applications. For example:
    <module>
        <inherits name="com.google.gwt.user.User"/>
        <inherits name="com.google.gwt.i18n.I18N"/>
        <inherits name="com.extjs.gxt.ui.GXT"/>
        <inherits name="pl.rmalinowski.gwt2swf.GWT2SWF"/>
    </module>
    
  6. Now the tricky part begins, mostly because of how the gwt-maven plugin currently works. In src/test/java, create a NoOpEntryPoint.gwt.xml that inherits your Core module and defines an EntryPoint.
    <module>
        <inherits name="com.company.app.Core"/>
        <entry-point class="com.company.app.NoOpEntryPoint"/>
    </module>
    
  7. Create a NoOpEntryPoint.java class in the same directory as NoOpEntryPoint.gwt.xml.
    public class NoOpEntryPoint implements EntryPoint {
        
        public void onModuleLoad() {
            // do nothing
        }
    }
    
  8. In any class that extends GWTTestCase (I usually create a parent class for all tests), reference the NoOpEntryPoint in the getModuleName() method.
        @Override
        public String getModuleName() {
            return "com.company.app.NoOpEntryPoint";
        }
    
  9. Lastly, in the gwt-maven plugin's configuration (in gwt-core/pom.xml), reference the NoOpEntryPoint in <compileTargets>, a non-existent file in <runTarget> and only the "test" goal in the executions.
    <plugin>
        <groupId>com.totsp.gwt</groupId>
        <artifactId>maven-googlewebtoolkit2-plugin</artifactId>
        <version>2.0-beta26</version>
        <configuration>
            <compileTargets>
                <value>com.company.app.NoOpEntryPoint</value>
            </compileTargets>
            <runTarget>com.company.app.NoOpEntryPoint/doesntexist.html</runTarget>
            <logLevel>INFO</logLevel>
            <style>OBF</style>
            <noServer>false</noServer>
            <extraJvmArgs>-Xmx512m</extraJvmArgs>
            <gwtVersion>${gwtVersion}</gwtVersion>
            <testFilter>*GwtTestSuite.java</testFilter>
            <testSkip>${skipTests}</testSkip>
        </configuration>
        <executions>
            <execution>
                <goals>
                    <goal>test</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    

The results of modularizing your application are beneficial (shared code) and detrimental (you have to mvn install gwt-core whenever you make changes in shared classes). If you know of a way to configure the gwt-maven plugin to read sources from both gwt-core and gwt-webapp in hosted mode, I'd love to hear about it.

Posted in Java at Mar 23 2009, 10:36:08 AM MDT 11 Comments

Nexus is a kick-ass Repository Manager

I started my current gig at the end of last year. I've been enjoying the work and especially the project infrastructure we've been using. We're using the usual suspects: JIRA, Confluence, Hudson and Subversion. We're also using a couple new ones, namely sventon and Nexus. For building, we're using Maven and Ivy (as a Grails plugin).

Nexus I'm writing this post to talk about Nexus and how much I've enjoyed using it. I like Nexus for two reasons: it's aesthetically pleasing and it's well-documented. Another reason I really dig it is because I haven't had to touch it since I first configured it. Software that just keeps on humming is always fun to work with.

Initially, I remember having some issues setting up repositories. I also remember solving them after learning how groups work.

In addition to on-the-job, I've started to use Nexus more and more in my open source life. With the help of Jason van Zyl, I recently moved AppFuse's repository to Sonatype's oss.sonatype.org. I also noticed there's a Nexus instance for Apache projects. If that's not enough, you can get Nexus Pro free if you're an open source project.

Personally, the open source version of Nexus seems good enough for me. While the Staging Suite looks nice, I think it's possible to do a lot of similar things with good communication. After all, it's not going to free you from having to wrestle with the maven-release-plugin.

Next week, I'm helping to polish and document our entire release process (from dev → qa → production). If you have any advice on how to best perform releases with Maven, Grails and/or Nexus, I'd love to hear about it. My goal is extreme efficiency so releases can be done very quickly and with minimal effort.

Posted in Java at Mar 05 2009, 11:59:02 PM MST 13 Comments

GWTTestSuite makes builds faster, but requires JUnit 4.1

Earlier this week, I spent some time implementing GWTTestSuite to speed up my project's build process. In Hudson, the project was taking around 15 minutes to build, locally it was only taking 5 minutes for mvn test. In IDEA, I could run all the tests in under a minute. While 15 minutes isn't a long time for a build to execute, a co-worker expressed some concern:

Does Maven have to run GWT test and individual Java processes? (See target/gwtTest/*.sh) This arrangement and the overhead of JVM launches is another reason why builds take so long. As we add more GWT tests we are going to test that LinkedIn record for the slowest build ever.

After this comment, I started looking into GWTTestSuite using Olivier Modica's blog entry as a guide. It was very easy to get things working in IDEA. However, when I'd run mvn test, I'd get the following error:

Error: java.lang.ClassCastException

No line numbers. No class information. Zilch. After comparing my project's pom.xml with the one from the default gwt-maven archetype, I noticed the default used JUnit 4.1, while I had the latest-and-supposedly-greatest JUnit 4.4. Reverting to JUnit 4.1 fixed the problem. Now Hudson takes 3:15 to execute the build instead of 15 minutes.

The reason for this blog post is this doesn't seem to be documented anywhere. Hopefully other developers will find this entry when googling for this issue.

Related to making GWT faster, I also added the following line to my Application.gwt.xml file:

<set-property name="user.agent" value="safari" />

This dropped the gwt:compile time from 1 minute to 25 seconds. As explained in the documentation, you can use the "user.agent" setting to only generate one JS file for your app instead of 4. The strange thing about adding this setting was I pretty much forgot about it since everything seemed to work fine on both Safari and Firefox. When I started testing things in IE6, I started seeing a lot of JavaScript errors. After debugging for an hour or so, I realized this setting was there, removed it, and everything started working great in all browsers.

Now if I could just figure out how to use safari-only for development, but remove the line when building the WAR. Suggestions welcome.

Posted in Java at Feb 27 2009, 11:58:12 AM MST 6 Comments

Enhancing your GWT Application with the UrlRewriteFilter

Last week, I spent some time trying to change the location of my cache/nocache HTML files in my GWT project. I started the project with the gwt-maven-plugin's archetype. The message I posted to the gwt-maven Google Group is below.

Rather than having my application's HTML file in src/main/java/com/mycompany/Application.html, I'd like to move it to src/main/webapp/index.html. I tried copying the HTML and adding the following to my index.html, but no dice:

<meta name="gwt:module" content="com.mycompany.Application"/>

Is this possible with the gwt-maven-plugin? I'd like to have my main HTML and CSS at the root of my application.

The good news is I figured out a solution using the UrlRewriteFilter that 1) allows hosted mode to work as usual and 2) allows your app to be served up from the root URL (/ instead of /com.company.Module/Application.html). Here's the urlrewrite.xml that makes it all possible.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCENGINE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN"
        "http://tuckey.org/res/dtds/urlrewrite3.0.dtd">

<urlrewrite>
    <rule>
        <from>^/$</from>
        <to type="forward" last="true">/com.mycompany.app.Application/Application.html</to>
    </rule>
    <rule>
        <from>/index.html</from>
        <to type="forward" last="true">/com.mycompany.app.Application/Application.html</to>
    </rule>
    <-- This last rule is necessary for JS and CSS files -->
    <rule>
        <from>^/(.*)\.(.*)$</from>
        <to type="forward">/com.mycompany.app.Application/$1.$2</to>
    </rule>
</urlrewrite>

If you're using the gwt-maven plugin, this file goes in src/main/webapp/WEB-INF. In addition, you'll need to add the following to your web.xml.

    <filter>
        <filter-name>rewriteFilter</filter-name>
        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>rewriteFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Finally, add the UrlRewriteFilter dependency in your pom.xml:

    <dependency>
        <groupId>org.tuckey</groupId>
        <artifactId>urlrewritefilter</artifactId>
        <version>3.1.0</version>
    </dependency>

Please let me know if you have any questions.

Update: Jeff posted an alternative configuration that allows you to eliminate the last rule in urlrewrite.xml, as well as use the beloved mvn jetty:run command. To use cleaner WAR packaging and the Jetty plugin, add the following to your pom.xml:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
        <webappDirectory>
            ${project.build.directory}/${project.build.finalName}/com.mycompany.app.Application
        </webappDirectory>
    </configuration>
</plugin>
<plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>maven-jetty-plugin</artifactId>
    <version>6.1.14</version>
    <configuration>
        <webAppConfig>
            <contextPath>/</contextPath>
            <baseResource implementation="org.mortbay.resource.ResourceCollection">
                <resourcesAsCSV>
                    ${basedir}/src/main/webapp,
                    ${project.build.directory}/${project.build.finalName}/com.mycompany.app.Application
                </resourcesAsCSV>
            </baseResource>
        </webAppConfig>
        <scanIntervalSeconds>3</scanIntervalSeconds>
        <scanTargets>
            <scanTarget>${basedir}/src/main/resources</scanTarget>
            <scanTarget>${basedir}/src/main/webapp/WEB-INF</scanTarget>
            <scanTarget>
                ${project.build.directory}/${project.build.finalName}/com.mycompany.app.Application
            </scanTarget>
        </scanTargets>
    </configuration>
</plugin>

Then you can trim your urlrewrite.xml down to:

<urlrewrite>
    <rule>
        <from>^/$</from>
        <to type="forward" last="true">/Application.html</to>
    </rule>
    <rule>
        <from>/index.html</from>
        <to type="forward" last="true">/Application.html</to>
    </rule>
</urlrewrite>

Of course, you could also change the welcome-file in your web.xml or use index.html and the <meta http-equiv="REFRESH"> option. Personally, I have so much affection for the UrlRewriteFilter that I like having it in my project. I'm sure I'll need it someday.

Thanks Jeff!

Posted in Java at Feb 23 2009, 05:02:29 PM MST 13 Comments

AppFuse Light converted to Maven modules, upgraded to Tapestry 5 and Stripes 1.5

This past week, I stayed up a couple of late nights to do some of the AppFuse Light work I wrote about in October. I converted all web frameworks to Maven modules, as well as made them inherit from the appfuse-web project. Below is what the new module structure looks like:

New AppFuse Light Modules

At this point, the project is ready to import into AppFuse's SVN project. Here's a list of other changes I made:

  • Modules now depend on AppFuse's backend and allow you to use Hibernate, JPA or iBATIS as the persistence framework. Implementations for Spring JDBC, OJB and JDO have been removed.
  • Upgraded to JWebUnit 2.1, which now uses HtmlUnit under the hood and has much better JavaScript support. It also has Selenium support, but I've yet to try it.
  • Ajaxified Body integrated into all frameworks. You can easily turn it off by modifying the global.js file.
  • Prototype and Scriptaculous loaded from Google's Ajax Libraries CDN.
  • Upgraded to Tapestry 5. Mad props to Serge Eby and his tapestry5-appfuse project for showing me how to do this. Serge became a committer on AppFuse recently, so hopefully we'll continue to see great things from the Tapestry 5 support. I really like the clean URLs and minimum configuration required in Tapestry 5. It's testing framework is nice too, but I believe it could be improved.
  • Upgraded to Stripes 1.5. This was easy and painless. I'm definitely a fan of Stripes and look forward to reading the Stripes book on my bookshelf.
  • Dropped support for: Struts 1.x, WebWork, Spring MVC + Velocity.

If you want to try any of these applications, you can create archetypes using the following commands:

svn co https://appfuse-light.dev.java.net/svn/appfuse-light/trunk appfuse-light
cd appfuse-light/preferred-web-framework
mvn archetype:create-from-project
cd target/generated-sources/archetype
mvn install
cd ~/dev
mvn archetype:generate # The new archetype should show up as an option

Next steps include figuring out a way to flatten the inherited dependencies and plugins so archetype:create-from-project can create truly standalone projects. Please let me know if you have any questions.

Posted in Java at Dec 20 2008, 06:42:03 PM MST 9 Comments

Free Maven Training in New Orleans on Election Day

Last week, I attended a talk by Jason van Zyl on Comprehensive Project Intelligence. This talk contained a good overview of some Maven goodies that Jason's company has been working on - namely better repository management (Nexus), better Eclipse support (m2eclipse) and improving an awesome CI server (we use Hudson heavily at LinkedIn).

Colorful New Orleans
Photo by Toshio

It looks like Jason is going to be doing a similar session in a full-day format at ApacheCon next week. The good news is it's free, the bad news is you have to be in New Orleans. Hopefully Jason and team will post their slides from this event and we can all learn how to use Maven more effectively.

In other Maven-related news, I hope to complete AppFuse 2.1 around the same time as Spring 3.0 (early next year). As part of that release, I hope to start using Nexus for AppFuse's repository as well as restructure its archetypes to allow using m2eclipse (with WTP) more effectively.

Posted in Java at Oct 29 2008, 09:55:45 PM MDT Add a Comment

AppFuse Light » AppFuse, Maven Archetypes and Shared Web Assets

Last night, I stayed up into the wee hours of the morning working on something I've been wanting to do for a long time. It wasn't until I was trouncing around the woods in Montana that I realized how easy it would be. The something I've wanted to do was to modify AppFuse Light to use AppFuse's core modules (service and dao). It only took me a few hours to make it happen and it inspired additional ideas.

I believe the major mistake we made in AppFuse 2.x was making it easy for user's to upgrade their applications. We currently use the maven-war-plugin and our own maven-warpath-plugin to make it possible to include AppFuse classes and assets in your project. You can easily start a new project w/o having a whole bunch of files in your project. The problem is, you can't easily use "mvn jetty:run" to work on your project. Of course, you can use "mvn appfuse:full-source" to solve this, but I'm starting to think more and more that "full-source" should be the default. This is what we did in 1.x and it seems to be the more natural pattern for folks using AppFuse.

That hard part about moving to "full-source" by default is coming up with a way to share common assets and classes among wars and war projects. Sure, I can copy all the shared images, css and js into each project - but that could become a maintenance nightmare. Subversion 1.5 with relative svn:externals might solve this, but it still seems kinda hacky. I don't want to use the maven-war-plugin because the overlay is kinda hokey and I think it's easier for users to understand when everything is in their project. AppFuse's current directory structure in SVN looks as follows. I've added indicators of what is in each directory.

AppFuse Web SVN

Rather than using AppFuse's current (manual) archetype-creation process, I'd like to move to a more automated creation process using the maven-archetype-plugin's create-from-project feature. I'd like to figure out a way where I can have the source code and assets from web/common included in each of the other web/* projects (both when using "jetty:run" and "archetype:create-from-project"). One idea I thought of is to make Jetty/Maven aware of multiple src/war directories for "jetty:run" and "package" and then somehow hook into the archetype plugin at creation time to pull in the shared resources. I don't know if something like this is possible. If you know of a good solution to this shared web assets issue, I'd love to hear about it.

Back to AppFuse Light. If I can figure out how to solve shared resources in web modules, I can use this in AppFuse Light to move to a modular SVN structure vs. its current "use Ant to create different combinations" setup. If a modular structure (like appfuse/web/*) is possible for AppFuse Light, I believe it makes sense to move its source into AppFuse's SVN repository. Below is how the directory structure might look after this move.

AppFuse Light » AppFuse

With this addition and "archetype:create-from-project", we should be able to create all the basic and light archetypes automatically. We'll probably still need a manual archetype-creation process for modular archetypes, but I'm OK with that.

The last thing I'm struggling with is figuring out the best way to create archetypes for something like AppFuse. In the past, we've used dependencies to allow users to inherit dependencies and their versions. This works, but it results in a lot of duplicate XML (in projects and archetypes) for developers. Last night, I tried using a parent project instead of dependencies and it seems to work much better. Not only do you inherit dependencies, but you also inherit plugins, profiles and properties. If you inherit, you can override, which is slick.

If you're an AppFuse user, how would you feel about having an AppFuse module as your project's parent? Would you prefer that, dependencies on AppFuse or full-source with no dependencies on AppFuse? Regardless of parent vs. dependencies, I think running "appfuse:full-source" should allow you to de-couple your project from AppFuse.

Posted in Java at Oct 29 2008, 02:18:59 AM MDT 7 Comments

Colorado Software Summit 2008 Wrapup

Snowman in Keystone Last week, I attended the Colorado Software Summit in Keystone and had a great time. Not only was the weather beautiful and the food delicious, the sessions I attended were awesome. If you ever get a chance to go to this conference, I highly recommend it. It's like being on vacation and learning with a bunch of old friends.

Yan Pujante also attended this conference and documents his experience, photography and presentations in Colorado Software Summit 2008.

Below is a list of my entries for all the sessions I attended.

For next year, I think the conference should shorten its sessions (from 90 to 60 minutes), invite more speakers and cut the price in half (to $999 per person). How do you think the Software Summit could be improved?

Posted in Java at Oct 28 2008, 11:03:23 PM MDT 2 Comments