Thursday, February 23, 2012

Building and Deploying the Seam 3 Booking example from Eclipse 3.7 to JBoss AS 7.1




This blog entry is about how to make the JBoss Seam 3 Booking Example to build and deploy under Eclipse 3.7 SR2 to JBoss AS 7.1 (under Windows).

There are two maven plugins which could help: The Maven Eclipse Plugin and the APT Plugin from Codehouse.

Maven 3.0.4 and Dependency versions

I got missing version information errors when upgraded to Maven 3.0.4, so I added the version information in every missing place (I have also removed the non JBoss 7 related profiles and testing related   goals) . The modified project pom somehow caused the Eclipse JDT-APT plugin to stop working, so I have added a new builder for running annotation processors (see later). This is how the modified pom looks like:
<?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">
    <version>3.0.1</version>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.jboss.seam.examples.seam-booking</groupId>
    <artifactId>seam-booking</artifactId>
    <packaging>war</packaging>
    <name>Seam Booking Example</name>
    <description>The Seam booking example using the simplified Java EE 6 programming model and packaging structure (i.e., web archive)</description>
    <url>http://seamframework.org/Seam3</url>
    <properties>
        <jpamodelgen.version>1.1.1.Final</jpamodelgen.version>
    </properties>
    <dependencies>
        <!-- Annotation processor for generating typed loggers -->
        <dependency>
            <groupId>org.jboss.solder</groupId>
            <artifactId>solder-tooling</artifactId>
            <scope>compile</scope>
            <version>3.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.solder</groupId>
            <artifactId>solder-impl</artifactId>
            <scope>runtime</scope>
            <version>3.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-jpamodelgen</artifactId>
            <version>${jpamodelgen.version}</version>
            <scope>provided</scope>
            <!-- Excluded Hibernate-provided JPA API because it's provided by the Java EE 6 dependencies -->
            <exclusions>
                <exclusion>
                    <groupId>org.hibernate.javax.persistence</groupId>
                    <artifactId>hibernate-jpa-2.0-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.jboss.seam.faces</groupId>
            <artifactId>seam-faces-api</artifactId>
            <version>3.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.seam.faces</groupId>
            <artifactId>seam-faces</artifactId>
            <version>3.1.0.Final</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.seam.international</groupId>
            <artifactId>seam-international</artifactId>
            <version>3.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.seam.security</groupId>
            <artifactId>seam-security</artifactId>
            <scope>compile</scope>
            <version>3.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.seam.transaction</groupId>
            <artifactId>seam-transaction</artifactId>
            <scope>compile</scope>
            <version>3.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.picketlink.idm</groupId>
            <artifactId>picketlink-idm-core</artifactId>
            <version>1.3.0.GA</version>
        </dependency>
        <dependency>
            <groupId>com.ocpsoft</groupId>
            <artifactId>ocpsoft-pretty-time</artifactId>
            <version>1.0.7</version>
        </dependency>
        <dependency>
            <groupId>com.ocpsoft</groupId>
            <artifactId>prettyfaces-jsf2</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-digester3</artifactId>
            <version>3.2</version>
            <classifier>with-deps</classifier>
        </dependency>
        <!-- Bean Validation Implementation; provides portable constraints @NotEmpty, @Email and @Url -->
        <!-- Hibernate Validator is the only JSR-303 implementation at the moment, so we can assume it's provided -->
        <!-- TODO Move Hibernate Validator to app server specific sections -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.2.0.Final</version>
        </dependency>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.1</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.spec</groupId>
            <artifactId>jboss-javaee-6.0</artifactId>
            <type>pom</type>
            <scope>provided</scope>
            <version>1.0.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.shrinkwrap.resolver</groupId>
            <artifactId>shrinkwrap-resolver-impl-maven</artifactId>
            <scope>runtime</scope>
            <version>1.1.0-alpha-2</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>knowledge-api</artifactId>
            <version>5.4.0.Beta1</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.servicemix.bundles</groupId>
            <artifactId>org.apache.servicemix.bundles.drools</artifactId>
            <version>5.1.1_1</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
    <build>
        <defaultGoal>package</defaultGoal>
        <finalName>seam-booking</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>1.0-alpha-4</version>
            </plugin>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalBuildcommands>
                        <!-- annoyingly creates a bin directory <buildCommand> <name>org.eclipse.wst.jsdt.core.javascriptValidator</name> </buildCommand> -->
                        <buildCommand>
                            <name>org.jboss.tools.common.verification.verifybuilder</name>
                        </buildCommand>
                    </additionalBuildcommands>
                    <additionalConfig>
                        <file>
                            <name>.settings/org.maven.ide.eclipse.prefs</name>
                            <content>eclipse.preferences.version=1
                                   fullBuildGoals=process-test-resources
                                   includeModules=false
                                   resolveWorkspaceProjects=true
                                   resourceFilterGoals=process-resources
                                   resources\:testResources
                                   skipCompilerPlugin=true
                                   version=1</content>
                        </file>
                    </additionalConfig>
                    <additionalProjectFacets>
                        <jst.jsf>2.0</jst.jsf>
                    </additionalProjectFacets>
                    <additionalProjectnatures>
                        <projectnature>org.eclipse.wst.jsdt.core.jsNature</projectnature>
                        <projectnature>org.jboss.tools.jsf.jsfnature</projectnature>
                    </additionalProjectnatures>
                    <workspace>d:\workspace</workspace>
                    <wtpdefaultserver>JBossAS</wtpdefaultserver>
                    <wtpversion>2.0</wtpversion>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <!-- The JBoss AS plugin deploys your war to a local JBoss AS container -->
            <!-- To use, set the JBOSS_HOME environment variable and run: mvn package jboss-as:deploy -->
            <plugin>
                <groupId>org.jboss.as.plugins</groupId>
                <artifactId>jboss-as-maven-plugin</artifactId>
                <version>7.1.0.Final</version>
            </plugin>
        </plugins>
    </build>
    <profiles>
        <profile>
            <id>distribution</id>
            <activation>
                <property>
                    <name>release</name>
                </property>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-assembly-plugin</artifactId>
                    </plugin>
                </plugins>
            </build>
        </profile>
        <profile>
            <id>jbossas7</id>
            <activation>
                <activeByDefault>true</activeByDefault>
                <property>
                    <name>arquillian</name>
                    <value>jbossas-managed-7</value>
                </property>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-war-plugin</artifactId>
                        <version>2.0</version>
                        <configuration>
                            <webResources>
                                <resource>
                                    <directory>src/main/resources-jbossas7</directory>
                                </resource>
                            </webResources>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
        <profile>
            <id>jbossas-remote-7</id>
            <activation>
                <property>
                    <name>arquillian</name>
                    <value>jbossas-remote-7</value>
                </property>
            </activation>
            <dependencies>
                <dependency>
                    <groupId>org.jboss.seam.test</groupId>
                    <artifactId>jbossas-remote-7</artifactId>
                    <type>pom</type>
                    <scope>test</scope>
                </dependency>
            </dependencies>
        </profile>
        <profile>
            <id>jbossas-managed-7</id>
            <activation>
                <property>
                    <name>arquillian</name>
                    <value>jbossas-managed-7</value>
                </property>
            </activation>
            <dependencies>
                <dependency>
                    <groupId>org.jboss.seam.test</groupId>
                    <artifactId>jbossas-managed-7</artifactId>
                    <type>pom</type>
                    <scope>test</scope>
                    <version>LATEST</version>
                </dependency>
            </dependencies>
        </profile>
    </profiles>
    <scm>
        <connection>scm:git:git://github.com/seam/examples.git</connection>
        <developerConnection>scm:git:git@github.com:seam/examples.git</developerConnection>
        <url>http://github.com/seam</url>
    </scm>
