Jive Maven Archetypes

Jive SBS Maven Archetypes

This document will describe in detail the Jive SBS Maven archetypes, covering both their structure and build processes.

Version: 4.0.x-SNAPSHOT

The 4.0.x-SNAPSHOT version of the SBS Maven archetypes includes two separate archetypes:

Each archetype can be used independently of the other.  However, plugin projects are generally created within the context of a WAR overlay project.  The following sections will describe each archetype in detail.

Archetype: maven-sbs-archetype

The WAR overlay archetype is generally used in a Jive SBS customized implementation when plugins will not suffice.  The general idea is that changes within this project are compressed into a WAR, along with the core SBS code, to create a custom SBS instance.  While a plugin is the preferred method of customizing your SBS instance, in extreme cases an overlay is acceptable.

Archetype Structure

Screen shot 2009-11-09 at 8.24.38 AM.png

In addition to the standard Maven src folder, the archetype contains a single sub-project, web.  The root project's structure contains mainly test resources that allow the local instance to run properly, while the web project houses the customized pieces of the project.

src/test/resources/jiveHome

This is the jiveHome directory that is used by default by the overlay instance.  When the project is built at the root level, the jiveHome directory is copied directly to the root target folder, replacing whatever was there before.  Because of this, save for your initial build,it's probably best not to do your builds from the root level, but at the individual sub-project levels instead.  The initial contents of the folder consists only of:

web/src/main/etc

Commonly referred to the ETC Escape Hatch, the etc folder is where any Spring XML files are placed.  Jive SBS loads these XML files last when initializing the Spring application context, so any beans defined therein will take precedence over any defined within the core SBS Spring XML files.  This gives developers the ability to override any Spring beans defined within SBS, as well as add new ones, as needed.  When the web project is built, this directory's contents are copied to the root target/jiveHome/etc.  Although only one file, spring-etc.xml, is included by default, multiple Spring XML files can be included in this directory, if the developer wishes to ruther compartmentalize any custom Spring beans.

web/src/main/java

This is where your custom Java classes will live.  The package structure used here is up to the developer, and should reflect the current project.  However, if an overlay of a core SBS class is needed, the developer will need to create the exact package structure in which the class to be overlaid lives, and the core Java class copied and modified as needed.  At build time, the core Jive SBS WAR file is exploded, and the contents of the web/src/main/java folder are copied to the exploded WAR's WEB-INF/classes directory, and thusly take precedence over any classes defined in JAR files contained within the WAR's lib directory.  A placeholder class, App.java, is included here by default, but can be deleted when development work starts.

web/src/main/keys

Any public/private encryption key certifications needed by the customization go here.  At build time, contents of this folder are copied to the root target/jiveHome/keys directory to make them available to the development instance.

web/src/main/overlay

Certain overlaid resources cannot just be placed within the WAR's WEB-INF/classes directory for the customization to take effect.  Resources like Javascript files and Widget properties files need to actually replace the original artifacts in the SBS JAR file, and placed back into the WAR.  By default, this is disabled in the web pom.xml for build performance reasons, but can be enabled by uncommenting the package-sbs-plugin execution element in the maven-antrun-plugin section in the pom.

web/src/main/overlay/beans

Overlaid widget properties files are placed here.  Generally, this is needed when adding, removing, or modifying the configurable properties available within a core SBS widget.

web/src/main/overlay/resources/scripts

Any overlaid Javascript resources will live here.  In previous versions of the archetype, overlaid Javascript files needed to be accompanied by a compressed version of the file, but now that processing is done automatically by the build.

web/src/main/resources-filtered

The contents of this folder are filtered at build time, and the parameterized sections of the files contained within are populated with values, such as build number, project name, etc.  The version.properties file is accessed by the web/src/main/webapp/customer_version.jsp to provide information about the build number for a deployed instance.

web/src/main/themes

This is where custom themes go.  The provided theme.xml file is initially populated with a theme name reflecting the name of the project.  This file should be copied into the theme's main folder (web/src/main/theme/mytheme) in order to be visible to the app.  It is merely placed in this folder as a placeholder.

web/src/main/webapp

