Technical Blog

4 Posts tagged with the build tag

I have a love/hate relationship with Eclipse.  It's a great editor with sane default key mappings, but it tries to be too much.  One thing that never worked all that well is the WTP plugin for managing application servers.


How many times have you refreshed/published/republished Tomcat in Eclipse?  Sometimes the configuration files get out of sync and you have to clean it.  And since all the wars end up in the same Tomcat instance the start up time is horrendous.


An alternative to WTP is the Tomcat Maven plugin.  It allows you to manage Tomcat servers, but what I want to show you is how use it to run a war project in an embedded Tomcat instance.


Unfortunately our war projects are not fully Mavenized (yet), but we can get around that by using the fact it is just a war in the end.  This allows us to use the Maven War plugin to create an overlay over our war projects and then run that in Tomcat.


So enough pre-amble, show me the code!  Let’s get com.elasticpath.sf running using the Tomcat Maven plugin and MySQL.


First we need to get some environment specific settings out of the way.  Since we are doing a war overlay we won’t have access to any of the settings in env.config.  Instead we’ll put our environment specific settings in ~/.m2/settings.xml:

<?xml version="1.0"?>

<settings>

  <activeProfiles>

    <acitveProfile>mysql-dev-db</activeProfile>

    <activeProfile>storefront-tomcat-properties</activeProfile>

    <activeProfile>keystore-properties</activeProfile>

  </activeProfiles>

                       

  <profiles>

    <profile>

      <id>storefront-tomcat-properties</id>

      <properties>

        <storefront.context>/storefront</storefront.context>

        <storefront.http.port>8080</storefront.http.port>

        <storefront.https.port>8443</storefront.https.port>

      </properties>

    </profile>

    <profile>

      <id>keystore-properties</id>

      <properties>

        <keystore.file>/your/very/own/.keystore</keystore.file>

        <keystore.pass>changeit</keystore.pass>

      </properties>

    </profile>

  </profiles>


       …


</settings>


Other war projects will need their own profile.  The profile mysql-dev-db will come from the grandparent pom.  It is available since 6.3 and the source is included under elasticpath-grandparent/pom.xml.  If the default properties defined in the mysql-dev-db profile are unsuitable for your needs, they can be overriden using another profile in ~/.m2/settings.xml and activate it after the mysql-dev-db profile.


We then create a new Maven project called storefront which will overlay com.elasticpath.sf.  Here we will use the released version of the grandparent pom and define the parent of the storefront project as the grandparent pom:

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

<project

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <modelVersion>4.0.0</modelVersion>


  <parent>

    <groupId>com.elasticpath</groupId>

    <artifactId>grandparent</artifactId>

    <version>16</version>

  </parent>

  <groupId>com.elasticpath.extensions</groupId>

  <artifactId>storefront</artifactId>

  <version>1.0-SNAPSHOT</version>

  <packaging>war</packaging>

  <name>Storefront Extension</name>


  <dependencies>

    <dependency>

      <groupId>com.elasticpath</groupId>

      <artifactId>com.elasticpath.sf</artifactId>

      <version>...your Elastic Path version...</version>

      <type>war</type>

    </dependency>

  </dependencies>


Now define the Tomcat Maven plugin configuration.  The path and port configuration is defined in the settings profile.  And finally we choose the JDBC driver.  Yes this means you never again have to figure out where is Tomcat’s shared library folder.  All the epdb.* properties are defined in the mysql-dev-db profile.

  <build>

    <plugins>

      <plugin>

        <groupId>org.codehaus.mojo</groupId>

        <artifactId>tomcat-maven-plugin</artifactId>

        <version>1.1</version>

        <configuration>

          <path>${storefront.context}</path>

          <port>${storefront.http.port}</port>

          <httpsPort>${storefront.https.port}</httpsPort>

          <keystoreFile>${keystore.file}</keystoreFile>

          <keystorePass>${keystore.pass}</keystorePass>

        </configuration>

        <dependencies>

          <dependency>

            <groupId>${epdb.maven.groupId}</groupId>

            <artifactId>${epdb.maven.artifactId}</artifactId>

            <version>${epdb.maven.version}</version>

          </dependency>

        </dependencies>

      </plugin>