</project>

Maven Eclipse Plugin

This plugin configures the Eclipse Workspace and creates/modifies the configuration files of Eclipse, so the maven project can be easily imported into Eclipse. I assume, you have imported the Seam Booking example project into your default eclipse workspace.

First, place the following plugin declaration into the <build> section of the pom file (as you have seen under the "Maven 3.0.4 and Dependency versions" section):

<plugin>
    <artifactId>maven-eclipse-plugin</artifactId>
    <version>2.9</version>
    <configuration>
        <additionalBuildcommands>
            <buildCommand>
                <name>org.jboss.tools.common.verification.verifybuilder</name>
            </buildCommand>
        </additionalBuildcommands>
        <additionalConfig>
            <file>
                <name>.settings/org.maven.ide.eclipse.prefs</name>
                <content>eclipse.preferences.version=1
                                   fullBuildGoals=process-test-resources
                                   includeModules=false
                                   resolveWorkspaceProjects=true
                                   resourceFilterGoals=process-resources
                                   resources\:testResources
                                   skipCompilerPlugin=true
                                   version=1</content>
            </file>
        </additionalConfig>
        <additionalProjectFacets>
            <jst.jsf>2.0</jst.jsf>
        </additionalProjectFacets>
        <additionalProjectnatures>
            <projectnature>org.eclipse.wst.jsdt.core.jsNature</projectnature>
            <projectnature>org.jboss.tools.jsf.jsfnature</projectnature>
        </additionalProjectnatures>
        <workspace>d:\workspace</workspace>
        <wtpdefaultserver>JBossAS</wtpdefaultserver>
        <wtpversion>2.0</wtpversion>
        <downloadSources>true</downloadSources>
        <downloadJavadocs>true</downloadJavadocs>
    </configuration>