The webapp folder contains artifact that are to be placed within the exploded WAR file directory.  The archetype provides the customer_version.jsp and a WEB-INF folder to house WAR customizations.

web/src/main/webapp/WEB-INF/classes

A series of files meant to provide a custom configuration to an SBS overlay instance go here.  Specifically:

web/src/main/webapp/WEB-INF/classes/template

Add your custom Freemarker templates here.  Generally, if your change is look and feel-related, it will go in a theme.  However, if the change needs to exist outside the context of a theme, such as in a major page structure/logic change, it will need to go here, in the same directory structure as the FTL being overlaid.  Any overlaid Freemarker templates defined here will take precedence over any matching files within the core WAR file.

Archetype Build

The build behavior is all contained within the web/pom.xml file.  This section will walk through each section of the pom, explaining them in detail.

<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">
    <name>weboverlay</name>
    <modelVersion>4.0.0</modelVersion>
    <groupId>${groupId}</groupId>
    <artifactId>web</artifactId>
    <packaging>war</packaging>
    <version>${version}</version>
    <description>
       Custom Jive SBS war. We try to only place files in this project that MUST be overlayed.
       Usually this means there is no way to make the change as a plugin.  Most customizations can be done by plugin these days, and there
       are many advantages to doing so in terms of packaging, deployment, upgradability and debugging.
       Overlaying a file ensures that you will have to put forth at least some development effort when you want to upgrade versions
       of Jive SBS. 
    </description>

    <parent>
        <groupId>${groupId}</groupId>
        <artifactId>${artifactId}</artifactId>
        <version>${version}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

This is the standard pom fare, defining the name, packaging, version, parentage of the project.  The parameterized values are populated by the archetypes generation process.

<build>
    <finalName>
        ${customer.name}-${customer.version}-sbs-${sbs.version}
    </finalName>
    <resources>
        <resource>
            <directory>\${basedir}/src/main/resources-filtered</directory>
            <filtering>true</filtering>
        </resource>
    </resources>

The finalName element dictates the name of the custom WAR file generated by the build process, and reflects the name of the project, and the version of SBS being built upon.

As referenced above, the resources element specifies that artifacts in the src/main/resources-filtered folder are to be filtered when they are processed by the Maven build.

<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.6</source>    <!-- compiling with JDK 6 now -->
            <target>1.6</target>
        </configuration>
     </plugin>

The maven-compiler-plugin is set up to compile with JDK 6.

We also use some Ant tasks to accomplish some of the more rudimentary file movements needed for the build:

<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
        <executions>
            <execution>
                <id>delete-cobertura-ser</id>
                <phase>clean</phase>
                <goals>
                    <goal>run</goal>
                </goals>
                <configuration>
                    <tasks>
                        <echo message="deleting cobertura.ser" />
                        <delete file="\${basedir}/cobertura.ser" failonerror="false"/>
                    </tasks>
                </configuration>
            </execution>

The delete-cobertura-ser Ant execution deletes the cobertura.ser file generated in previous builds.  If this file is not deleted, it can result in erroneous coverage data.

<execution>
    <id>compile-sbs-artifacts</id>
    <phase>compile</phase>
    <goals>
        <goal>run</goal>
    </goals>
    <configuration>
        <tasks>
            <!-- Copy themes files into ../target/jiveHome/themes for testing  -->
            <copy todir="\${basedir}/../target/jiveHome/themes" overwrite="true">
                <fileset dir="\${basedir}/src/main/themes">
                    <include name="**/*" />
                </fileset>
            </copy>

            <!-- Now build a new themes.zip for distribution -->
            <mkdir dir="${project.build.directory}/themes"/>
            <copy todir="${project.build.directory}/themes" overwrite="yes" filtering="off">
                <fileset dir="\${basedir}/src/main/themes"
                         includes="**/*" excludes="**/.svn, **/.svn/**" />
            </copy>
            <zip destfile="${project.build.directory}/themes.zip">
                <zipfileset dir="${project.build.directory}/themes" prefix=""/>
            </zip>

            <!-- Copy your etc directory to ../target/jiveHome for testing-->
            <mkdir dir="../target/jiveHome/etc"/>
            <copy todir="../target/jiveHome/etc" overwrite="true">
                <fileset dir="src/main/etc">
                    <include name="*.xml"/>
                </fileset>
            </copy>

            <!-- Build an etc.zip for distribution-->
            <zip destfile="${project.build.directory}/etc.zip">
                <zipfileset dir="\${basedir}/src/main/etc" prefix=""/>
            </zip>

            <!-- Copy your etc directory to ../target/jiveHome for testing-->
            <mkdir dir="../target/jiveHome/keys"/>
            <copy todir="../target/jiveHome/keys" overwrite="true">
                <fileset dir="\${basedir}/src/main/keys">
                    <include name="*.der"/>
                </fileset>
            </copy>

            <!-- Build an keys.zip for distribution-->
            <zip destfile="${project.build.directory}/keys.zip">
                <zipfileset dir="\${basedir}/src/main/keys" prefix=""/>
            </zip>
        </tasks>
    </configuration>