We need to define the jdbc/epjndi resource as a MySQL datasource.  This is done with META-INF/context.xml.  To get our settings into context.xml we’ll filter it using the Maven War plugin:

      <plugin>

        <groupId>org.apache.maven.plugins</groupId>

        <artifactId>maven-war-plugin</artifactId>

        <version>2.1.1</version>

        <configuration>

          <webResources>

            <resource>

              <directory>src/main/webapp-filtered</directory>

              <filtering>true</filtering>

            </resource>

          </webResources>

        </configuration>

      </plugin>

    </plugins>

  </build>

</project>


That will filter any file in src/main/webapp-filtered and put the result in the root of the built war.  This allows us to create src/main/webapp-filtered/META-INF/context.xml with the contents:

<Context>

  <Resource auth="Container" name="mail/Session" type="javax.mail.Session" />

  <Resource

    name="jdbc/epjndi"

    auth="Container"

    scope="Shareable"

    type="${epdb.datasource.classname}"

    maxActive="100"

    maxIdle="30"

    maxWait="10000"

    removeAbandoned="true"

    username="${epdb.username}"

    password="${epdb.password}"

    driverClassName="${epdb.jdbc.driver}"

    url="${epdb.url}" />

</Context>


...and have it filled out by the mysql-dev-db profile.


Our storefront project depends on com.elasticpath.sf so make sure it's in your local repo by running ant install under com.elasticpath.sf.


Since we are running Tomcat with Maven in order to pass JVM arguments to Tomcat you’ll need to configure the environment variable MAVEN_OPTS instead of CATALINA_OPTS.  Note for Java 6 users to copy over their special JVM args to MAVEN_OPTS.  This also means remote debugging parameters should be set in MAVEN_OPTS.  For more information on remote debugging see: http://java.dzone.com/articles/how-debug-remote-java-applicat


Finally we run our storefront project with

    mvn tomcat:run-war


Storefront is now running under http://localhost:8080/storefront and can be killed with ^C.


Repeat for the remaining wars and you can have each war project running in a separate embedded Tomcat instance.  Just remember to give each instance its own port and update settings like COMMERCE/SYSTEM/SEARCH/searchHost.  See http://mojo.codehaus.org/tomcat-maven-plugin/index.html for more details on how to configure the run-war goal.  Special care is needed to ensure each project has its own remote debugging ports.  This is accomplished by setting different MAVEN_OPTS for each project.  Simply use

    MAVEN_OPTS=”$MAVEN_OPTS <project specific opts>” mvn tomcat:run-war

This will temporary append project specific options to MAVEN_OPTS.  There is no semicolon before mvn because we only want to set this variable for this process and not back to the shell.


This gives you great control to start and stop individual wars.  Only changed com.elasticpath.sf?  Just ant install and restart that Tomcat instance.


While it took a little bit of work to get the environment specific settings in the right place this now gives us a platform to use more Maven without having to wait for the full Mavenization of our projects.  Let’s get cracking!

0 Comments Permalink

One of the quirks that I used to have while developing using binary based development is the fact that we have multiple maven projects, and changes to one of the projects (ie. core) will need to be rebuilt in other projects that depend on it (ie. storefront).

 

This was typical what I had to do:

 

cd project-root
cd core-project
mvn clean install

<take a nap for a few minutes>

<check to make sure the project built successfully>

cd ../storefront-project
mvn clean install

 

The other option is to build all the projects in the workspace.

 

cd project-root
mvn clean install

<take a longer nap for 10 minutes>

 

That is actually ineffective and a waste of time. One could argue you can write a script that will invoke those commands for you. However, you'd have to check for cases whent the build fails. Luckily, I found that there is a maven plugin that helps with automating that for us.

 

This is where the Maven Reactor plugin comes to the rescue.

 

The solve the previous problem where you changed your core project and only want to build the storefront, all you have to do is type this in the project-root directory:

 

mvn reactor:make -Dmake.folders=storefront-project

 

The Maven Reactor plugin will build core-project and then the storefront-project for you. If there is a problem with the core project (ie. compilation failures), it will stop the build and tell you.

4 Comments Permalink

The contract negociation went through, the SLA is signed, and as a super-keen developer, you've already downloaded and built Elastic Path within minutes ()! Your heart is racing. The adrenaline is pumping. You just can't wait to start building your ecommerce storefront. With the source code in hand, it's so tempting to start hacking the Elastic Path source code right away.

 