</plugin>

Now, you can execute the plugin in the seam-booking directory:
mvn eclipse:eclipse

Now the eclipse project should be refreshed, to reflect the changes. If you try to build and deploy the application, it will fail, because the src/test/java directory is configured as source and the content will be included in the resulting war. I simply removed the src/test/java and src/test/resource folders from Project Properties/Java Build Path/Source.

Running the Annotation Processor in Seam Solder
You have several options to run the annotation processor to generate the typed logging class org\jboss\seam\examples\booking\logBookingLog_$logger.java. You can make Eclipse to run it or you can use ant for this purpose. I have used the APT Maven Plugin to configure the .factorypath file to enable running the annotation processor in Seam Solder Tooling, but later after adding the latest versions to the project pom's dependencies, the Eclipse APT was stopped working (no error messages, no results) so I changed to running the annotation processors using javac and ant (see later).  


APT Maven Plugin

This plugin can configure the Eclipse Annotation Processing Tool to be able to run the annotation processor in you maven project.

First, place the following plugin declaration into the build section of the pom file:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>apt-maven-plugin</artifactId>
    <version>1.0-alpha-4</version>
</plugin>


Now, you can execute the plugin in the seam-booking directory:
mvn apt:eclipse

The plugin will change the content of the ".factorypath" file in the project root directory, adding classpath entries to it. Eclipse's APT plugin will search trough this classpath and if an annotation processor factory is found, it tries to execute.

The first thing you should change is the name of the generated source directory. Go to Project properties/Java Compiler/Annotation Processing tab/Generated Source directory text box. Here enter a valid file name (e.g.: ".apt_generated", which is the default by Eclipse).

To see the list of files in the annotation processor classpath, go to the Project Properties/Java Compiler/Annotation Processor/Factory Path tab. The annotation processor for Seam 3 Booking example is found in "M2_REPO/org/jboss/solder/solder-tooling/3.1.0.Final/solder-tooling-3.1.0.Final.jar", where M2_REPO is the eclipse variable for the local maven repository. The Java 6 JDK tools.jar was missing from this factory path, so I manually added as: "D:\bin\jdk1.6.0_31\lib\tools.jar".

If you have installed JBoss 7.1 and configured in Eclipse, you should able to make the war file and deploy it to the application server (I assume you have installed the latest JBoss Tools eclipse plugin).

Using ant to run the annotation processors in your project

The JDT-APT functionality of Eclipse sometimes just doesn't work (see the previous chapter), so my alternative is to use ant and javac compiler to do it. First, create a build file for ant, and save it as build.xml in your project root:

<?xml version="1.0" encoding="UTF-8"?>
<project name="seam-booking-annotation-processing" basedir="." default="apt">
    <property name="src" value="./src/main/java" />

    <target name="apt">

        <javac compiler="javac1.6" srcdir="${src}">
            <include name="**/*.java" />
            <classpath path="${classpath}"/>
            <compilerarg line="-s ${src_gen}" />
            <compilerarg value="-verbose" />
            <compilerarg value="-proc:only" />

        </javac>
    </target>

</project>

Next, you should add a custom builder to your project: Project/Properties/Builders tab/New button:

Use "Ant Builder", then the "OK" button. The following dialog will appear. I have added the name "APT" to this custom builder. The Buildfile name is "build.xml" in the project root (which is "seam-booking" in the workspace)

The interesting part is the arguments for the ant task. The "classpath" parameter is passed to the ant build file containing the classpath, and the "src_gen" parameter contains the full path of the directory where javac will place the generated java code. The directory should be created manually, since javac doesn't create it, if missing.

-Dclasspath=${project_classpath:seam-booking}
-Dsrc_gen=${project_loc:seam-booking}/src-gen

Your builder list for the project should look like this:


Now you should add src-gen to the source paths of your project and do a build (Ctrl-B) to test if the build file is working. If the ant task is executed, it logs to the Console. I have used ant 1.7.1 and Java 1.6 u31.


Troubleshooting

When the application is not deploying, usually the src/test directories are included in the source directories.

When you click on a hotel name, and that results in an exception, this is probably caused by the missing typed loggers which should have been generated during the build process. In this case you should check the error log on why the annotation processor (Solder Tooling) haven't been run properly.