</execution>

The compile-sbs-artifacts Ant execution performs the following actions:

  1. Copies the web/src/main/themes directory to the root target/jiveHome/themes for use by the local instance (if running Cargo, this is not necessary as the -DthemesDir system property points to the src/main/themes directory and makes changes available on the fly).
  2. Zips the web/src/main/themes directory up into a themes.zip file, for deployment to a test or production server.
  3. Copies the web/src/main/etc directory to the root target/jiveHome/etc for use by the local instance.
  4. Zips the web/src/main/etc directory up into an etc.zip file, for deployment to a test or production server.
  5. Copies the web/src/main/keys directory to the root target/jiveHome/keys for use by the local instance.
  6. Zips the web/src/main/keys directory up into a keys.zip file, for deployment to a test or production server.

        <!-- The execution below should be used when a project needs to overlay any Jive SBS bean.properties
             or resources in the Jive SBS directory "resources.scripts".  In order for these overlay files
             to actually override their equivalents in the Jive SBS jar, they need to be placed in the
             Jive SBS jar itself. -->                    
        <!--<execution>
            <id>repackage-sbs-jar</id>
            <phase>package</phase>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <tasks>
                    <unjar src="./target/${build.finalName}/WEB-INF/lib/jive-sbs-employee-${sbs.shortversion}.jar"
                           dest="./target/jive-sbs-employee-temp-${sbs.shortversion}" />
                    <copy todir="./target/jive-sbs-employee-temp-${sbs.shortversion}" overwrite="true">
                        <fileset dir="./src/main/overlay/" includes="**/*"/>
                    </copy>

                    <taskdef name="yui-compressor"
                             classname="net.noha.tools.ant.yuicompressor.tasks.YuiCompressorTask"
                             classpathref="maven.dependency.classpath"/>

                    <yui-compressor
                            warn="false"
                            munge="true"
                            preserveallsemicolons="false"
                            todir="./target/jive-sbs-employee-temp-${sbs.shortversion}"
                            fromdir="./src/main/overlay"
                            charset="utf8">
                    </yui-compressor>
                    <jar jarfile="./target/${build.finalName}/WEB-INF/lib/jive-sbs-employee-${sbs.shortversion}.jar" update="false">
                        <fileset dir="./target/jive-sbs-employee-temp-${sbs.shortversion}" includes="**/*"/>
                    </jar>
                    <jar destfile="./target/${build.finalName}.war">
                        <fileset dir="./target/${build.finalName}"/>
                    </jar>
                </tasks>
            </configuration>
        </execution>-->
    </executions>
</plugin>

The repackage-sbs-jar Ant execution, which is commented out by default, repackages the SBS JAR file with artifacts that cannot be appropriately overlaid within the WAR's WEB-INF/classes directory, specifically widget properties and Javascript files.  It performs the following actions:

  1. Explodes the core SBS JAR file to a directory.
  2. Copies any artifacts from web/source/main/overlay to the exploded SBS JAR directory, overwriting any duplicate files.
  3. Compresses any Javascript artifacts using the YUI Compressor utility to create the *-min.js Javascript artifacts.
  4. Creates a new JAR file from the contents of the exploded JAR directory.
  5. Creates a new WAR file from the contents of the exploded WAR directory.