But then you start thinking about the next EP release version, and bug fixes... and you're wondering what you're going to do when it's time to upgrade... How will you manage your customizations while keeping in sync with the most recent stable release of Elastic Path?

 

Maven to the rescue! You can use the power of Maven dependencies and, more importantly, the WAR overlay feature to do this. Overlays are used to share common resources across multiple web applications. Basically, it's a nice and clean way to apply the Decorator pattern to any EP based web applications.

 

How It Works

Step 1. If you don't already have one, install your own Maven repository (Sonatype Nexus, for instance). I won't go into details, but have a look at this old post on TheServerSide.com: Setting Up a Maven Repository.

 

Step 2. Deploy all required libraries shipped with the EP source code in your new Maven repository and build the codebase as per the Developer Guide. When it's done, you should have all applications packaged and ready to be deployed. Depending on your chosen Maven repository, you will need to deploy your different WAR packages (cmserver, searchserver and storefront) by uploading both the WAR binary and the POM file within the project.

 

Step 3. Create a WAR Maven project to hold all the customizations that you want to make on the standard storefront source code (controller, XML configuration, etc.) and specify that you are dependent on EP's Mavenized storefront WAR as follows:

<dependency>
     <groupId>com.elasticpath</groupId>
     <artifactId>com.elasticpath.sf</artifactId>
     <version>6.1.1</version>
     <type>war</type>
</dependency>

 

In your POM project file, add   the Maven Warpath plugin. The Warpath plugin extends the existing war overlay functionality included in the Maven War plugin to turn war artifacts into fully fledged build dependencies. We need it to expose the classes built and contained within the WAR dependency.

<plugin>
     <groupId>org.appfuse</groupId>
     <artifactId>maven-warpath-plugin</artifactId>

     <extensions>true</extensions>
     <executions>
          <execution>
            <goals>
                 <goal>add-classes</goal>
            </goals>
          </execution>
     </executions>
</plugin>

 

While packaging your new extended storefront, all configuration, classes, and libs will be imported from the depending WAR archive into your new web application. The web application "overlay" will work exactly as the original and will be ready for any customization.
Now, let's say you want to override a specific configuration file like WEB-INF/web.xml to declare your extending ContextConfigListener java class. Simply copy locally to your project the WEB-INF/web.xml file and make your modifications. While packaging, the override files will replace all existing configuration files and resources from EP.

 

waroverlay.png

 

WAR overlay gives you full control and dependency management on all your EP customizations. In case of an upgrade or bug fix, all you need to do is rebuild the default EP package and update your project dependency. No more code merge nightmares! No more wondering if you missed any updated configuration files!

 

By combining the WAR overlay approach with Spring framework's plugin capability available within EP, you can override even bean implementation by simply creating your own core extension jar project, having a dependency on the standard EP core jar library, and defining a plugin.xml file within your own jar project. All this has already been proven in the field. You can implement your own storefront without modifying any EP core domain interfaces, services by injection you own implementation.

 

And voila! By leveraging Maven dependency and WAR overlay mechanisms, you have a clean, straightforward approach to implementing EP in the field that keeps the upgrade effort low.

8 Comments Permalink

A lot of people use ant all to build their Elastic Path projects. This is convenient when you're setting up your development environment because it builds the webapps and CM client binaries, and creates projects to import into Eclipse. On the downside, it can take a long time to do all that. As Tom pointed out in a recent blog post ( http://grep.elasticpath.com/community/techblog/blog/2009/01/27/ep-61-development-environment-tips-tricks), you really don't want to run ant all all the time. It's easier and faster to build your projects individually from within Eclipse.

 

Each webapp project (com.elasticpath.sf, com.elasticpath.cm, and com.elasticpath.search) has its own build.xml file in the root of the project directory.

 

eclipse-build-xml.png

If you only need to build one webapp, right-click the build.xml file in Eclipse's Project Explorer and choose Run As->Ant Build... . Then select the target(s) you want to run.

eclipse-targets.png

 

 

For more information on available ant targets, see the Elastic Path 6.1 Developer Guide (http://docs.elasticpath.com/display/EP61DEV/2+-+Using+the+Elastic+Path+Ant+tasks).

0 Comments 0 References Permalink