<plugin>
    <!-- Surefire is our unit testing framework of choice-->
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <!-- Don't suck up selenium tests in there-->
        <excludes>
            <exclude>**/selenium/*Test.java</exclude>
        </excludes>
    </configuration>
</plugin>

The maven-surefire-plugin is configured to exclude any Selenium tests from being executed as part of the normal build process.

         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-war-plugin</artifactId>
             <version>2.0</version>
             <configuration>
                 <workingDirectory>\${basedir}/target/tmp</workingDirectory>
             </configuration>
         </plugin>
    </plugins>
</build>

More goodies for further configuring the maven-war-plugin.

<!-- These properties are set by a TeamCity CI server.  They get populated into the customer_version.jsp that
     is copied into our war file at the root.  This gives you web-accessible, definitive build information -->
<properties>
    <build.number>${env.BUILD_NUMBER}</build.number>
    #set($vcsNumber = '${env.BUILD_VCS_NUMBER.1}')
    <build.vcs.number>$vcsNumber</build.vcs.number>
    #set($projectName = '${env.TEAMCITY_PROJECT_NAME}')
    <build.project.name>$projectName</build.project.name>
</properties>

This is how we get the build version numbers into the custom_version.jsp file.

<dependencies>
    <dependency>
        <groupId>com.jivesoftware</groupId>
        <artifactId>jive-sbs-employee</artifactId>     <!-- was clearspacex -->
        <version>${sbs.version}</version>
        <type>war</type>
    </dependency>
       
    <dependency>
        <groupId>com.jivesoftware</groupId>
        <artifactId>jive-sbs-employee</artifactId>     <!-- was clearspacex -->
        <version>${sbs.version}</version>
        <type>jar</type>
        <scope>provided</scope>
    </dependency>
       
    <dependency>
        <groupId>com.jivesoftware</groupId>
        <artifactId>jive-sbs-employee-all</artifactId> <!-- was clearspacex-all -->
        <version>${sbs.version}</version>
        <type>pom</type>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.4</version>
        <scope>compile</scope>
    </dependency>

    <!-- We assume your jdbc jars will be provided at runtime-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.5</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>8.3-603.jdbc3</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.openqa.selenium.client-drivers</groupId>
        <artifactId>selenium-java-client-driver</artifactId>
        <version>0.9.2</version>
        <scope>test</scope>
    </dependency>

    <!-- The dependencies below should be used when a project needs to overlay any resources in the Jive SBS
         directory "resources.scripts".  In order for the minimized Javascript files to be generated, these
         dependencies must be present so the yui-compressor task can run -->
    <!--<dependency>
        <groupId>com.jivesoftware</groupId>
        <artifactId>yuicompressor</artifactId>
        <version>2.2.4_2_0_0_rc1</version>
    </dependency>
    <dependency>
        <groupId>com.jivesoftware</groupId>
        <artifactId>yuicompressor-anttask</artifactId>
        <version>2.4.2</version>
    </dependency>-->
</dependencies>

The dependency element defines the libraries needed to compile and build the web project, including:

Profiles

The following section describes the various profiles that exist within the web project's POM.  Profiles allow for different configurations to be used during a build by specifying the profile when the build is run.  In the case of the overlay project, two profiles are used by default:
  • int: integration-testing profile. Allows for running all of the integration tests for the project, but more commonly for running the project inside of a local Tomcat instance via Cargo.
  • dev:  largely the same as the int profile, but adds the ability to run the project in an environment a bit more conducive to the iterations associated with development.
Profile: int
The int profile contains two plugins:
  • cargo-maven2-plugin: Discussed below
  • selenium-maven-plugin:  Runs the Selenium integration test suite
  • maven-surefire-plugin:  Specifies that only Selenium integration tests are to be run

The cargo-maven2-plugin allows us to deploy the app to Tomcat for the purpose of running integration tests against the instance, and also to allow for manual use of the app, depending how it is run.

There are several ways to run Cargo:
Command Comments
mvn -P int integration-test Runs the integration tests inside of Cargo and then exits.  Maven will run through all of the other dependent lifecycle phases before running the tests (compile, package, test, etc).  You would use this if you wanted to only run the automated integration tests.
mvn -Dcargo.wait=true -P int integration-test Runs the app within Cargo, after running through dependent Maven lifecycle phases.  The presence of the cargo.wait system property tells Maven to keep the Tomcat instance up and to wait for either user input, or for the instance to be shut down manually.  Note that running this way will cause the custom WAR to be rebuilt before the app is deployed.
mvn -Dcargo.wait=true -P int cargo:start Runs the app within Cargo, but does not run through any dependent Maven lifecycle phases.  Rather, it deploys the existing custom WAR to the Tomcat instance, and waits for user input or a manual shutdown.  This option is recommended for plugin development when a new WAR is not required to observe changes in a local instance.
The cargo-maven2-plugin is defined in the POM as follows:

<profiles>     <profile>         <id>int</id>         <build>             <plugins>                 <!-- Cargo is our main method of running and testing/debugging SBS.  This is the main configuration area. -->           <!-- Here is the config reference:  http://cargo.codehaus.org/Maven2+Plugin+Reference+Guide    -->                 <plugin>                     <groupId>org.codehaus.cargo</groupId>                     <artifactId>cargo-maven2-plugin</artifactId>                     <version>1.0</version>                     <configuration>                   <!-- Feed them this value; Decides if Cargo should wait after the container is started or not -->                         <wait>${cargo.wait}</wait>                         <container>                             <containerId>tomcat6x</containerId>                             <home>${tomcat6.home}</home>                             <systemProperties>                                 <jive.instance.home>\${basedir}/../target/jiveHome</jive.instance.home>                                 <jive.ws.disabled>true</jive.ws.disabled>                                 <jive.devMode>true</jive.devMode>                                 <themes.directory>\${basedir}/src/main/themes</themes.directory>                                 <!-- <pluginDirs>\${basedir}/../myplugin/src/main/plugin</pluginDirs> -->                             </systemProperties>                             <dependencies>                        <!-- Throw in our most common jdbc connectors; add yours here if it's missing -->                                 <dependency>                                     <groupId>mysql</groupId>                                     <artifactId>mysql-connector-java</artifactId>                                     <type>jar</type>                                 </dependency>                                 <dependency>                                     <groupId>postgresql</groupId>                                     <artifactId>postgresql</artifactId>                                 </dependency>                                 <dependency>                                     <groupId>javax.servlet</groupId>                                     <artifactId>servlet-api</artifactId>                                     <type>jar</type>                                 </dependency>                             </dependencies>                         </container>                         <configuration>                             <home>target/tomcat6x</home>                             <properties>                                 <cargo.jvmargs>-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n -Xms512m -Xmx1024m -XX:MaxPermSize=256m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC</cargo.jvmargs>                             </properties>                             <deployables>                                 <deployable>                                     <location>target/${customer.name}-${customer.version}-sbs-${sbs.version}.war</location>                                     <pingURL>http://localhost:8080/jive</pingURL>                                     <properties>                                         <context>jive</context>                                     </properties>                                 </deployable>                             </deployables>                         </configuration>                     </configuration>                     <executions>                         <execution>                             <id>start-container</id>                             <phase>pre-integration-test</phase>                             <goals>                                 <goal>start</goal>                             </goals>                         </execution>                         <execution>                             <id>stop-container</id>                             <phase>post-integration-test</phase>                             <goals>                                 <goal>stop</goal>                             </goals>                         </execution>                     </executions>                 </plugin>

The configuration element allows for the specification of system properties, deployables, customization of the JVM args, and more.  Each item is discussed below.

<wait>${cargo.wait}</wait>

The value for the wait property is passed through from the command line, and determines whether Cargo will remain up, waiting for user interaction.

<container>     <containerId>tomcat6x</containerId>     <home>${tomcat6.home}</home>     <systemProperties>         <jive.instance.home>\${basedir}/../target/jiveHome</jive.instance.home>         <jive.ws.disabled>true</jive.ws.disabled>         <jive.devMode>true</jive.devMode>         <themes.directory>\${basedir}/src/main/themes</themes.directory>         <!-- <pluginDirs>\${basedir}/../myplugin/target/myplugin</pluginDirs> -->     </systemProperties>     <dependencies>         <!-- Throw in our most common jdbc connectors; add yours here if it's missing -->         <dependency>             <groupId>mysql</groupId>             <artifactId>mysql-connector-java</artifactId>             <type>jar</type>         </dependency>         <dependency>             <groupId>postgresql</groupId>             <artifactId>postgresql</artifactId>         </dependency>         <dependency>             <groupId>javax.servlet</groupId>             <artifactId>servlet-api</artifactId>             <type>jar</type>         </dependency>     </dependencies> </container>

The container element allows for the configuration of how the Tomcat instance is run.  The home element specifies where the Tomcat instance to be used is located, the value of which should be specified in your Maven settings.xml file.

JVM system properties are specified in the systemProperties element.  The default values are as follows:

System Property Value Comments
jive.instance.home ${basedir}/../target/jiveHome This points the SBS instance to the jiveHome directory deployed when the root project is built.
jive.ws.disabled true Disables web services, which makes startup much faster.
jive.devMode true Allows for running SBS in dev mode, which allows for the use of pluginDirs, themes.directory, and disables FTL cacheing.
themes.directory ${basedir}/src/main/themes Specifies that the themes directory used by the app will be the those in the src/main/themes directory.  This allows for changes to the themes to be made and observed on the fly, without rebuilding or restarting.
pluginDirs none Specifes a comma-delimited list of plugins to run, each being represented by a directory containing the contents of the exploded plugin JAR file.  This allows the plugin to be installed in the SBS instance without actually saving it to the database and having to restart.

The dependencies element references upstream dependencies defined within the POM that are needed to properly run the tomcat instance.

    <configuration>         <home>target/tomcat6x</home>         <properties>             <cargo.jvmargs>-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n -Xms512m -Xmx1024m -XX:MaxPermSize=256m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC</cargo.jvmargs>         </properties>         <deployables>             <deployable>                 <location>target/${customer.name}-${customer.version}-sbs-${sbs.version}.war</location>                 <pingURL>http://localhost:8080/jive</pingURL>                 <properties>                     <context>jive</context>                 </properties>             </deployable>         </deployables>     </configuration>

</configuration>

The configuration element defines various Cargo properties, including how to start the JVM, and where the artifacts to be deployed reside.  The home element specifies where the WAR being deployed should be copied to and exploded.  Running SBS is very memory intensive and requires that additional memory be allocated to the stack, which is done using the cargo.jvmargs property.  The webapp(s) to run is/are defined in the deployables element, each supplying the location of the war to be deployed, as well as the context under which the deployable is to be run.  By default, only one deployable is defined: the WAR created during the build, which runs under the jive context (http://localhost:8080/jive).

Profile: dev

The dev profile, like the int profile, provides for the running of the customized SBS instance locally, via Tomcat and Cargo, but without the notion of integration testing being the purpose.  The plugins offered by the profile are:

The cargo-maven2-plugin functions largely the same as in the int profile, but with a few more options to better facilitate the use of Java Rebel.  For example, the following system properties are specified in the systemProperties element:

System Property Default Value Comments
docverse.enabled false Disables the DocVerse module, which causes problems with JavaRebel
rebel.struts2-plugin true Enables Rebel monitoring of Struts configuration changes

The JavaRebel plugin is commented out by default, since it requires a license to run.  Java Rebel allows for the monitoring of class directories so that changes can be hot-deployed to a running instance without a restart.

<!--<plugin>     <groupId>org.zeroturnaround</groupId>     <artifactId>javarebel-maven-plugin</artifactId>     <executions>         <execution>             <id>generate-rebel-xml</id>             <phase>process-resources</phase>             <goals>                 <goal>generate</goal>             </goals>         </execution>     </executions>     <configuration>         <classpath>             <fallback>default</fallback>             <resources>                 <resource>                     <directory>\${basedir}/../myplugin/target/classes</directory>                 </resource>                 <resource>                     <jarset>\${basedir}/../myplugin/target/dependency</jarset>                 </resource>             </resources>         </classpath>         <war>             <path>\${basedir}/target/${customer.name}-${customer.version}-sbs-${sbs.version}</path>         </war>     </configuration> </plugin> -->

The custom WAR file is specified by default.  To target additional directories, such as plugins, an entry for the plugin's classes directory is needed in the resources element, like shown in the listing above.  This will allow for changes to the plugin's code to be monitored and loaded without having to rebuild the plugin and restart the server.

Archetype: maven-sbs-plugin-archetype

The plugin archetype provides a template for SBS plugin projects, and is the preferred method for customizing an SBS instance.

Archetype Structure

Screen shot 2009-11-10 at 9.19.51 AM.png

The archetype creates a single project, representing the plugin to be developed, built, and deployed.

src/main/assembly

The plugin makes use of the maven-assembly-plugin to determine how the plugin JAR is packaged.  Its configuration is contained within the assembly-plugin.xml.

src/main/java

The Java code making up the plugin goes here.  Not much else to say about it.

src/main/plugin

Artifacts contained within this folder will be placed in the plugin's root directory as part of the build process.  Artifacts in this folder are filtered by the build process and can be parameterized.  Files included in this folder by default include:

src/main/plugin/resources/images

Images needed by the plugin go here

src/main/plugin/resources/script

Javascript files used by the plugin go here

src/main/plugin/resources/styles

The plugin's cascading stylesheets will go here.

src/main/plugin/resources/templates

Freemarker templates needed by the plugin go here.

src/main/resources

Artifacts in this directory will be placed in the classes directory when the project is built.  Only one file, plugin_i18n.properties, which acts as the default resource bundle for the plugin, is included here by default.

src/test/java

This is where unit tests live.

Archetype Build

The build behavior is all contained within the plugin's pom.xml file.  This section will walk through each section of the pom, explaining them in detail.

<?xml version="1.0" encoding="UTF-8"?> <!--   ~  $Revision: 96475 $   ~  $Date: 2009-11-02 16:51:02 -0800 (Mon, 02 Nov 2009) $   ~   ~  Copyright (C) 1999-${YEAR} Jive Software. All rights reserved.   ~   ~  This software is the proprietary information of Jive Software. Use is subject to license terms.   --> <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">     <!--       These parameters were pased in via the commandline when this pom was created by the archetype.       -->     <modelVersion>4.0.0</modelVersion>     <groupId>${groupId}</groupId>     <artifactId>${artifactId}-plugin</artifactId>     <name>${artifactId}</name>     <version>1.0</version>     <packaging>jar</packaging>     <url>http://www.jivesoftware.com</url>

This is the standard Maven project definition, the parameterized values of which are populated upon creation of the plugin project.

    <build>         <finalName>${artifactId}-plugin</finalName>         <plugins>          <!-- For compilation-->             <plugin>                 <artifactId>maven-compiler-plugin</artifactId>                 <configuration>                     <source>1.6</source>                     <target>1.6</target>                 </configuration>             </plugin>

The finalName element defines the name of the JAR file created by the build process.

Like the web POM, the maven-compiler-plugin is set up to use JDK 6 to compile Java resources.

            <!-- Weave transactions into the plugin -->             <plugin>                 <groupId>org.codehaus.mojo</groupId>                 <artifactId>aspectj-maven-plugin</artifactId>                 <version>1.1</version>                 <configuration>                     <aspectLibraries>                         <aspectLibrary>                             <groupId>org.springframework</groupId>                             <artifactId>spring-aspects</artifactId>                         </aspectLibrary>                     </aspectLibraries>                     <source>1.6</source>                 </configuration>                 <executions>                     <execution>                         <goals>                             <goal>compile</goal>                         </goals>                     </execution>                 </executions>             </plugin>

The aspectj-maven-plugin allows for the weaving of aspect libraries into the plugin code.  By default, the spring-aspects library is included to provide support for use of the @Transactional aspect within Java classes.

            <plugin>                 <artifactId>maven-assembly-plugin</artifactId>                 <executions>                     <execution>                         <id>assembly</id>                         <phase>package</phase>                         <goals><goal>single</goal></goals>                         <configuration>                             <appendAssemblyId>false</appendAssemblyId>                             <descriptors>                                 <descriptor>\${basedir}/src/main/assembly/assembly-plugin.xml</descriptor>                             </descriptors>                         </configuration>                     </execution>                 </executions>             </plugin>

The maven-assembly-plugin affects how the JAR file artifact produced by the build process is structured.  This configuration points to the assembly-plugin.xml for its directives.

            <plugin>                 <artifactId>maven-antrun-plugin</artifactId>                 <executions>                     <execution>                         <!-- Unpackages this SBS plugin.  That way it can be used in conjunction with the -DpluginDirs= property, which                              bypasses the standard plugin installation (which happens via the Admin Console), by pointing to exploded plugin jar created by this. -->                         <id>explode-sbs-plugin</id>                         <phase>package</phase>                         <goals>                             <goal>run</goal>                         </goals>                         <configuration>                             <tasks>                                <mkdir dir="\${basedir}/target/${artifactId}" />                                <unjar src="\${basedir}/target/${artifactId}-plugin.jar" dest="\${basedir}/target/${artifactId}" />                             </tasks>                         </configuration>                     </execution>                 </executions>             </plugin>

The maven-antrun-plugin for the plugin build process takes the resulting JAR artifact and explodes it into a directory, whose name is dictated by the plugin's name, within the plugin's target folder.  This enables the inclusion of the plugin in a local SBS instance using the pluginDirs system property, which points to the exploded JAR directory.

            <plugin>                 <groupId>org.apache.maven.plugins</groupId>                 <artifactId>maven-source-plugin</artifactId>                 <executions>                     <execution>                         <id>attach-sources</id>                         <phase>verify</phase>                         <goals>                             <goal>jar</goal>                         </goals>                     </execution>                 </executions>             </plugin>

Including the maven-source-plugin creates a source jar artifact for the plugin when it's built.

         <!-- For unit testing -->             <plugin>                 <artifactId>maven-surefire-plugin</artifactId>                 <configuration>                     <excludes>                         <exclude>**/selenium/*Test.java</exclude>                     </excludes>                 </configuration>             </plugin>         </plugins>     </build>

Like in the web POM, this configuration of the maven-surefire-plugin excludes Selenium tests from being run as part of the normal build process.

    <dependencies>         <dependency>             <groupId>com.jivesoftware</groupId>          <artifactId>jive-sbs-employee</artifactId>   

            <version>${sbs.version}</version>             <type>jar</type>             <scope>provided</scope>      </dependency>         <dependency>

            <groupId>com.jivesoftware</groupId>             <artifactId>jive-sbs-employee-all</artifactId>             <version>${sbs.version}</version>             <type>pom</type>             <scope>provided</scope>         </dependency>         <dependency>             <groupId>javax.servlet</groupId>             <artifactId>servlet-api</artifactId>             <version>2.3</version>             <type>jar</type>             <scope>provided</scope>         </dependency>     

        <!-- The following dependencies are for unit testing-->         <dependency>             <groupId>junit</groupId>             <artifactId>junit</artifactId>             <version>4.4</version>             <scope>test</scope>         </dependency>         <dependency>             <groupId>org.objenesis</groupId>             <artifactId>objenesis</artifactId>             <version>1.0</version>             <scope>test</scope>         </dependency>         <dependency>             <groupId>cglib</groupId>             <artifactId>cglib</artifactId>             <version>2.1</version>             <scope>test</scope>         </dependency>         <dependency>             <groupId>org.jmock</groupId>             <artifactId>jmock-junit4</artifactId>             <version>2.4.0</version>             <scope>test</scope>         </dependency>     </dependencies>

The plugin POM includes the following dependencies by default:

    <!-- This is where you set the Jive SBS version your plugin is compiled against. -->     <properties>         <sbs.version>4.0.0</sbs.version>     </properties> </project>

The version of Jive against which the plugin is being compiled against is defined here, in the sbs.version property.