<?xml version="1.0" encoding='utf-8'?>
<?xml-stylesheet type="text/xsl" href="https://raibledesigns.com/roller-ui/styles/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom">
    <title type="html">Raible Designs</title>
    <subtitle type="html">Raible Designs is an Enterprise Open Source Consulting company. We specialize in UI and Full Stack Architectures using HTML5, CSS, JavaScript and Java. We love HTML5, Angular, Bootstrap, Spring Boot, and especially JHipster.</subtitle>
    <id>https://raibledesigns.com/rd/feed/entries/atom</id>
            <link rel="self" type="application/atom+xml" href="https://raibledesigns.com/rd/feed/entries/atom?tags=tomcat" />
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/" />
        <updated>2026-03-30T03:31:45-06:00</updated>
    <generator uri="http://roller.apache.org" version="5.0.3 (1388864191739:dave)">Apache Roller (incubating)</generator>
        <entry>
        <id>https://raibledesigns.com/rd/entry/developing_services_with_apache_camel2</id>
        <title type="html">Developing Services with Apache Camel - Part III: Integrating Spring 4 and Spring Boot</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/developing_services_with_apache_camel2"/>
        <published>2014-10-08T07:13:18-06:00</published>
        <updated>2014-10-15T19:00:44-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="apachecamel" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <category term="microservices" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring-boot" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="camel" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring4" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;
&lt;a href=&quot;http://projects.spring.io/spring-boot/&quot;&gt;&lt;img src=&quot;//raibledesigns.com/repository/images/spring-boot-logo.png&quot; alt=&quot;Spring Boot&quot; height=&quot;108&quot; class=&quot;picture&quot;&gt;&lt;/a&gt;
    This article is the third in a series on Apache Camel and how I used it to replace IBM Message Broker for a client.
    I used Apache Camel for several months this summer to create a number of SOAP services. These services performed
    various third-party data lookups for our customers. For previous articles, see
    &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_services_with_apache_camel&quot;&gt;Part I: The Inspiration&lt;/a&gt;
    and &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_services_with_apache_camel1&quot;&gt;Part II: Creating and
    Testing Routes&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
    In late June, I sent an email to my client&apos;s engineering team. Its subject: &quot;External Configuration and
    Microservices&quot;.
    I recommended we integrate &lt;a href=&quot;http://projects.spring.io/spring-boot/&quot;&gt;Spring Boot&lt;/a&gt; into the
    Apache Camel project I was working on. I told them my main motivation was its
    &lt;a href=&quot;http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-external-config&quot;&gt;
        external configuration&lt;/a&gt; feature. I also pointed out its container-less WAR feature, where Tomcat (or Jetty)
    is embedded in the WAR and you can start your app with &quot;java -jar appname.war&quot;. I mentioned
    &lt;a href=&quot;http://martinfowler.com/articles/microservices.html&quot;&gt;microservices&lt;/a&gt;
    and that Spring Boot would make it easy to split the project into a project-per-service structure if we wanted
    to go that route. I then asked two simple questions:
&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Is it OK to integrate Spring Boot?&lt;/li&gt;
    &lt;li&gt;Should I split the project into microservices?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
    Both of these suggestions were well received, so I went to work.
&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;
&lt;a href=&quot;http://projects.spring.io/spring-boot/&quot;&gt;&lt;img src=&quot;//raibledesigns.com/repository/images/spring-boot-logo.png&quot; alt=&quot;Spring Boot&quot; height=&quot;108&quot; class=&quot;picture&quot;&gt;&lt;/a&gt;
    This article is the third in a series on Apache Camel and how I used it to replace IBM Message Broker for a client.
    I used Apache Camel for several months this summer to create a number of SOAP services. These services performed
    various third-party data lookups for our customers. For previous articles, see
    &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_services_with_apache_camel&quot;&gt;Part I: The Inspiration&lt;/a&gt;
    and &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_services_with_apache_camel1&quot;&gt;Part II: Creating and
    Testing Routes&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
    In late June, I sent an email to my client&apos;s engineering team. Its subject: &quot;External Configuration and
    Microservices&quot;.
    I recommended we integrate &lt;a href=&quot;http://projects.spring.io/spring-boot/&quot;&gt;Spring Boot&lt;/a&gt; into the
    Apache Camel project I was working on. I told them my main motivation was its
    &lt;a href=&quot;http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-external-config&quot;&gt;
        external configuration&lt;/a&gt; feature. I also pointed out its container-less WAR feature, where Tomcat (or Jetty)
    is embedded in the WAR and you can start your app with &quot;java -jar appname.war&quot;. I mentioned
    &lt;a href=&quot;http://martinfowler.com/articles/microservices.html&quot;&gt;microservices&lt;/a&gt;
    and that Spring Boot would make it easy to split the project into a project-per-service structure if we wanted
    to go that route. I then asked two simple questions:
&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Is it OK to integrate Spring Boot?&lt;/li&gt;
    &lt;li&gt;Should I split the project into microservices?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
    Both of these suggestions were well received, so I went to work.
&lt;/p&gt;

&lt;h3 id=&quot;spring4&quot;&gt;Spring 4&lt;/h3&gt;

&lt;p&gt;
    Before I integrated Spring Boot, I knew I had to upgrade to &lt;a href=http://docs.spring.io/spring/docs/current/spring-framework-reference/html/new-in-4.0.html&quot;&gt;Spring 4&lt;/a&gt;. The version of Camel I was using (2.13.1)
    did not support Spring 4. I found issue CAMEL-7074 (Support spring 4.x) and
    &lt;a href=&quot;https://issues.apache.org/jira/browse/CAMEL-7074?focusedCommentId=14042668&amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-14042668&quot;&gt;
        added a comment&lt;/a&gt; to see when it would be fixed. After fiddling with dependencies and trying Camel
    2.14-SNAPSHOT,
    I was able to upgrade to CXF 3.0. However, this didn&apos;t solve my problem. There were some API uncompatible changes
    between
    Spring 3.3.x and Spring 4.0.x and the camel-test-spring module wouldn&apos;t work with both. I proposed the following:
&lt;/p&gt;

&lt;p class=&quot;quote&quot;&gt;
    I think the easiest way forward is to create two modules: camel-test-spring and camel-test-spring3. The former
    compiles against Spring 4 and the latter against Spring 3. You could switch it so camel-test-spring defaults to
    Spring 3, but camel-test-spring4 doesn&apos;t seem to be forward-looking, as you hopefully won&apos;t need a
    camel-test-spring5.
    &lt;br/&gt;&lt;br/&gt;
    I&apos;ve made this change in a fork and it works in my project. I can upgrade to Camel 2.14-SNAPSHOT and CXF 3.0 with
    Spring 3.2.8 (by using camel-test-spring3). I can also upgrade to Spring 4 if I use the upgraded camel-test-spring.
    &lt;br/&gt;&lt;br/&gt;
    Here&apos;s a pull request that has this change: &lt;a href=&quot;https://github.com/apache/camel/pull/199&quot;&gt;https://github.com/apache/camel/pull/199&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The Camel team integrated my suggested change a couple weeks later. Unfortunately,
    &lt;a href=&quot;https://issues.apache.org/jira/browse/CAMEL-7835&quot;&gt;a similar situation happened with Spring 4.1&lt;/a&gt;, so
    you&apos;ll have to wait for Camel 2.15 if you want to use Spring 4.1.&lt;/p&gt;
&lt;p&gt;
    After making a patched 2.14-SNAPSHOT version available to my project, I was able to upgrade to Spring 4 and CXF 3
    with a few minor changes to my pom.xml.
&lt;/p&gt;
&lt;pre class=&quot;brush: diff&quot;&gt;
    &amp;lt;properties&amp;gt;
      &amp;lt;project.build.sourceEncoding&amp;gt;UTF-8&amp;lt;/project.build.sourceEncoding&amp;gt;
      &amp;lt;project.reporting.outputEncoding&amp;gt;UTF-8&amp;lt;/project.reporting.outputEncoding&amp;gt;
-     &amp;lt;camel.version&amp;gt;2.13.1&amp;lt;/camel.version&amp;gt;
-     &amp;lt;cxf.version&amp;gt;2.7.11&amp;lt;/cxf.version&amp;gt;
-     &amp;lt;spring.version&amp;gt;3.2.8.RELEASE&amp;lt;/spring.version&amp;gt;
+     &amp;lt;camel.version&amp;gt;2.14-SNAPSHOT&amp;lt;/camel.version&amp;gt;
+     &amp;lt;cxf.version&amp;gt;3.0.0&amp;lt;/cxf.version&amp;gt;
+     &amp;lt;spring.version&amp;gt;4.0.5.RELEASE&amp;lt;/spring.version&amp;gt;
    &amp;lt;/properties&amp;gt;
...
+      &amp;lt;!-- upgrade camel-spring dependencies --&amp;gt;
+      &amp;lt;dependency&amp;gt;
+         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
+         &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
+         &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;
+      &amp;lt;/dependency&amp;gt;
+      &amp;lt;dependency&amp;gt;
+         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
+         &amp;lt;artifactId&amp;gt;spring-aop&amp;lt;/artifactId&amp;gt;
+         &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;
+      &amp;lt;/dependency&amp;gt;
+      &amp;lt;dependency&amp;gt;
+         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
+         &amp;lt;artifactId&amp;gt;spring-tx&amp;lt;/artifactId&amp;gt;
+         &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;
+      &amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;I also had to change some imports for CXF 3.0 since it &lt;a href=&quot;http://cxf.apache.org/docs/30-migration-guide.html&quot;&gt;
    includes a new major version of Apache WSS4J (2.0.0)&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;brush: diff&quot;&gt;
-import org.apache.ws.security.handler.WSHandlerConstants;
+import org.apache.wss4j.dom.handler.WSHandlerConstants;
...
-import org.apache.ws.security.WSPasswordCallback;
+import org.apache.wss4j.common.ext.WSPasswordCallback;
&lt;/pre&gt;
&lt;p&gt;After getting everything upgraded, I continued developing services for the next couple weeks.&lt;/p&gt;
&lt;h3 id=&quot;spring-boot&quot;&gt;Spring Boot&lt;/h3&gt;
&lt;p&gt;In late July, I integrated Spring Boot. It was fairly straightforward and mostly consisted of adding/removing
    dependencies and removing versions already defined in Boot&apos;s starter-parent.
&lt;/p&gt;
&lt;pre class=&quot;brush: diff&quot;&gt;
+   &amp;lt;parent&amp;gt;
+      &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
+      &amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;
+      &amp;lt;version&amp;gt;1.1.4.RELEASE&amp;lt;/version&amp;gt;
+   &amp;lt;/parent&amp;gt;
...
       &amp;lt;cxf.version&amp;gt;3.0.1&amp;lt;/cxf.version&amp;gt;
+      &amp;lt;java.version&amp;gt;1.7&amp;lt;/java.version&amp;gt;
+      &amp;lt;servlet-api.version&amp;gt;3.1.0&amp;lt;/servlet-api.version&amp;gt;
       &amp;lt;spring.version&amp;gt;4.0.6.RELEASE&amp;lt;/spring.version&amp;gt;
...
-            &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;
-            &amp;lt;version&amp;gt;2.5.1&amp;lt;/version&amp;gt;
-            &amp;lt;configuration&amp;gt;
-               &amp;lt;source&amp;gt;1.7&amp;lt;/source&amp;gt;
-               &amp;lt;target&amp;gt;1.7&amp;lt;/target&amp;gt;
-            &amp;lt;/configuration&amp;gt;
-         &amp;lt;/plugin&amp;gt;
-         &amp;lt;plugin&amp;gt;
-            &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
             &amp;lt;artifactId&amp;gt;maven-resources-plugin&amp;lt;/artifactId&amp;gt;
          &amp;lt;/plugin&amp;gt;
+         &amp;lt;plugin&amp;gt;
+            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
+            &amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;
+         &amp;lt;/plugin&amp;gt;
       &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;

    &amp;lt;dependencies&amp;gt;
+      &amp;lt;!-- spring boot --&amp;gt;
+      &amp;lt;dependency&amp;gt;
+         &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
+         &amp;lt;artifactId&amp;gt;spring-boot-starter-actuator&amp;lt;/artifactId&amp;gt;
+         &amp;lt;exclusions&amp;gt;
+            &amp;lt;exclusion&amp;gt;
+               &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
+               &amp;lt;artifactId&amp;gt;spring-boot-starter-logging&amp;lt;/artifactId&amp;gt;
+            &amp;lt;/exclusion&amp;gt;
+         &amp;lt;/exclusions&amp;gt;
+      &amp;lt;/dependency&amp;gt;
+      &amp;lt;dependency&amp;gt;
+         &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
+         &amp;lt;artifactId&amp;gt;spring-boot-starter-log4j&amp;lt;/artifactId&amp;gt;
+      &amp;lt;/dependency&amp;gt;
+      &amp;lt;dependency&amp;gt;
+         &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
+         &amp;lt;artifactId&amp;gt;spring-boot-starter-tomcat&amp;lt;/artifactId&amp;gt;
+         &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
+      &amp;lt;/dependency&amp;gt;
+      &amp;lt;dependency&amp;gt;
+         &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
+         &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
+      &amp;lt;/dependency&amp;gt;
       &amp;lt;!-- camel --&amp;gt;
...
-      &amp;lt;!-- upgrade camel-spring dependencies --&amp;gt;
-      &amp;lt;dependency&amp;gt;
-         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
-         &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
-         &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;
-      &amp;lt;/dependency&amp;gt;
-      &amp;lt;dependency&amp;gt;
-         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
-         &amp;lt;artifactId&amp;gt;spring-aop&amp;lt;/artifactId&amp;gt;
-         &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;
-      &amp;lt;/dependency&amp;gt;
-      &amp;lt;dependency&amp;gt;
-         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
-         &amp;lt;artifactId&amp;gt;spring-tx&amp;lt;/artifactId&amp;gt;
-         &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;
-      &amp;lt;/dependency&amp;gt;
...
-      &amp;lt;!-- logging --&amp;gt;
-      &amp;lt;dependency&amp;gt;
-         &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;
-         &amp;lt;artifactId&amp;gt;slf4j-api&amp;lt;/artifactId&amp;gt;
-         &amp;lt;version&amp;gt;1.7.6&amp;lt;/version&amp;gt;
-      &amp;lt;/dependency&amp;gt;
-      &amp;lt;dependency&amp;gt;
-         &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;
-         &amp;lt;artifactId&amp;gt;slf4j-log4j12&amp;lt;/artifactId&amp;gt;
-         &amp;lt;version&amp;gt;1.7.6&amp;lt;/version&amp;gt;
-      &amp;lt;/dependency&amp;gt;
-      &amp;lt;dependency&amp;gt;
-         &amp;lt;groupId&amp;gt;log4j&amp;lt;/groupId&amp;gt;
-         &amp;lt;artifactId&amp;gt;log4j&amp;lt;/artifactId&amp;gt;
-         &amp;lt;version&amp;gt;1.2.17&amp;lt;/version&amp;gt;
-      &amp;lt;/dependency&amp;gt;
-
       &amp;lt;!-- utilities --&amp;gt;
       &amp;lt;dependency&amp;gt;
          &amp;lt;groupId&amp;gt;joda-time&amp;lt;/groupId&amp;gt;
          &amp;lt;artifactId&amp;gt;joda-time&amp;lt;/artifactId&amp;gt;
-         &amp;lt;version&amp;gt;2.3&amp;lt;/version&amp;gt;
       &amp;lt;/dependency&amp;gt;
       &amp;lt;dependency&amp;gt;
          &amp;lt;groupId&amp;gt;commons-dbcp&amp;lt;/groupId&amp;gt;
          &amp;lt;artifactId&amp;gt;commons-dbcp&amp;lt;/artifactId&amp;gt;
-         &amp;lt;version&amp;gt;1.4&amp;lt;/version&amp;gt;
...
       &amp;lt;!-- testing --&amp;gt;
       &amp;lt;dependency&amp;gt;
+         &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
+         &amp;lt;artifactId&amp;gt;spring-boot-starter-test&amp;lt;/artifactId&amp;gt;
+         &amp;lt;exclusions&amp;gt;
+            &amp;lt;exclusion&amp;gt;
+               &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
+               &amp;lt;artifactId&amp;gt;spring-boot-starter-logging&amp;lt;/artifactId&amp;gt;
+            &amp;lt;/exclusion&amp;gt;
+         &amp;lt;/exclusions&amp;gt;
+      &amp;lt;/dependency&amp;gt;
+      &amp;lt;dependency&amp;gt;
-      &amp;lt;dependency&amp;gt;
-         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
-         &amp;lt;artifactId&amp;gt;spring-test&amp;lt;/artifactId&amp;gt;
-         &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;
-         &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
-      &amp;lt;/dependency&amp;gt;
-      &amp;lt;dependency&amp;gt;
-         &amp;lt;groupId&amp;gt;org.mockito&amp;lt;/groupId&amp;gt;
-         &amp;lt;artifactId&amp;gt;mockito-core&amp;lt;/artifactId&amp;gt;
-         &amp;lt;version&amp;gt;1.9.5&amp;lt;/version&amp;gt;
-         &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
-      &amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Next, I deleted the &lt;code&gt;AppInitializer.java&lt;/code&gt; class I mentioned in
    &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_services_with_apache_camel1&quot;&gt;Part II&lt;/a&gt; and added an
    &lt;code&gt;Application.java&lt;/code&gt; class.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.ErrorPage;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;

@Configuration
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,
        DataSourceTransactionManagerAutoConfiguration.class})
@ComponentScan
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        CXFServlet servlet = new CXFServlet();
        return new ServletRegistrationBean(servlet, &quot;/api/*&quot;);
    }

    @Bean
    public EmbeddedServletContainerCustomizer containerCustomizer() {
        return new EmbeddedServletContainerCustomizer() {
            @Override
            public void customize(ConfigurableEmbeddedServletContainer container) {
                ErrorPage error401Page = new ErrorPage(HttpStatus.UNAUTHORIZED, &quot;/401.html&quot;);
                ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, &quot;/404.html&quot;);
                ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, &quot;/500.html&quot;);
                container.addErrorPages(error401Page, error404Page, error500Page);
            }
        };
    }
}
&lt;/pre&gt;
&lt;p&gt;
    The error pages you see configured above were configured and copied from Tim Sporcic&apos;s
    &lt;a href=&quot;http://sporcic.org/2014/05/custom-error-pages-with-spring-boot/&quot;&gt;Custom Error Pages with Spring Boot&lt;/a&gt;.
&lt;/p&gt;
&lt;h4 id=&quot;dynamic-datasources&quot;&gt;Dynamic DataSources&lt;/h4&gt;
&lt;p&gt;I excluded the DataSource-related AutoConfiguration classes because this application had many datasources.
It also had a requirement to allow datasources to be added on-the-fly by simply editing application.properties.
I &lt;a href=&quot;http://stackoverflow.com/questions/25160221/how-do-i-create-beans-programmatically-in-spring-boot/25160828&quot;&gt;
asked how to do this on Stack Overflow&lt;/a&gt; and received an &lt;a href=&quot;http://stackoverflow.com/a/25160828/65681&quot;&gt;excellent
    answer&lt;/a&gt; from &lt;a href=&quot;http://stackoverflow.com/users/613628/st%C3%A9phane-nicoll&quot;&gt;St&#233;phane Nicoll&lt;/a&gt;.
&lt;/p&gt;
&lt;h4 id=&quot;spring-boot-issues&quot;&gt;Spring Boot Issues&lt;/h4&gt;
&lt;p&gt;
    I did encounter a couple issues after integrating Spring Boot. The first was that &lt;a href=&quot;https://github.com/spring-projects/spring-boot/issues/1316&quot;&gt;
    it was removing the content-* headers for CXF responses&lt;/a&gt;. This only happened when running the WAR in Tomcat and I
    was able to figure out a workaround with a custom ResponseWrapper and Filter. This issue was fixed in Spring Boot 1.1.6.
&lt;/p&gt;
&lt;p&gt;The other issue was that the property override feature didn&apos;t seem to work when setting environment variables. The workaround
was to create a &lt;code&gt;setenv.sh&lt;/code&gt; script in $CATALINA_HOME/bin and add the environment variables there. See section 3.4
of &lt;a href=&quot;http://tomcat.apache.org/tomcat-7.0-doc/RUNNING.txt&quot;&gt;Tomcat 7&apos;s RUNNING.txt&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h4 id=&quot;soap-faults&quot;&gt;SOAP Faults&lt;/h4&gt;
&lt;p&gt;
    After upgrading to Spring 4 and integrating Spring Boot, I continued migrating IBM Message Broker flows. My goal
    was to make all new services backward compatible, but I ran into an issue. With the new services, SOAP Faults were
    sent back to the client instead of error messages in a SOAP Message. I suggested we fix it with one of two ways:
&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Modify the client so it looks for SOAP Faults and handles them appropriately.&lt;/li&gt;
    &lt;li&gt;Modify the new services so messages are returned instead of faults.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For #2, I learned how do to &lt;a href=&quot;http://camel.465427.n5.nabble.com/Convert-from-Fault-to-Message-td5754465.html&quot;&gt;convert from a fault to messages&lt;/a&gt;
on the Camel user mailing list. However, the team opted to improve the client and we added fault handling there instead.&lt;/p&gt;


&lt;h3 id=&quot;microservices&quot;&gt;Microservice Deployment&lt;/h3&gt;
&lt;p&gt;When I first integrated Spring Boot, I was planning on splitting our project into a project-per-service.
    This would allow each service to evolve on its own, instead of having a monolithic war that contains all the services.
    In team discussions, there was some concern about the memory overhead of running multiple instances instead of one.
    &lt;/p&gt;
&lt;p&gt;
    I pointed out an &lt;a href=&quot;http://camel.465427.n5.nabble.com/one-context-or-multiple-contexts-td5754635.html&quot;&gt;interesting thread&lt;/a&gt;
    on the Camel mailing list about deploying routes with a route-per-jvm or all in the same JVM.
    The recommendation from that thread was to bundle similar routes together if you were to split them.&lt;/p&gt;
&lt;p&gt;In the end, we decided to allow our Operations team decide how they wanted to manage/deploy everything. I mentioned that
    Spring Boot can work with &lt;a href=&quot;http://spring.io/blog/2014/03/07/deploying-spring-boot-applications&quot;&gt;
        Tomcat, Jetty, JBoss and even cloud providers like Heroku and Cloud Foundry&lt;/a&gt;. I estimated that splitting the project
    apart would take less than a day, as would making it back into a monolithic WAR.
&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;This article explains how we upgraded our Apache Camel application to Spring 4 and integrated Spring Boot. There was
    a bit of pain getting things to work, but nothing a few pull requests and workarounds couldn&apos;t fix. We discovered
    some issues with setting environment variables for Tomcat and opted not to split our project into small microservices.
    Hopefully this article will help people trying to &lt;a href=&quot;http://stackoverflow.com/questions/25775418/camelize-a-spring-boot-application&quot;&gt;
        Camelize a Spring Boot application
    &lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;//raibledesigns.com/rd/entry/developing_services_with_apache_camel3&quot;&gt;next article&lt;/a&gt;, I&apos;ll talk about load testing with &lt;a href=&quot;http://gatling.io&quot;&gt;Gatling&lt;/a&gt;, logging with
    &lt;a href=&quot;http://www.infoq.com/news/2014/07/apache-log4j2&quot;&gt;Log4j2&lt;/a&gt; and monitoring with
    &lt;a href=&quot;http://hawt.io/&quot;&gt;hawtio&lt;/a&gt; and &lt;a href=&quot;http://newrelic.com/&quot;&gt;New Relic&lt;/a&gt;. &lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/developing_services_with_apache_camel1</id>
        <title type="html">Developing Services with Apache Camel - Part II: Creating and Testing Routes</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/developing_services_with_apache_camel1"/>
        <published>2014-09-30T10:05:38-06:00</published>
        <updated>2014-10-15T19:00:16-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="junit" scheme="http://roller.apache.org/ns/tags/" />
        <category term="testing" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <category term="apachecamel" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="microservices" scheme="http://roller.apache.org/ns/tags/" />
        <category term="camel" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jenkins" scheme="http://roller.apache.org/ns/tags/" />
        <summary type="html">&lt;p&gt;
    &lt;a href=&quot;http://camel.apache.org&quot;&gt;&lt;img src=&quot;http://camel.apache.org/images/camel-box-small.png&quot; height=&quot;150&quot;
                                           alt=&quot;Apache Camel&quot; class=&quot;picture&quot;&gt;&lt;/a&gt;
    This article is the second in a series on Apache Camel and how I used it to replace IBM Message Broker for a client.
    The first article, &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_services_with_apache_camel&quot;&gt;
    Developing Services with Apache Camel - Part I: The Inspiration&lt;/a&gt;, describes why I chose Camel for this project.
&lt;/p&gt;

&lt;p&gt;

&lt;p&gt;To make sure these new services correctly replaced existing services, a 3-step approach was used:&lt;/p&gt;
&lt;ol class=&quot;task-list&quot;&gt;
    &lt;li&gt;Write an integration test pointing to the old service.&lt;/li&gt;
    &lt;li&gt;Write the implementation and a unit test to prove it works.&lt;/li&gt;
    &lt;li&gt;Write an integration test pointing to the new service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
    I chose to start by replacing the simplest service first. It was a SOAP Service that talked to a database to
    retrieve
    a value based on an input parameter. To learn more about Camel and how it works, I started by looking at the
    &lt;a href=&quot;http://camel.apache.org/cxf-tomcat-example.html&quot;&gt;CXF Tomcat Example&lt;/a&gt;. I learned that
    Camel is used to provide &lt;em&gt;routing&lt;/em&gt; of requests. Using its &lt;a href=&quot;http://camel.apache.org/cxf.html&quot;&gt;CXF
    component&lt;/a&gt;, it can easily produce SOAP web service
    endpoints. An end point is simply an interface, and Camel takes care of producing the implementation.
&lt;/p&gt;</summary>
        <content type="html">&lt;p&gt;
    &lt;a href=&quot;http://camel.apache.org&quot;&gt;&lt;img src=&quot;http://camel.apache.org/images/camel-box-small.png&quot; height=&quot;150&quot;
                                           alt=&quot;Apache Camel&quot; class=&quot;picture&quot;&gt;&lt;/a&gt;
    This article is the second in a series on Apache Camel and how I used it to replace IBM Message Broker for a client.
    The first article, &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_services_with_apache_camel&quot;&gt;
    Developing Services with Apache Camel - Part I: The Inspiration&lt;/a&gt;, describes why I chose Camel for this project.
&lt;/p&gt;

&lt;p&gt;

&lt;p&gt;To make sure these new services correctly replaced existing services, a 3-step approach was used:&lt;/p&gt;
&lt;ol class=&quot;task-list&quot;&gt;
    &lt;li&gt;Write an integration test pointing to the old service.&lt;/li&gt;
    &lt;li&gt;Write the implementation and a unit test to prove it works.&lt;/li&gt;
    &lt;li&gt;Write an integration test pointing to the new service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
    I chose to start by replacing the simplest service first. It was a SOAP Service that talked to a database to
    retrieve
    a value based on an input parameter. To learn more about Camel and how it works, I started by looking at the
    &lt;a href=&quot;http://camel.apache.org/cxf-tomcat-example.html&quot;&gt;CXF Tomcat Example&lt;/a&gt;. I learned that
    Camel is used to provide &lt;em&gt;routing&lt;/em&gt; of requests. Using its &lt;a href=&quot;http://camel.apache.org/cxf.html&quot;&gt;CXF
    component&lt;/a&gt;, it can easily produce SOAP web service
    endpoints. An end point is simply an interface, and Camel takes care of producing the implementation.
&lt;/p&gt;

&lt;h3 id=&quot;legacy-integration-test&quot;&gt;Legacy Integration Test&lt;/h3&gt;

&lt;p&gt;I started by writing a &lt;code&gt;LegacyDrugServiceTests&lt;/code&gt; integration test for the old drug service.
    I tried two different ways of testing, using WSDL-generated Java classes, as well as using JAX-WS&apos;s SOAP API.
    Finding the WSDL for the legacy service was difficult because IBM Message Broker doesn&apos;t expose it when adding
    &quot;?wsdl&quot; to the service&apos;s URL. Instead, I had to dig through the project files until I found it. Then I
    used the &lt;a href=&quot;http://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html&quot;&gt;cxf-codegen-plugin&lt;/a&gt;
    to generate the web service client. Below is what one of the tests looked like that uses the JAX-WS API.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Test
public void sendGPIRequestUsingSoapApi() throws Exception {
    SOAPElement bodyChildOne = getBody(message).addChildElement(&quot;gpiRequest&quot;, &quot;m&quot;);
    SOAPElement bodyChildTwo = bodyChildOne.addChildElement(&quot;args0&quot;, &quot;m&quot;);
    bodyChildTwo.addChildElement(&quot;NDC&quot;, &quot;ax22&quot;).addTextNode(&quot;54561237201&quot;);
    SOAPMessage reply = connection.call(message, getUrlWithTimeout(SERVICE_NAME));
    if (reply != null) {
        Iterator itr = reply.getSOAPBody().getChildElements();
        Map resultMap = TestUtils.getResults(itr);
        assertEquals(&quot;66100525123130&quot;, resultMap.get(&quot;GPI&quot;));
    }
}
&lt;/pre&gt;
&lt;h3 id=&quot;implementation&quot;&gt;Implementing the Drug Service&lt;/h3&gt;

&lt;p&gt;In the last article, I mentioned I wanted no XML in the project. To facilitate this, I used Camel&apos;s
    &lt;a href=&quot;http://camel.apache.org/java-dsl.html&quot;&gt;Java DSL&lt;/a&gt; to define routes and Spring&apos;s
    &lt;a href=&quot;http://docs.spring.io/spring/docs/4.0.6.RELEASE/spring-framework-reference/htmlsingle/#beans-java&quot;&gt;JavaConfig&lt;/a&gt;
    to configure dependencies.
&lt;/p&gt;

&lt;p&gt;The first route I wrote was one that looked up a GPI (Generic Product Identifier) by NDC (National Drug Code).&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@WebService
public interface DrugService {
    @WebMethod(operationName = &quot;gpiRequest&quot;)
    GpiResponse findGpiByNdc(GpiRequest request);
}
&lt;/pre&gt;
&lt;p&gt;
    To expose this as a web service endpoint with CXF, I needed to do two things:
&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Tell Spring how to configure CXF by importing &quot;classpath:META-INF/cxf/cxf.xml&quot; into a @Configuration class.&lt;/li&gt;
    &lt;li&gt;Configure CXF&apos;s Servlet so endpoints can be served up at a particular URL.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To satisfy item #1, I created a &lt;code&gt;CamelConfig&lt;/code&gt; class that extends &lt;a
        href=&quot;http://camel.apache.org/maven/camel-2.14.0/camel-spring-javaconfig/apidocs/org/apache/camel/spring/javaconfig/CamelConfiguration.html&quot;&gt;CamelConfiguration&lt;/a&gt;.
    This class allows Camel to be configured by Spring&apos;s JavaConfig. In it, I imported the CXF configuration, allowed
    tracing to be
    configured dynamically, and exposed my &lt;code&gt;application.properties&lt;/code&gt; to Camel. I also set it up (with &lt;code&gt;@ComponentScan&lt;/code&gt;)
    to look
    for Camel routes annotated with &lt;code&gt;@Component&lt;/code&gt;.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Configuration
@ImportResource(&quot;classpath:META-INF/cxf/cxf.xml&quot;)
@ComponentScan(&quot;com.raibledesigns.camel&quot;)
public class CamelConfig extends CamelConfiguration {
    @Value(&quot;${logging.trace.enabled}&quot;)
    private Boolean tracingEnabled;

    @Override
    protected void setupCamelContext(CamelContext camelContext) throws Exception {
        PropertiesComponent pc = new PropertiesComponent();
        pc.setLocation(&quot;classpath:application.properties&quot;);
        camelContext.addComponent(&quot;properties&quot;, pc);
        // see if trace logging is turned on
        if (tracingEnabled) {
            camelContext.setTracing(true);
        }
        super.setupCamelContext(camelContext);
    }

    @Bean
    public Tracer camelTracer() {
        Tracer tracer = new Tracer();
        tracer.setTraceExceptions(false);
        tracer.setTraceInterceptors(true);
        tracer.setLogName(&quot;com.raibledesigns.camel.trace&quot;);
        return tracer;
    }
}
&lt;/pre&gt;
&lt;p&gt;CXF has a servlet that&apos;s responsible for serving up its services at common path. To map CXF&apos;s servlet, I leveraged
    Spring&apos;s
    &lt;a href=&quot;http://docs.spring.io/autorepo/docs/spring-framework/4.0.x/javadoc-api/org/springframework/web/WebApplicationInitializer.html&quot;&gt;
        WebApplicationInitializer&lt;/a&gt; in an &lt;code&gt;AppInitializer&lt;/code&gt; class. I decided to serve up everything from a
    &lt;code&gt;/api/*&lt;/code&gt; base URL.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
package com.raibledesigns.camel.config;

import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class AppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        servletContext.addListener(new ContextLoaderListener(getContext()));
        ServletRegistration.Dynamic servlet = servletContext.addServlet(&quot;CXFServlet&quot;, new CXFServlet());
        servlet.setLoadOnStartup(1);
        servlet.setAsyncSupported(true);
        servlet.addMapping(&quot;/api/*&quot;);
    }

    private AnnotationConfigWebApplicationContext getContext() {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.setConfigLocation(&quot;com.raibledesigns.camel.config&quot;);
        return context;
    }
}
&lt;/pre&gt;
&lt;p&gt;
    To implement this web service with Camel, I created a &lt;code&gt;DrugRoute&lt;/code&gt; class that extends Camel&apos;s
    &lt;code&gt;RouteBuilder&lt;/code&gt;.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Component
public class DrugRoute extends RouteBuilder {
    private String uri = &quot;cxf:/drugs?serviceClass=&quot; + DrugService.class.getName();

    @Override
    public void configure() throws Exception {
        from(uri)
            .recipientList(simple(&quot;direct:${header.operationName}&quot;));
        from(&quot;direct:gpiRequest&quot;).routeId(&quot;gpiRequest&quot;)
            .process(new Processor() {
                public void process(Exchange exchange) throws Exception {
                    // get the ndc from the input
                    String ndc = exchange.getIn().getBody(GpiRequest.class).getNDC();
                    exchange.getOut().setBody(ndc);
                }
            })
            .to(&quot;sql:{{sql.selectGpi}}&quot;)
            .to(&quot;log:output&quot;)
            .process(new Processor() {
                public void process(Exchange exchange) throws Exception {
                    // get the gpi from the input
                    List&amp;lt;HashMap&amp;gt; data = (ArrayList&amp;lt;HashMap&amp;gt;) exchange.getIn().getBody();
                    DrugInfo drug = new DrugInfo();
                    if (data.size() &amp;gt; 0) {
                        drug = new DrugInfo(String.valueOf(data.get(0).get(&quot;GPI&quot;)));
                    }
                    GpiResponse response = new GpiResponse(drug);
                    exchange.getOut().setBody(response);
                }
            });
    }
}
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;sql.selectGpi&lt;/code&gt; property is read from &lt;code&gt;src/main/resources/application.properties&lt;/code&gt; and looks
    as follows:&lt;/p&gt;
&lt;pre&gt;sql.selectGpi=select GPI from drugs where ndc = #?dataSource=ds.drugs&lt;/pre&gt;
&lt;p&gt;The &quot;ds.drugs&quot; reference is to a datasource that&apos;s created by Spring. From my
    &lt;code&gt;AppConfig&lt;/code&gt; class:&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Configuration
@PropertySource(&quot;classpath:application.properties&quot;)
public class AppConfig {

    @Value(&quot;${ds.driver.db2}&quot;)
    private String jdbcDriverDb2;

    @Value(&quot;${ds.password}&quot;)
    private String jdbcPassword;

    @Value(&quot;${ds.url}&quot;)
    private String jdbcUrl;

    @Value(&quot;${ds.username}&quot;)
    private String jdbcUsername;

    @Bean(name = &quot;ds.drugs&quot;)
    public DataSource drugsDataSource() {
        return createDataSource(jdbcDriverDb2, jdbcUsername, jdbcPassword, jdbcUrl);
    }

    private BasicDataSource createDataSource(String driver, String username, String password, String url) {
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName(driver);
        ds.setUsername(username);
        ds.setPassword(password);
        ds.setUrl(url);
        ds.setMaxActive(100);
        ds.setMaxWait(1000);
        ds.setPoolPreparedStatements(true);
        return ds;
    }
}
&lt;/pre&gt;

&lt;h3 id=&quot;unit-testing&quot;&gt;Unit Testing&lt;/h3&gt;

&lt;p&gt;
    The hardest part about unit testing this route was figuring out how to use Camel&apos;s
    &lt;a href=&quot;http://camel.apache.org/testing.html&quot;&gt;testing support&lt;/a&gt;. I posted
    &lt;a href=&quot;http://camel.465427.n5.nabble.com/Mocking-SQL-results-in-a-route-td5752169.html&quot;&gt;a question&lt;/a&gt; to the
    Camel users mailing list in early June. Based on advice received, I bought
    &lt;a href=&quot;http://www.manning.com/ibsen/&quot;&gt;Camel in Action&lt;/a&gt;, read chapter 6 on testing and went to work.
    I wanted to eliminate the dependency on a datasource, so I used Camel&apos;s
    &lt;a href=&quot;http://camel.apache.org/advicewith.html&quot;&gt;AdviceWith&lt;/a&gt; feature to modify my route and intercept the
    SQL call. This allowed me to return pre-defined results and verify everything worked.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@RunWith(CamelSpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = CamelSpringDelegatingTestContextLoader.class, classes = CamelConfig.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@UseAdviceWith
public class DrugRouteTests {

    @Autowired
    CamelContext camelContext;

    @Produce
    ProducerTemplate template;

    @EndpointInject(uri = &quot;mock:result&quot;)
    MockEndpoint result;

    static List&amp;lt;Map&amp;gt; results = new ArrayList&amp;lt;Map&amp;gt;() {{
        add(new HashMap&amp;lt;String, String&amp;gt;() {{
            put(&quot;GPI&quot;, &quot;123456789&quot;);
        }});
    }};

    @Before
    public void before() throws Exception {
        camelContext.setTracing(true);

        ModelCamelContext context = (ModelCamelContext) camelContext;
        RouteDefinition route = context.getRouteDefinition(&quot;gpiRequest&quot;);
        route.adviceWith(context, new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                interceptSendToEndpoint(&quot;sql:*&quot;).skipSendToOriginalEndpoint().process(new Processor() {
                    @Override
                    public void process(Exchange exchange) throws Exception {
                        exchange.getOut().setBody(results);
                    }
                });
            }
        });
        route.to(result);
        camelContext.start();
    }

    @Test
    public void testMockSQLEndpoint() throws Exception {
        result.expectedMessageCount(1);
        GpiResponse expectedResult = new GpiResponse(new DrugInfo(&quot;123456789&quot;));
        result.allMessages().body().contains(expectedResult);

        GpiRequest request = new GpiRequest();
        request.setNDC(&quot;123&quot;);
        template.sendBody(&quot;direct:gpiRequest&quot;, request);

        MockEndpoint.assertIsSatisfied(camelContext);
    }
}
&lt;/pre&gt;
&lt;p&gt;
    I found AdviceWith to be extremely useful as I developed more routes and tests in this project. I used its
    &lt;a href=&quot;http://camel.apache.org/advicewith.html#AdviceWith-UsingweaveById&quot;&gt;weaveById&lt;/a&gt; feature to intercept
    calls to stored procedures, replace steps in my routes and remove steps I didn&apos;t want to test. For example,
    in one route, there was a complicated workflow to interact with a customer&apos;s data.
&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Call a stored procedure in a remote database, which then inserts a record into a temp table.&lt;/li&gt;
    &lt;li&gt;Lookup that data using the value returned from the stored procedure.&lt;/li&gt;
    &lt;li&gt;Delete the record from the temp table.&lt;/li&gt;
    &lt;li&gt;Parse the data (as CSV) since the returned value is ~ delimited.&lt;/li&gt;
    &lt;li&gt;Convert the parsed data into objects, then do database inserts in a local database (if data doesn&apos;t exist).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To make matters worse, remote database access was restricted by IP address. This meant that, while developing, I
    couldn&apos;t
    even manually test from my local machine. To solve this, I used the following:
&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;code&gt;interceptSendToEndpoint(&quot;bean:*&quot;)&lt;/code&gt; to intercept the call to my stored procedure bean.&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;weaveById(&quot;myJdbcProcessor&quot;).before()&lt;/code&gt; to replace the temp table lookup with a CSV file.&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://code.google.com/p/mockito/&quot;&gt;Mockito&lt;/a&gt; to mock a JdbcTemplate that does the inserts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
    To figure out how to configure and execute stored procedures in a route, I used the &lt;a
        href=&quot;https://github.com/quephird/camel-stored-procedure&quot;&gt;
    camel-store-procedure project on GitHub&lt;/a&gt;. Mockito&apos;s
    &lt;a href=&quot;http://docs.mockito.googlecode.com/hg/org/mockito/ArgumentCaptor.html&quot;&gt;ArgumentCaptor&lt;/a&gt; also became very
    useful
    when developing a route that called a 3rd-party web service within a route. James Carr has
    &lt;a href=&quot;http://blog.james-carr.org/2009/09/28/mockito-verifying-details-of-an-object-passed-to-a-collaborator/&quot;&gt;more
        information&lt;/a&gt;
    on how you might use this to verify values on an argument.
&lt;/p&gt;

&lt;p&gt;
    To see if my tests were hitting all aspects of the code, I integrated the
    &lt;a href=&quot;http://mojo.codehaus.org/cobertura-maven-plugin/&quot;&gt;cobertura-maven-plugin&lt;/a&gt; for code coverage
    reports (generated by running &lt;code&gt;mvn site&lt;/code&gt;).
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;build&amp;gt;
    &amp;lt;plugins&amp;gt;
        &amp;lt;plugin&amp;gt;
            &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;cobertura-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;configuration&amp;gt;
                &amp;lt;instrumentation&amp;gt;
                    &amp;lt;excludes&amp;gt;
                        &amp;lt;exclude&amp;gt;**/model/*.class&amp;lt;/exclude&amp;gt;
                        &amp;lt;exclude&amp;gt;**/AppInitializer.class&amp;lt;/exclude&amp;gt;
                        &amp;lt;exclude&amp;gt;**/StoredProcedureBean.class&amp;lt;/exclude&amp;gt;
                        &amp;lt;exclude&amp;gt;**/SoapActionInterceptor.class&amp;lt;/exclude&amp;gt;
                    &amp;lt;/excludes&amp;gt;
                &amp;lt;/instrumentation&amp;gt;
                &amp;lt;check/&amp;gt;
            &amp;lt;/configuration&amp;gt;
            &amp;lt;version&amp;gt;2.6&amp;lt;/version&amp;gt;
        &amp;lt;/plugin&amp;gt;
...
&amp;lt;reporting&amp;gt;
    &amp;lt;plugins&amp;gt;
        &amp;lt;plugin&amp;gt;
            &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;cobertura-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;2.6&amp;lt;/version&amp;gt;
        &amp;lt;/plugin&amp;gt;
&lt;/pre&gt;
&lt;h3 id=&quot;integration-testing&quot;&gt;Integration Testing&lt;/h3&gt;

&lt;p&gt;
    Writing an integration test was fairly straightforward. I created a &lt;code&gt;DrugRouteITest&lt;/code&gt; class, a
    client using CXF&apos;s &lt;a href=&quot;https://cxf.apache.org/javadoc/latest/org/apache/cxf/jaxws/JaxWsProxyFactoryBean.html&quot;&gt;JaxWsProxyFactoryBean&lt;/a&gt;
    and called the method on the service.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public class DrugRouteITest {

    private static final String URL = &quot;http://localhost:8080/api/drugs&quot;;

    protected static DrugService createCXFClient() {
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setBindingId(&quot;http://schemas.xmlsoap.org/wsdl/soap12/&quot;);
        factory.setServiceClass(DrugService.class);
        factory.setAddress(getTestUrl(URL));
        return (DrugService) factory.create();
    }

    @Test
    public void findGpiByNdc() throws Exception {
        // create input parameter
        GpiRequest input = new GpiRequest();
        input.setNDC(&quot;54561237201&quot;);

        // create the webservice client and send the request
        DrugService client = createCXFClient();
        GpiResponse response = client.findGpiByNdc(input);

        assertEquals(&quot;66100525123130&quot;, response.getDrugInfo().getGPI());
    }
}
&lt;/pre&gt;
&lt;p&gt;This integration test is only run after Tomcat has started and deployed the app. Unit tests are run by Maven&apos;s
    &lt;a href=&quot;http://maven.apache.org/surefire/maven-surefire-plugin/&quot;&gt;surefire-plugin&lt;/a&gt;, while integration tests are
    run by the &lt;a href=&quot;http://maven.apache.org/surefire/maven-failsafe-plugin/&quot;&gt;failsafe-plugin&lt;/a&gt;. An available
    Tomcat port is determined by the &lt;a href=&quot;http://mojo.codehaus.org/build-helper-maven-plugin/&quot;&gt;
        build-helper-maven-plugin&lt;/a&gt;. This port is set as a system property and read by the &lt;code&gt;getTestUrl()&lt;/code&gt;
    method call above.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
public static String getTestUrl(String url) {
    if (System.getProperty(&quot;tomcat.http.port&quot;) != null) {
        url = url.replace(&quot;8080&quot;, System.getProperty(&quot;tomcat.http.port&quot;));
    }
    return url;
}
&lt;/pre&gt;
&lt;p&gt;Below are the relevant bits from
    &lt;code&gt;pom.xml&lt;/code&gt; that determines when to start/stop Tomcat, as well as which tests to run. &lt;/p&gt;

&lt;p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;org.apache.tomcat.maven&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;tomcat7-maven-plugin&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;2.2&amp;lt;/version&amp;gt;
    &amp;lt;configuration&amp;gt;
        &amp;lt;path&amp;gt;/&amp;lt;/path&amp;gt;
    &amp;lt;/configuration&amp;gt;
    &amp;lt;executions&amp;gt;
        &amp;lt;execution&amp;gt;
            &amp;lt;id&amp;gt;start-tomcat&amp;lt;/id&amp;gt;
            &amp;lt;phase&amp;gt;pre-integration-test&amp;lt;/phase&amp;gt;
            &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;run&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
            &amp;lt;configuration&amp;gt;
                &amp;lt;fork&amp;gt;true&amp;lt;/fork&amp;gt;
                &amp;lt;port&amp;gt;${tomcat.http.port}&amp;lt;/port&amp;gt;
            &amp;lt;/configuration&amp;gt;
        &amp;lt;/execution&amp;gt;
        &amp;lt;execution&amp;gt;
            &amp;lt;id&amp;gt;stop-tomcat&amp;lt;/id&amp;gt;
            &amp;lt;phase&amp;gt;post-integration-test&amp;lt;/phase&amp;gt;
            &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;shutdown&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
        &amp;lt;/execution&amp;gt;
    &amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;maven-surefire-plugin&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;2.17&amp;lt;/version&amp;gt;
    &amp;lt;configuration&amp;gt;
        &amp;lt;excludes&amp;gt;
            &amp;lt;exclude&amp;gt;**/*IT*.java&amp;lt;/exclude&amp;gt;
            &amp;lt;exclude&amp;gt;**/Legacy**.java&amp;lt;/exclude&amp;gt;
        &amp;lt;/excludes&amp;gt;
        &amp;lt;includes&amp;gt;
            &amp;lt;include&amp;gt;**/*Tests.java&amp;lt;/include&amp;gt;
            &amp;lt;include&amp;gt;**/*Test.java&amp;lt;/include&amp;gt;
        &amp;lt;/includes&amp;gt;
    &amp;lt;/configuration&amp;gt;
&amp;lt;/plugin&amp;gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;maven-failsafe-plugin&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;2.17&amp;lt;/version&amp;gt;
    &amp;lt;configuration&amp;gt;
        &amp;lt;includes&amp;gt;
            &amp;lt;include&amp;gt;**/*IT*.java&amp;lt;/include&amp;gt;
        &amp;lt;/includes&amp;gt;
        &amp;lt;systemProperties&amp;gt;
            &amp;lt;tomcat.http.port&amp;gt;${tomcat.http.port}&amp;lt;/tomcat.http.port&amp;gt;
        &amp;lt;/systemProperties&amp;gt;
    &amp;lt;/configuration&amp;gt;
    &amp;lt;executions&amp;gt;
        &amp;lt;execution&amp;gt;
            &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;integration-test&amp;lt;/goal&amp;gt;
                &amp;lt;goal&amp;gt;verify&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
        &amp;lt;/execution&amp;gt;
    &amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The most useful part of integration testing came when I copied one of my legacy tests into it and started verifying
    backwards compatibility. Since we wanted to replace existing services, and require no client changes, I had to make
    the XML request and response match. &lt;a href=&quot;http://www.charlesproxy.com&quot;&gt;Charles&lt;/a&gt; was very useful for this
    exercise,
    letting me inspect the request/response and tweak things to match. The following JAX-WS annotations allowed me to
    change the XML
    element names and achieve backward compatibility.&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;code&gt;@BindingType(SOAPBinding.SOAP12HTTP_BINDING)&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;@WebResult(name = &quot;return&quot;, targetNamespace = &quot;...&quot;)&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;@ResponseWrapper(localName = &quot;gpiResponse&quot;)&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;@WebParam(name = &quot;args0&quot;, targetNamespace = &quot;...&quot;)&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;@XmlElement(name = &quot;...&quot;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;jenkins-and-continuous-deployment&quot;&gt;Continuous Integration and Deployment&lt;/h3&gt;

&lt;p&gt;My next item of business was configuring a job in &lt;a href=&quot;http://jenkins-ci.org/&quot;&gt;Jenkins&lt;/a&gt; to continually test
    and deploy. Getting all the tests to pass was easy, and deploying to Tomcat was simple enough thanks to the
    &lt;a href=&quot;https://wiki.jenkins-ci.org/display/JENKINS/Deploy+Plugin&quot;&gt;Deploy Plugin&lt;/a&gt; and
    &lt;a href=&quot;http://paxcel.net/blog/automation-of-warear-deployment-using-jenkins/&quot;&gt;this article&lt;/a&gt;. However, after a
    few deploys, Tomcat would throw OutOfMemory exceptions. Therefore, I ended up creating a second &quot;deploy&quot; job that
    stops Tomcat, copies the successfully-built WAR to $CATALINA_HOME/webapps, removes $CATALINA_HOME/webapps/ROOT and
    restarts Tomcat. I used Jenkins &quot;Execute shell&quot; feature to configure these three steps.
    I was pleased to find my &lt;a
            href=&quot;http://raibledesigns.com/tomcat/boot-howto.html&quot;&gt;&lt;code&gt;/etc/init.d/tomcat&lt;/code&gt;&lt;/a&gt;
    script still worked for starting Tomcat at boot time and providing convenient start/stop commands.
&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;

&lt;p&gt;
    This article shows you how I implemented and tested a simple Apache Camel route. The route described
    only does a simple database lookup, but you can see how Camel&apos;s testing support allows you to mock results and concentrate
    on developing your route logic. I found its testing framework very useful and not well documented, so hopefully this
    article helps to fix that. In the &lt;a href=&quot;http://raibledesigns.com/rd/entry/developing_services_with_apache_camel2&quot;&gt;next article&lt;/a&gt;, I&apos;ll talk about upgrading to Spring 4, integrating Spring Boot and
    our team&apos;s microservice deployment discussions.
&lt;/p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/fixing_xss_in_jsp_2</id>
        <title type="html">Fixing XSS in JSP 2</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/fixing_xss_in_jsp_2"/>
        <published>2011-02-28T14:08:46-07:00</published>
        <updated>2012-11-11T02:00:40-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jsp" scheme="http://roller.apache.org/ns/tags/" />
        <category term="xss" scheme="http://roller.apache.org/ns/tags/" />
        <category term="security" scheme="http://roller.apache.org/ns/tags/" />
        <category term="appsec" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Way back in 2007, I wrote about &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_frameworks_and_xss&quot;&gt;Java Web Frameworks and XSS&lt;/a&gt;. My main point was that JSP EL &lt;a href=&quot;http://www.sleberknight.com/blog/sleberkn/entry/20060721&quot;&gt;doesn&apos;t bother to handle XSS&lt;/a&gt;. &lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
Of course, the whole problem with JSP EL could be solved if Tomcat (and other containers) would allow a flag to turn on XML escaping by default. IMO, it&apos;s badly needed to make JSP-based webapps safe from XSS. &lt;/p&gt;
&lt;p&gt;A couple months later, I &lt;a href=&quot;http://raibledesigns.com/rd/entry/proposed_tomcat_enhancement_add_flag&quot;&gt;proposed a Tomcat enhancement to escape JSP&apos;s EL by default&lt;/a&gt;. I also entered an &lt;a href=&quot;http://issues.apache.org/bugzilla/show_bug.cgi?id=43497&quot;&gt;enhancement request&lt;/a&gt; for this feature and attached a patch. That issue has remained open and unfixed for 3 and 1/2 years. 
&lt;/p&gt;
&lt;p&gt;Yesterday, Chin Huang posted a handy-dandy &lt;a href=&quot;http://pukkaone.github.com/2011/01/03/jsp-cross-site-scripting-elresolver.html&quot;&gt;ELResolver that XML-escapes EL values&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I tried Chin&apos;s resolver in AppFuse today and it works as well as advertised. To do this, I copied his &lt;a href=&quot;https://github.com/pukkaone/webappenhance/tree/master/src/com/github/pukkaone/jsp&quot;&gt;EscapeXML*.java files&lt;/a&gt; into my project, changed the JSP API&apos;s Maven coordinates from javax.servlet:jsp-api:2.0 to javax.servlet.jsp:jsp-api:2.1 and added the listener to web.xml. 
&lt;/p&gt;
&lt;p&gt;
With Struts 2 and Spring MVC, I was previously able to have ${param.xss} and pass in ?xss=&amp;lt;script&amp;gt;alert(&apos;gotcha&apos;)&amp;lt;/script&gt; and it would show a JavaScript alert. After using Chin&apos;s ELResolver, it prints the string on the page instead of displaying an alert.&lt;/p&gt;
&lt;p&gt;Thanks to Chin Huang for this patch! If you&apos;re using JSP, I highly recommend you add this to your projects as well.
    
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/integration_testing_with_http_https</id>
        <title type="html">Integration Testing with HTTP, HTTPS and Maven</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/integration_testing_with_http_https"/>
        <published>2011-02-11T15:54:16-07:00</published>
        <updated>2012-11-11T02:00:40-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="cargo" scheme="http://roller.apache.org/ns/tags/" />
        <category term="jetty" scheme="http://roller.apache.org/ns/tags/" />
        <category term="overstock.com" scheme="http://roller.apache.org/ns/tags/" />
        <category term="ssl" scheme="http://roller.apache.org/ns/tags/" />
        <category term="http" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven" scheme="http://roller.apache.org/ns/tags/" />
        <category term="https" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">Earlier this week, I was tasked with getting automated integration tests working in my project at &lt;a href=&quot;http://overstock.com&quot;&gt;Overstock.com&lt;/a&gt;. By &lt;em&gt;automated&lt;/em&gt;, I mean that ability to run &quot;mvn install&quot; and have the following process cycled through: 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start a container&lt;/li&gt;
&lt;li&gt;Deploy the application&lt;/li&gt;
&lt;li&gt;Run all integration tests&lt;/li&gt;
&lt;li&gt;Stop the container&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since it makes sense for integration tests to run in Maven&apos;s &lt;em&gt;integration-test&lt;/em&gt; phase, I first configured the maven-surefire-plugin to skip tests in the &lt;em&gt;test&lt;/em&gt; phase and execute them in the &lt;em&gt;integration-test&lt;/em&gt; phase. I used the &amp;lt;id&gt;&lt;strong&gt;default-&lt;/strong&gt;&lt;em&gt;phase&lt;/em&gt;&amp;lt;/id&gt; syntax to override the plugins&apos; usual behavior.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;plugin&amp;gt;
  &amp;lt;artifactId&amp;gt;maven-surefire-plugin&amp;lt;/artifactId&amp;gt;
  &amp;lt;executions&amp;gt;
    &amp;lt;execution&amp;gt;
      &amp;lt;id&amp;gt;default-test&amp;lt;/id&amp;gt;
      &amp;lt;configuration&amp;gt;
        &amp;lt;excludes&amp;gt;
          &amp;lt;exclude&amp;gt;**/*Test*.java&amp;lt;/exclude&amp;gt;
        &amp;lt;/excludes&amp;gt;
      &amp;lt;/configuration&amp;gt;
    &amp;lt;/execution&amp;gt;
    &amp;lt;execution&amp;gt;
      &amp;lt;id&amp;gt;default-integration-test&amp;lt;/id&amp;gt;
      &amp;lt;phase&amp;gt;integration-test&amp;lt;/phase&amp;gt;
      &amp;lt;goals&amp;gt;
        &amp;lt;goal&amp;gt;test&amp;lt;/goal&amp;gt;
      &amp;lt;/goals&amp;gt;
      &amp;lt;configuration&amp;gt;
        &amp;lt;includes&amp;gt;
          &amp;lt;include&amp;gt;**/*Test.java&amp;lt;/include&amp;gt;
        &amp;lt;/includes&amp;gt;
        &amp;lt;excludes&amp;gt;
          &amp;lt;exclude&amp;gt;none&amp;lt;/exclude&amp;gt;
          &amp;lt;exclude&amp;gt;**/TestCase.java&amp;lt;/exclude&amp;gt;
        &amp;lt;/excludes&amp;gt;
      &amp;lt;/configuration&amp;gt;
    &amp;lt;/execution&amp;gt;
  &amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/pre&gt;
&lt;p&gt;After I had this working, I moved onto getting the container started and stopped properly. In the past, I&apos;ve &lt;a href=&quot;http://raibledesigns.com/rd/entry/integrating_selenium_with_maven_2&quot;&gt;done this&lt;/a&gt; using &lt;a href=&quot;http://cargo.codehaus.org&quot;&gt;Cargo&lt;/a&gt; and it&apos;s always worked well for me. Apart from the usual setup I use in AppFuse archetypes (&lt;a href=&quot;http://source.appfuse.org/browse/appfuse/trunk/archetypes/appfuse-basic-struts/src/pom.xml?r=HEAD#l496&quot;&gt;example pom.xml&lt;/a&gt;), I added a couple additional items:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Added &amp;lt;timeout&gt;180000&amp;lt;/timeout&gt; so the container would wait up to 3 minutes for the WAR to deploy.&lt;/li&gt;
&lt;li&gt;In configuration/properties, specified &amp;lt;context.path&gt;ROOT&amp;lt;/context.path&gt; so the app would deploy at the / context path.&lt;/li&gt;
&lt;li&gt;In configuration/properties, specified &amp;lt;cargo.protocol&gt;https&amp;lt;/cargo.protocol&gt; since many existing unit tests made requests to secure resources.
&lt;/ul&gt;
&lt;p&gt;I started by using Cargo with Tomcat and had to &lt;a href=&quot;http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html&quot;&gt;create certificate keystore&lt;/a&gt; in order to get Tomcat to start with SSL enabled. After getting it to start, I found the tests failed with the following errors in the logs:
&lt;/p&gt;
&lt;pre&gt;
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: 
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target
	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1649)
&lt;/pre&gt;
&lt;p&gt;Co-workers told me this was easily solved by &lt;a href=&quot;http://blogs.sun.com/gc/entry/unable_to_find_valid_certification&quot;&gt;adding my &apos;untrusted&apos; cert to my JVM keystore&lt;/a&gt;. Once all this was working, I thought I was good to go, but found that some tests were still failing. The failures turned out to be because they were talking to http and https was the only protocol enabled. After doing some research, I discovered that Cargo &lt;a href=&quot;http://jira.codehaus.org/browse/CARGO-574&quot;&gt;doesn&apos;t support starting on both http and https ports&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So back to the drawing board I went. I ended up turning to the &lt;a href=&quot;http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin&quot;&gt;maven-jetty-plugin&lt;/a&gt; and the &lt;a href=&quot;http://mojo.codehaus.org/tomcat-maven-plugin/&quot;&gt;tomcat-maven-plugin&lt;/a&gt; to get the functionality I was looking for. I also automated the certificate keystore generation using the &lt;a href=&quot;http://mrhaki.blogspot.com/2009/05/configure-maven-jetty-plugin-for-ssl.html&quot;&gt;keytool-maven-plugin&lt;/a&gt;. Below is the extremely-verbose 95-line profiles section of my pom.xml that allows either container to be used.
&lt;/p&gt;
&lt;p style=&quot;margin-left: 20px&quot;&gt;&lt;em&gt;Sidenote: I wonder how this same setup would look using &lt;a href=&quot;http://www.gradle.org&quot;&gt;Gradle&lt;/a&gt;?&lt;/em&gt;
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;profiles&amp;gt;
  &amp;lt;profile&amp;gt;
    &amp;lt;id&amp;gt;jetty&amp;lt;/id&amp;gt;
    &amp;lt;activation&amp;gt;
      &amp;lt;activeByDefault&amp;gt;true&amp;lt;/activeByDefault&amp;gt;
    &amp;lt;/activation&amp;gt;
    &amp;lt;build&amp;gt;
      &amp;lt;plugins&amp;gt;
        &amp;lt;plugin&amp;gt;
          &amp;lt;groupId&amp;gt;org.mortbay.jetty&amp;lt;/groupId&amp;gt;
          &amp;lt;artifactId&amp;gt;maven-jetty-plugin&amp;lt;/artifactId&amp;gt;
          &amp;lt;version&amp;gt;6.1.26&amp;lt;/version&amp;gt;
          &amp;lt;configuration&amp;gt;
            &amp;lt;contextPath&amp;gt;/&amp;lt;/contextPath&amp;gt;
            &amp;lt;connectors&amp;gt;
              &amp;lt;connector implementation=&quot;org.mortbay.jetty.nio.SelectChannelConnector&quot;&amp;gt;
                &amp;lt;!-- forwarded == true interprets x-forwarded-* headers --&amp;gt;
                &amp;lt;!-- http://docs.codehaus.org/display/JETTY/Configuring+mod_proxy --&amp;gt;
                &amp;lt;forwarded&amp;gt;true&amp;lt;/forwarded&amp;gt;
                &amp;lt;port&amp;gt;8080&amp;lt;/port&amp;gt;
                &amp;lt;maxIdleTime&amp;gt;60000&amp;lt;/maxIdleTime&amp;gt;
              &amp;lt;/connector&amp;gt;
              &amp;lt;connector implementation=&quot;org.mortbay.jetty.security.SslSocketConnector&quot;&amp;gt;
                &amp;lt;forwarded&amp;gt;true&amp;lt;/forwarded&amp;gt;
                &amp;lt;port&amp;gt;8443&amp;lt;/port&amp;gt;
                &amp;lt;maxIdleTime&amp;gt;60000&amp;lt;/maxIdleTime&amp;gt;
                &amp;lt;keystore&amp;gt;${project.build.directory}/ssl.keystore&amp;lt;/keystore&amp;gt;
                &amp;lt;password&amp;gt;overstock&amp;lt;/password&amp;gt;
                &amp;lt;keyPassword&amp;gt;overstock&amp;lt;/keyPassword&amp;gt;
              &amp;lt;/connector&amp;gt;
            &amp;lt;/connectors&amp;gt;
            &amp;lt;stopKey&amp;gt;overstock&amp;lt;/stopKey&amp;gt;
            &amp;lt;stopPort&amp;gt;9999&amp;lt;/stopPort&amp;gt;
          &amp;lt;/configuration&amp;gt;
          &amp;lt;executions&amp;gt;
            &amp;lt;execution&amp;gt;
              &amp;lt;id&amp;gt;start-jetty&amp;lt;/id&amp;gt;
              &amp;lt;phase&amp;gt;pre-integration-test&amp;lt;/phase&amp;gt;
              &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;run-war&amp;lt;/goal&amp;gt;
              &amp;lt;/goals&amp;gt;
              &amp;lt;configuration&amp;gt;
                &amp;lt;daemon&amp;gt;true&amp;lt;/daemon&amp;gt;
              &amp;lt;/configuration&amp;gt;
            &amp;lt;/execution&amp;gt;
            &amp;lt;execution&amp;gt;
              &amp;lt;id&amp;gt;stop-jetty&amp;lt;/id&amp;gt;
              &amp;lt;phase&amp;gt;post-integration-test&amp;lt;/phase&amp;gt;
              &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;stop&amp;lt;/goal&amp;gt;
              &amp;lt;/goals&amp;gt;
            &amp;lt;/execution&amp;gt;
          &amp;lt;/executions&amp;gt;
        &amp;lt;/plugin&amp;gt;
      &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;
  &amp;lt;/profile&amp;gt;
  &amp;lt;profile&amp;gt;
    &amp;lt;id&amp;gt;tomcat&amp;lt;/id&amp;gt;
    &amp;lt;build&amp;gt;
      &amp;lt;plugins&amp;gt;
        &amp;lt;plugin&amp;gt;
          &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
          &amp;lt;artifactId&amp;gt;tomcat-maven-plugin&amp;lt;/artifactId&amp;gt;
          &amp;lt;version&amp;gt;1.1&amp;lt;/version&amp;gt;
          &amp;lt;configuration&amp;gt;
            &amp;lt;addContextWarDependencies&amp;gt;true&amp;lt;/addContextWarDependencies&amp;gt;
            &amp;lt;fork&amp;gt;true&amp;lt;/fork&amp;gt;
            &amp;lt;path&amp;gt;/&amp;lt;/path&amp;gt;
            &amp;lt;port&amp;gt;8080&amp;lt;/port&amp;gt;
            &amp;lt;httpsPort&amp;gt;8443&amp;lt;/httpsPort&amp;gt;
            &amp;lt;keystoreFile&amp;gt;${project.build.directory}/ssl.keystore&amp;lt;/keystoreFile&amp;gt;
            &amp;lt;keystorePass&amp;gt;overstock&amp;lt;/keystorePass&amp;gt;
          &amp;lt;/configuration&amp;gt;
          &amp;lt;executions&amp;gt;
            &amp;lt;execution&amp;gt;
              &amp;lt;id&amp;gt;start-tomcat&amp;lt;/id&amp;gt;
              &amp;lt;phase&amp;gt;pre-integration-test&amp;lt;/phase&amp;gt;
              &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;run-war&amp;lt;/goal&amp;gt;
              &amp;lt;/goals&amp;gt;
            &amp;lt;/execution&amp;gt;
            &amp;lt;execution&amp;gt;
              &amp;lt;id&amp;gt;stop-tomcat&amp;lt;/id&amp;gt;
              &amp;lt;phase&amp;gt;post-integration-test&amp;lt;/phase&amp;gt;
              &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;shutdown&amp;lt;/goal&amp;gt;
              &amp;lt;/goals&amp;gt;
            &amp;lt;/execution&amp;gt;
          &amp;lt;/executions&amp;gt;
        &amp;lt;/plugin&amp;gt;
      &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;
  &amp;lt;/profile&amp;gt;
&amp;lt;/profiles&amp;gt;
&lt;/pre&gt;
&lt;p&gt;With this setup in place, I was able to automate running our integration tests by simply typing &quot;mvn install&quot; (for Jetty) or &quot;mvn install -Ptomcat&quot; (for Tomcat). For running in Hudson, it&apos;s possible I&apos;ll have to further enhance things to randomize the port and pass that into tests as a system property. The &lt;a href=&quot;http://mojo.codehaus.org/build-helper-maven-plugin/&quot;&gt;build-helper-maven-plugin&lt;/a&gt; and its &lt;em&gt;reserve-network-port&lt;/em&gt; goal is a nice way to do this. Note: if you want to run more than one instance of Tomcat at a time, you might have to randomize the ajp and rmi ports to avoid collisions.
&lt;/p&gt;
&lt;p&gt;The final thing I encountered was our app didn&apos;t shutdown gracefully. Luckily, this was fixed in a newer version of our core framework and upgrading fixed the problem. Here&apos;s the explanation from an architect on the core framework team.&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
The hanging problem was caused by the way the framework internally
aggregated statistics related to database connection usage and page
response times.  The aggregation runs on a separate thread but not as a
daemon thread.  Previously, the aggregation threads weren&apos;t being
terminated on shutdown so the JVM would hang waiting for them to finish.
In the new frameworks, the aggregation threads are terminated on shutdown.
&lt;/p&gt;
&lt;p&gt;Hopefully this post helps you test your secure and unsecure applications at the same time. At the same time, I&apos;m hoping it motivates the Cargo developers to add simultaneous http and https support. &lt;img src=&quot;https://raibledesigns.com/images/smileys/wink.gif&quot; class=&quot;smiley&quot; alt=&quot;;)&quot; title=&quot;;)&quot; /&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; In the comments, Ron Piterman recommended I use the &lt;a href=&quot;http://maven.apache.org/plugins/maven-failsafe-plugin/&quot;&gt;Maven Failsafe Plugin&lt;/a&gt; because its designed to run integration tests while Surefire Plugin is for unit tests. I changed my configuration to the following and everything still passes. Thanks Ron!
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;plugin&amp;gt;
  &amp;lt;artifactId&amp;gt;maven-surefire-plugin&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;2.7.2&amp;lt;/version&amp;gt;
  &amp;lt;configuration&amp;gt;
    &amp;lt;skipTests&amp;gt;true&amp;lt;/skipTests&amp;gt;
  &amp;lt;/configuration&amp;gt;
&amp;lt;/plugin&amp;gt;
&amp;lt;plugin&amp;gt;
  &amp;lt;artifactId&amp;gt;maven-failsafe-plugin&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;2.7.2&amp;lt;/version&amp;gt;
  &amp;lt;configuration&amp;gt;
    &amp;lt;includes&amp;gt;
      &amp;lt;include&amp;gt;**/*Test.java&amp;lt;/include&amp;gt;
    &amp;lt;/includes&amp;gt;
    &amp;lt;excludes&amp;gt;
      &amp;lt;exclude&amp;gt;**/TestCase.java&amp;lt;/exclude&amp;gt;
    &amp;lt;/excludes&amp;gt;
  &amp;lt;/configuration&amp;gt;
  &amp;lt;executions&amp;gt;
    &amp;lt;execution&amp;gt;
      &amp;lt;id&amp;gt;integration-test&amp;lt;/id&amp;gt;
      &amp;lt;phase&amp;gt;integration-test&amp;lt;/phase&amp;gt;
      &amp;lt;goals&amp;gt;
        &amp;lt;goal&amp;gt;integration-test&amp;lt;/goal&amp;gt;
      &amp;lt;/goals&amp;gt;
    &amp;lt;/execution&amp;gt;
    &amp;lt;execution&amp;gt;
      &amp;lt;id&amp;gt;verify&amp;lt;/id&amp;gt;
      &amp;lt;phase&amp;gt;verify&amp;lt;/phase&amp;gt;
      &amp;lt;goals&amp;gt;
        &amp;lt;goal&amp;gt;verify&amp;lt;/goal&amp;gt;
      &amp;lt;/goals&amp;gt;
    &amp;lt;/execution&amp;gt;
  &amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Update 2:&lt;/strong&gt; In addition to application changes to solve hanging issues, I also had to change my Jetty Plugin configuration to use a different SSL connector implementation. This also required adding the jetty-sslengine dependency, which has been &lt;a href=&quot;http://stackoverflow.com/questions/2215550/mavens-jetty-plugin-ssl-configuration-issue&quot;&gt;renamed to jetty-ssl for Jetty 7&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;connector implementation=&quot;org.mortbay.jetty.security.SslSelectChannelConnector&quot;&amp;gt;
...
&amp;lt;dependencies&amp;gt;
  &amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.mortbay.jetty&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jetty-sslengine&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;6.1.26&amp;lt;/version&amp;gt;
  &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;
&lt;/pre&gt;&lt;p&gt;</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/what_s_new_in_spring</id>
        <title type="html">What&apos;s New in Spring 3.0</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/what_s_new_in_spring"/>
        <published>2010-03-19T11:46:25-06:00</published>
        <updated>2010-03-19T17:53:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="vmware" scheme="http://roller.apache.org/ns/tags/" />
        <category term="javaconfig" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="java" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <category term="roo" scheme="http://roller.apache.org/ns/tags/" />
        <category term="springsource" scheme="http://roller.apache.org/ns/tags/" />
        <category term="twitter" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">This morning, I attended Rod Johnson&apos;s &lt;a href=&quot;http://javasymposium.techtarget.com/html/sessions.html#RJohnsonKeynote&quot;&gt;What&apos;s New in Spring 3.0&lt;/a&gt; keynote at TSSJS. Rod ditched his slides for the talk and mentioned that this might be risky. Especially since he was pretty jetlagged (flew in from Paris at 11pm last night). Below are my notes from his talk.
&lt;/p&gt;
&lt;p style=&quot;border-top: 1px dotted silver; padding-top: 10px&quot;&gt;
The most important thing for the future of Java is productivity and cloud computing. The focus at SpringSource is heavily on productivity and not just on improving the Spring codebase. If you look at the comparisons out there between Rails and Spring, it&apos;s not an apples-to-apples comparison. The philosophy with Spring has always been the developer is always right. However, if you look at something like Rails, you&apos;ll see it&apos;s far more prescriptive. That layer of opinionated frameworks is important in that it improves your productivity greatly.
&lt;/p&gt;
&lt;p&gt;
SpringSource is putting a lot of emphasis on improving developer productivity with two opinionated frameworks: Grails and Spring Roo. To show how productive developers can be, Rod started to build a web app with Spring Roo. As part of this demo, he mentioned we&apos;d see many of the new features of Spring 3: RestTemplate, @Value and Spring EL. 
&lt;/p&gt;
&lt;p&gt;
Rod used STS to write the application and built a Twitter client. After creating a new project using File -&gt; New Roo Project, a Roo Shell tab shows up at the bottom. Typing &quot;hint&quot; tells you what you should do write away. The initial message is &quot;Roo requires the installation of a JPA provider and associated database.&quot; The initial command is &quot;persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY&quot;. After running this, a bunch of log messages are shown on the console, most of them indicating that pom.xml has been modified.
&lt;/p&gt;
&lt;p&gt;
The first file that Rod shows is src/main/resources/META-INF/spring/applicationContext.xml. It&apos;s the only XML file you&apos;ll need in your application and includes a PropertyPlaceHolderConfigurer, a context:component-scan for finding annotations and a transaction manager.
&lt;/p&gt;
&lt;p&gt;
After typing &quot;hint&quot; again, Roo indicates that Rod should create entities. He does this by running &quot;ent --class ~.domain.Term --testAutomatically&quot;.  A Term class (with a bunch of annotations) is created, as well as a number of *.aj files and an integration test. Most of the files don&apos;t have anything in them but annotations. The integration test uses @RooIntegrationTest(entity=Term.class) on its class to fire up a Spring container in the test and do dependency injection (if necessary). From there, Rod demonstrated that he could easily modify the test to verify the database existed.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
private SimpleJdbcTemplate jt;

@Autowired
public void init(DataSource ds) {
    this.jt = new SimpleJdbcTemplate(ds);
}

@Test 
public void testDb() {
    jt.queryForInt(&quot;SELECT COUNT(0) FROM TERM&quot;);
}
&lt;/pre&gt;
&lt;p&gt;
Interestingly, after running the test, you could see a whole bunch of tests being run, not just the one that was in the class itself. From there, he modified the Term class to add two new properties: name and searchTerms. He also used JSR 303&apos;s @NotNull annotation to make the fields required.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
@Entity
@RooJavaBean
@RooToString
@RooEntity
public class Term {

    @NotNull
    private String name;

    @NotNull
    private String searchTerms;
}
&lt;/pre&gt;
&lt;p&gt;
Next, Rod added a new test and showed that the setters for these properties were automatically created and he never had to write getters and setters. This is done by aspects that are generated beside your Java files. Roo is smart enough that if you write toString() methods in your Java code, it will delete the aspect that normally generates the toString() method.
&lt;/p&gt;
&lt;p&gt;
To add fields to an entity from the command lie, you can run commands like &quot;field string --fieldName text --notNull&quot; and &quot;field number --type java.lang.Long --fieldName twitterId --notNull&quot;. The Roo Shell is also capable of establishing relationships between entities. 
&lt;/p&gt;
&lt;p&gt;
After successfully modifying his Entities, Rod started creating code to talk to Twitter&apos;s API. He used RestTemplate to do this and spent a good 5 minutes trying to get Eclipse to import the class properly. The best part of this demo was watching him do what most developers do: searching Google for RestTemplate to get the package name to import.
&lt;/p&gt;
&lt;p&gt;
After awkward silence and some fumbling, he opened an existing project (that had the dependencies properly configured) and used Java Config to configure beans for the project. This was done with a @Configuration annotation on the class, @Value annotations on properties (that read from a properties file) and @Bean annotations for the beans to expose. The first time Rod tried to run the test it failed because a twitter.properties file didn&apos;t exist.  After creating it, he successfully ran the test and successfully searched Twitter&apos;s API. 
&lt;/p&gt;
&lt;p&gt;
The nice thing about @Configuration is the classes are automatically picked up and you don&apos;t need to configure any XML to recognize them. Also, in your Java classes, you don&apos;t have to use @Autowired to get @Bean references injected. 
&lt;/p&gt;
&lt;p&gt;
After this, Rod attempted to show a web interface of the application. He started the built-in SpringSource tc Server and proceeded to show us Tomcat&apos;s 404 page. Unfortunately, Tomcat seemed to startup OK (no errors in the logs), but obviously something didn&apos;t work well. For the next few silent moments, we watched him try to delete web.xml from Eclipse. Unfortunately, this didn&apos;t work and we weren&apos;t able to see the scaffolding the entities that Rod created. 
&lt;/p&gt;
&lt;p&gt;
At this point, Rod opened a completed version of the app and was able to show it to us in a browser. You could hear the murmur of the crowd as everyone realized he was about to show the the &lt;a href=&quot;http://twitter.com/search?q=%23tssjs&quot;&gt;Twitter search results for #tssjs&lt;/a&gt;. Most of the tweets displayed were from folks commenting about how some things didn&apos;t work in the demo. 
&lt;/p&gt;
&lt;p&gt;
In summary, there&apos;s some really cool things in Spring 3: @Configuration, @Value, task scheduling with @Scheduled and one-way methods with @Async. 
&lt;/p&gt;
&lt;p&gt;
Final points of SpringSource and VMWare: they&apos;re committed to Java and middleware. Their big focus is providing an integrated experience from productivity to cloud. There&apos;s other languages that are further along than Java and SpringSource is trying to fix that. One thing they&apos;re working on is a private Java cloud that companies can use and leverage as a VMWare appliance.
&lt;/p&gt;
&lt;p style=&quot;border-top: 1px dotted silver; padding-top: 10px&quot;&gt;
I think there&apos;s a lot of great things in Spring 3 and most users of Roo seem to be happy with it. It&apos;s unfortunate that the Demo Gods frowned upon Rod, but it was cool to see him do the &quot;no presentation&quot; approach. 
&lt;/p&gt;
&lt;p&gt;

</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/packaging_a_sofea_application_for</id>
        <title type="html">Packaging a SOFEA Application for Distribution</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/packaging_a_sofea_application_for"/>
        <published>2009-10-06T01:17:38-06:00</published>
        <updated>2009-10-06T17:01:07-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="gwt" scheme="http://roller.apache.org/ns/tags/" />
        <category term="selenium" scheme="http://roller.apache.org/ns/tags/" />
        <category term="sofea" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <category term="maven" scheme="http://roller.apache.org/ns/tags/" />
        <category term="waroverlays" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">The project I&apos;m working on is a bit different from those I&apos;m used to. I&apos;m used to working on web applications that are hosted on servers and customers access with their browser. &lt;a href=&quot;http://en.wikipedia.org/wiki/Software_as_a_service&quot;&gt;SaaS&lt;/a&gt; if you will. My current client is different. They&apos;re a product company that sells applications and distributes them to customers via download and CD. Their customers install these applications on internal servers (supported servers include WebSphere, WebLogic and Tomcat).
&lt;/p&gt;
&lt;p&gt;
The product I&apos;m currently working on is structured as a &lt;a href=&quot;http://raibledesigns.com/rd/entry/re_life_above_the_service&quot; title=&quot;Service Oriented Front End Architecture&quot;&gt;SOFEA&lt;/a&gt; application and therefore consists of two separate modules - a backend and a frontend. Since it&apos;s installed in a servlet container, both modules are WARs and can be installed separately. 
&lt;/p&gt;
&lt;p&gt;
Building the backend and frontend as separate projects makes a lot of sense for two reasons:
&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;In development, different teams can work on the frontend and backend projects.&lt;/li&gt;
&lt;li&gt;Having them as separate projects allows them to be versioned separately.
&lt;/ul&gt;
&lt;p&gt;However, having them as two separate projects does make it a bit more difficult for distribution. I&apos;m writing this post to show you how I recently added support for distributing our application as 2 WARs &lt;em&gt;or&lt;/em&gt; 1 WAR using the power of Maven, war overlays and the &lt;a href=&quot;http://www.tuckey.org/urlrewrite/&quot;&gt;UrlRewriteFilter&lt;/a&gt;. 
&lt;/p&gt;
&lt;p id=&quot;projectsetup&quot;&gt;&lt;strong&gt;Project Setup&lt;/strong&gt;&lt;br/&gt;
First of all, we have several different Maven modules, but the most important ones are as follows:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;product-services&lt;/li&gt;
&lt;li&gt;product-client&lt;/li&gt;
&lt;li&gt;product-integration-tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, our modules aren&apos;t really named &quot;product&quot;, but you get the point. The services project is really just a WAR project with Spring Security configured. It depends on other JAR modules that the services exist in. The client project is a GWT WAR that has a proxy servlet defined in its web.xml that makes it easier to develop. It also contains some UrlRewrite configuration that allows &lt;a href=&quot;http://code.google.com/p/gwt-log/&quot;&gt;GWT Log&apos;s&lt;/a&gt; Remote Logging feature to work. The proxy servlet is something we don&apos;t want to ship with our product, so we have a separate web.xml for production vs. development. We do the substitution using the maven-war-plugin:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;maven-war-plugin&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;2.0.2&amp;lt;/version&amp;gt;
    &amp;lt;configuration&amp;gt;
        &amp;lt;!-- Production web.xml --&amp;gt;
        &amp;lt;webXml&amp;gt;src/main/resources/web.xml&amp;lt;/webXml&amp;gt;
        &amp;lt;warSourceDirectory&amp;gt;war&amp;lt;/warSourceDirectory&amp;gt;
        &amp;lt;!-- Exclude everything but urlrewrite JAR --&amp;gt;
        &amp;lt;warSourceExcludes&amp;gt;
            WEB-INF/lib/aop**,WEB-INF/lib/commons-**,WEB-INF/lib/gin-**,
            WEB-INF/lib/guice-**,WEB-INF/lib/gwt-**,WEB-INF/lib/gxt-**,
            WEB-INF/lib/junit-**
        &amp;lt;/warSourceExcludes&amp;gt;
    &amp;lt;/configuration&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/pre&gt;
&lt;p style=&quot;margin-left: 30px&quot;&gt;
&lt;em&gt;I could exclude WEB-INF/lib/** and WEB-INF/classes/**, but in my particular project, we still want UrlRewrite in standalone mode, and we have some i18n properties files in WEB-INF/classes that are served up for Selenium tests.&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;With this configuration, we have a services WAR and a client WAR that can be installed and used by clients. To collapse them into one and make it possible to ship a single war, I turned to our &lt;em&gt;product-integration-tests&lt;/em&gt; module. This module contains Selenium tests that test both types of distributions.
&lt;/p&gt;
&lt;p id=&quot;mergingwars&quot;&gt;
&lt;strong&gt;Merging 2 WARs into 1&lt;/strong&gt;&lt;br/&gt;
The most important thing in the product-integration-tests module is that it creates a single WAR. First of all, it uses &lt;code&gt;&amp;lt;packaging&gt;war&amp;lt;/packaging&gt;&lt;/code&gt; to make this possible. The rest is done using the following 3 steps.
&lt;/p&gt;
&lt;p&gt;
1. Its dependencies include the client and servlet WARs (and Selenium RC for testing).
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;com.company.app&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;product-services&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
        &amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
    &amp;lt;/dependency&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;com.company.app&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;product-client&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
        &amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
    &amp;lt;/dependency&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.seleniumhq.selenium.client-drivers&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;selenium-java-client-driver&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.0.1&amp;lt;/version&amp;gt;
        &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;
&lt;/pre&gt;
&lt;p&gt;2. The WAR created excludes the &quot;integration-tests&quot; part of the name:
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;build&amp;gt;
    &amp;lt;finalName&amp;gt;product-${project.version}&amp;lt;/finalName&amp;gt;
    ...
&amp;lt;/build&amp;gt;
&lt;/pre&gt;
&lt;p&gt;3. WAR overlays are configured so the everything in the client&apos;s &lt;em&gt;WEB-INF&lt;/em&gt; directory is excluded from the merged WAR.
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;artifactId&amp;gt;maven-war-plugin&amp;lt;/artifactId&amp;gt;
    &amp;lt;configuration&amp;gt;
        &amp;lt;!-- http://maven.apache.org/plugins/maven-war-plugin/overlays.html --&amp;gt;
        &amp;lt;overlays&amp;gt;
            &amp;lt;overlay&amp;gt;
                &amp;lt;groupId&amp;gt;com.company.app&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;product-services&amp;lt;/artifactId&amp;gt;
                &amp;lt;excludes&amp;gt;
                    &amp;lt;!-- TODO: Rename to api.html (this is the Enunciate-generated documentation) --&amp;gt;
                    &amp;lt;exclude&amp;gt;index.html&amp;lt;/exclude&amp;gt;
                &amp;lt;/excludes&amp;gt;
            &amp;lt;/overlay&amp;gt;
            &amp;lt;!-- No server needed in product-client --&amp;gt;
            &amp;lt;overlay&amp;gt;
                &amp;lt;groupId&amp;gt;com.company.app&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;product-client&amp;lt;/artifactId&amp;gt;
                &amp;lt;excludes&amp;gt;
                    &amp;lt;exclude&amp;gt;WEB-INF/**&amp;lt;/exclude&amp;gt;
                &amp;lt;/excludes&amp;gt;
            &amp;lt;/overlay&amp;gt;
            &amp;lt;!-- Only include META-INF/context.xml to set the ROOT path --&amp;gt;
            &amp;lt;overlay&amp;gt;
                &amp;lt;excludes&amp;gt;
                    &amp;lt;exclude&amp;gt;WEB-INF/**&amp;lt;/exclude&amp;gt;
                &amp;lt;/excludes&amp;gt;
            &amp;lt;/overlay&amp;gt;
        &amp;lt;/overlays&amp;gt;
    &amp;lt;/configuration&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/pre&gt;
&lt;p&gt;That&apos;s it! Using this configuration, it&apos;s possible to distribute a Maven-based SOFEA project as single or multiple WARs. However, there are some nuances.
&lt;/p&gt;
&lt;p&gt;One thing you might notice is the reference to &lt;em&gt;META-INF/context.xml&lt;/em&gt; in the overlays configuration. This subtly highlights one issue I experienced when merging the WARs. In our GWT client, we&apos;re using URLs that point to our services at &lt;strong&gt;/product-services/*&lt;/strong&gt;. This works in development (via a proxy servlet) and when the WARs are installed separately - as long as the services WAR is installed at &lt;strong&gt;/product-services&lt;/strong&gt;. However, when they&apos;re merged, a little URL rewriting needs to happen. To do this, I added the UrlRewriteFilter to the product-services module and configured a simple rule. 
&lt;/p&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCENGINE urlrewrite PUBLIC &quot;-//tuckey.org//DTD UrlRewrite 3.0//EN&quot;
        &quot;http://tuckey.org/res/dtds/urlrewrite3.0.dtd&quot;&amp;gt;

&amp;lt;urlrewrite use-query-string=&quot;true&quot;&amp;gt;
    &amp;lt;!-- Used when services are merged into WAR with GWT client --&amp;gt;
    &amp;lt;rule&amp;gt;
        &amp;lt;from&amp;gt;^/product-services/(.*)$&amp;lt;/from&amp;gt;
        &amp;lt;to type=&quot;forward&quot;&amp;gt;/$1&amp;lt;/to&amp;gt;
    &amp;lt;/rule&amp;gt;
&amp;lt;/urlrewrite&amp;gt;
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;Because the services URLs point to the root (/product-services), the merged WAR has to be installed as the ROOT application. When you&apos;re using Cargo with Tomcat and want to deploy to ROOT, you have to have a &lt;em&gt;META-INF/context.xml&lt;/em&gt; with a path=&quot;&quot; reference (ref: &lt;a href=&quot;http://jira.codehaus.org/browse/CARGO-516&quot;&gt;CARGO-516&lt;/a&gt;).
&lt;/p&gt;
&lt;pre&gt;
&amp;lt;Context path=&quot;&quot;/&amp;gt;
&lt;/pre&gt;
&lt;p&gt;It is possible to change the URLs in the client to be relative, but this gets seems to get messy when you&apos;re using separate WARs. When using relative URLs, I found I had to do solution using cross-context forwarding to get the results I wanted. Using a redirect instead of a forward worked, but resulted in the client talking to the server twice (once to get redirected, a second time for the actual call). Cross-context forwarding is supported by the UrlRewriteFilter and Tomcat, but I&apos;m not sure WebSphere or WebLogic support it. The best solution is probably to change the URLs dynamically at runtime, possibly using some sort of deferred binding technique. &lt;!--The upside to having the URLs start at a known location (/product-services) is that you could  install the merged WAR initially and install a newer product-services.war later to upgrade the services.--&gt;
&lt;/p&gt;
&lt;p id=&quot;testingwithselenium&quot;&gt;&lt;strong&gt;Testing with Cargo and Selenium&lt;/strong&gt;&lt;br/&gt;
Once I had everything merged, I wanted to configure Cargo and Selenium to allow testing both distribution types. If I installed all 3 wars at the same time, the &quot;product-services&quot; WAR would be used by both the product-client.war and the product.war, so I had to use profiles to allow installing the single merged WAR or both WARs. Below is the profile I used for starting Cargo, deploying the merged WAR, starting Selenium RC and running Selenium tests.&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
&amp;lt;properties&amp;gt;
    &amp;lt;cargo.container&amp;gt;tomcat6x&amp;lt;/cargo.container&amp;gt;
    &amp;lt;cargo.container.url&amp;gt;
        http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.20/bin/apache-tomcat-6.0.20.zip
    &amp;lt;/cargo.container.url&amp;gt;
    &amp;lt;cargo.host&amp;gt;localhost&amp;lt;/cargo.host&amp;gt;
    &amp;lt;cargo.port&amp;gt;23433&amp;lt;/cargo.port&amp;gt;
    &amp;lt;cargo.wait&amp;gt;false&amp;lt;/cargo.wait&amp;gt;
    &amp;lt;cargo.version&amp;gt;1.0&amp;lt;/cargo.version&amp;gt;

    &amp;lt;!-- *safari and *iexplore are additional options --&amp;gt;
    &amp;lt;selenium.browser&amp;gt;*firefox&amp;lt;/selenium.browser&amp;gt;
&amp;lt;/properties&amp;gt;
...
&amp;lt;profile&amp;gt;
    &amp;lt;id&amp;gt;itest-bamboo&amp;lt;/id&amp;gt;
    &amp;lt;activation&amp;gt;
        &amp;lt;activeByDefault&amp;gt;false&amp;lt;/activeByDefault&amp;gt;
    &amp;lt;/activation&amp;gt;
    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.codehaus.cargo&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;cargo-maven2-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;${cargo.version}&amp;lt;/version&amp;gt;
                &amp;lt;configuration&amp;gt;
                    &amp;lt;wait&amp;gt;${cargo.wait}&amp;lt;/wait&amp;gt;
                    &amp;lt;container&amp;gt;
                        &amp;lt;containerId&amp;gt;${cargo.container}&amp;lt;/containerId&amp;gt;
                        &amp;lt;log&amp;gt;${project.build.directory}/${cargo.container}/cargo.log&amp;lt;/log&amp;gt;
                        &amp;lt;zipUrlInstaller&amp;gt;
                            &amp;lt;url&amp;gt;${cargo.container.url}&amp;lt;/url&amp;gt;
                            &amp;lt;installDir&amp;gt;${installDir}&amp;lt;/installDir&amp;gt;
                        &amp;lt;/zipUrlInstaller&amp;gt;
                    &amp;lt;/container&amp;gt;
                    &amp;lt;configuration&amp;gt;
                        &amp;lt;home&amp;gt;${project.build.directory}/${cargo.container}/container&amp;lt;/home&amp;gt;
                        &amp;lt;properties&amp;gt;
                            &amp;lt;cargo.hostname&amp;gt;${cargo.host}&amp;lt;/cargo.hostname&amp;gt;
                            &amp;lt;cargo.servlet.port&amp;gt;${cargo.port}&amp;lt;/cargo.servlet.port&amp;gt;
                        &amp;lt;/properties&amp;gt;
                        &amp;lt;!-- Deploy as ROOT since XHR requests are made to /product-services --&amp;gt;
                        &amp;lt;deployables&amp;gt;
                            &amp;lt;deployable&amp;gt;
                                &amp;lt;properties&amp;gt;
                                    &amp;lt;context&amp;gt;ROOT&amp;lt;/context&amp;gt;
                                &amp;lt;/properties&amp;gt;
                            &amp;lt;/deployable&amp;gt;
                        &amp;lt;/deployables&amp;gt;
                    &amp;lt;/configuration&amp;gt;
                &amp;lt;/configuration&amp;gt;
                &amp;lt;executions&amp;gt;
                    &amp;lt;execution&amp;gt;
                        &amp;lt;id&amp;gt;start-container&amp;lt;/id&amp;gt;
                        &amp;lt;phase&amp;gt;pre-integration-test&amp;lt;/phase&amp;gt;
                        &amp;lt;goals&amp;gt;
                            &amp;lt;goal&amp;gt;start&amp;lt;/goal&amp;gt;
                        &amp;lt;/goals&amp;gt;
                    &amp;lt;/execution&amp;gt;
                    &amp;lt;execution&amp;gt;
                        &amp;lt;id&amp;gt;stop-container&amp;lt;/id&amp;gt;
                        &amp;lt;phase&amp;gt;post-integration-test&amp;lt;/phase&amp;gt;
                        &amp;lt;goals&amp;gt;
                            &amp;lt;goal&amp;gt;stop&amp;lt;/goal&amp;gt;
                        &amp;lt;/goals&amp;gt;
                    &amp;lt;/execution&amp;gt;
                &amp;lt;/executions&amp;gt;
            &amp;lt;/plugin&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;selenium-maven-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;1.0&amp;lt;/version&amp;gt;
                &amp;lt;executions&amp;gt;
                    &amp;lt;execution&amp;gt;
                        &amp;lt;phase&amp;gt;pre-integration-test&amp;lt;/phase&amp;gt;
                        &amp;lt;goals&amp;gt;
                            &amp;lt;goal&amp;gt;start-server&amp;lt;/goal&amp;gt;
                        &amp;lt;/goals&amp;gt;
                        &amp;lt;configuration&amp;gt;
                            &amp;lt;background&amp;gt;true&amp;lt;/background&amp;gt;
                        &amp;lt;/configuration&amp;gt;
                    &amp;lt;/execution&amp;gt;
                &amp;lt;/executions&amp;gt;
            &amp;lt;/plugin&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;artifactId&amp;gt;maven-surefire-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;executions&amp;gt;
                    &amp;lt;execution&amp;gt;
                        &amp;lt;phase&amp;gt;integration-test&amp;lt;/phase&amp;gt;
                        &amp;lt;goals&amp;gt;
                            &amp;lt;goal&amp;gt;test&amp;lt;/goal&amp;gt;
                        &amp;lt;/goals&amp;gt;
                        &amp;lt;configuration&amp;gt;
                            &amp;lt;excludes&amp;gt;
                                &amp;lt;exclude&amp;gt;none&amp;lt;/exclude&amp;gt;
                            &amp;lt;/excludes&amp;gt;
                            &amp;lt;includes&amp;gt;
                                &amp;lt;include&amp;gt;**/*SeleniumTest.java&amp;lt;/include&amp;gt;
                            &amp;lt;/includes&amp;gt;
                            &amp;lt;systemProperties&amp;gt;
                                &amp;lt;property&amp;gt;
                                    &amp;lt;name&amp;gt;selenium.browser&amp;lt;/name&amp;gt;
                                    &amp;lt;value&amp;gt;${selenium.browser}&amp;lt;/value&amp;gt;
                                &amp;lt;/property&amp;gt;
                                &amp;lt;property&amp;gt;
                                    &amp;lt;name&amp;gt;cargo.port&amp;lt;/name&amp;gt;
                                    &amp;lt;value&amp;gt;${cargo.port}&amp;lt;/value&amp;gt;
                                &amp;lt;/property&amp;gt;
                            &amp;lt;/systemProperties&amp;gt;
                        &amp;lt;/configuration&amp;gt;
                    &amp;lt;/execution&amp;gt;
                &amp;lt;/executions&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;
&amp;lt;/profile&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This profile is run by our Bamboo nightly tests with &lt;code&gt;mvn install -Pitest-bamboo&lt;/code&gt;. The 2nd profile I added doesn&apos;t install the project&apos;s WAR, but instead installs the two separate WARs. Running &lt;code&gt;mvn install -Pitest-bamboo,multiple-wars&lt;/code&gt; executes the Selenium tests against the multi-WAR distribution.
&lt;/p&gt;
&lt;pre class=&quot;brush: java&quot;&gt;
&amp;lt;profile&amp;gt;
    &amp;lt;id&amp;gt;multiple-wars&amp;lt;/id&amp;gt;
    &amp;lt;activation&amp;gt;
        &amp;lt;activeByDefault&amp;gt;false&amp;lt;/activeByDefault&amp;gt;
    &amp;lt;/activation&amp;gt;
    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.codehaus.cargo&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;cargo-maven2-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;${cargo.version}&amp;lt;/version&amp;gt;
                &amp;lt;configuration&amp;gt;
                    &amp;lt;configuration&amp;gt;
                        &amp;lt;home&amp;gt;${project.build.directory}/${cargo.container}/container&amp;lt;/home&amp;gt;
                        &amp;lt;properties&amp;gt;
                            &amp;lt;cargo.hostname&amp;gt;${cargo.host}&amp;lt;/cargo.hostname&amp;gt;
                            &amp;lt;cargo.servlet.port&amp;gt;${cargo.port}&amp;lt;/cargo.servlet.port&amp;gt;
                        &amp;lt;/properties&amp;gt;
                        &amp;lt;deployables&amp;gt;
                            &amp;lt;deployable&amp;gt;
                                &amp;lt;groupId&amp;gt;com.company.app&amp;lt;/groupId&amp;gt;
                                &amp;lt;artifactId&amp;gt;product-client&amp;lt;/artifactId&amp;gt;
                                &amp;lt;pingURL&amp;gt;http://${cargo.host}:${cargo.port}/product-client/index.html&amp;lt;/pingURL&amp;gt;
                                &amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
                                &amp;lt;properties&amp;gt;
                                    &amp;lt;context&amp;gt;/product-client&amp;lt;/context&amp;gt;
                                &amp;lt;/properties&amp;gt;
                            &amp;lt;/deployable&amp;gt;
                            &amp;lt;deployable&amp;gt;
                                &amp;lt;groupId&amp;gt;com.company.app&amp;lt;/groupId&amp;gt;
                                &amp;lt;artifactId&amp;gt;product-services&amp;lt;/artifactId&amp;gt;
                                &amp;lt;pingURL&amp;gt;
                                    http://${cargo.host}:${cargo.port}/project-services/index.jspx
                                &amp;lt;/pingURL&amp;gt;
                                &amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
                                &amp;lt;properties&amp;gt;
                                    &amp;lt;context&amp;gt;/product-services&amp;lt;/context&amp;gt;
                                &amp;lt;/properties&amp;gt;
                            &amp;lt;/deployable&amp;gt;
                        &amp;lt;/deployables&amp;gt;
                    &amp;lt;/configuration&amp;gt;
                &amp;lt;/configuration&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;
&amp;lt;/profile&amp;gt;
&lt;/pre&gt;
&lt;p&gt;I won&apos;t be including any information on authoring Selenium tests because there&apos;s already many good references. I encourage you to checkout the following if you&apos;re looking for Selenium testing techniques.
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/carlossg/appfuse-selenium&quot;&gt;Carlos Sanchez&apos;s Selenium Test Environment for AppFuse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.extjs.com/blog/2008/11/03/testing-ext-js-ext-gwt-applications-with-selenium/&quot;&gt;Testing Ext JS &amp;amp; Ext GWT Applications With Selenium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.sonatype.com/people/2009/09/testing-nexus-with-selenium-a-lesson-in-complex-ui-testing-part-1/&quot;&gt;Testing Nexus with Selenium: A lesson in complex UI testing (Part 1)&lt;/a&gt;
&lt;li&gt;&lt;a href=&quot;http://www.sonatype.com/people/2009/10/selenium-part-2/&quot;&gt;Testing Nexus with Selenium: A lesson in complex UI testing (Part 2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.sonatype.com/people/2009/10/selenium-part-3/&quot;&gt;Testing Nexus with Selenium: A lesson in complex UI testing (Part 3)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br/&gt;
This article has shown you how I used Maven, war overlays and the UrlRewriteFilter to allow create different distributions of a SOFEA application. I&apos;m still not sure which packaging (1 WAR vs. 2) mechanism is best, but it&apos;s nice to know there&apos;s options. If you package and distribute SOFEA applications, I&apos;d love to hear about your experience in this area.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/building_linkedin_s_next_generation</id>
        <title type="html">Building LinkedIn&apos;s Next Generation Architecture with OSGi by Yan Pujante</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/building_linkedin_s_next_generation"/>
        <published>2008-10-20T11:20:09-06:00</published>
        <updated>2009-06-04T20:03:31-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="rpc" scheme="http://roller.apache.org/ns/tags/" />
        <category term="eclipse" scheme="http://roller.apache.org/ns/tags/" />
        <category term="glassfish" scheme="http://roller.apache.org/ns/tags/" />
        <category term="yanpujante" scheme="http://roller.apache.org/ns/tags/" />
        <category term="linkedin" scheme="http://roller.apache.org/ns/tags/" />
        <category term="infiniflow" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <category term="apache" scheme="http://roller.apache.org/ns/tags/" />
        <category term="osgi" scheme="http://roller.apache.org/ns/tags/" />
        <category term="spring" scheme="http://roller.apache.org/ns/tags/" />
        <category term="architecture" scheme="http://roller.apache.org/ns/tags/" />
        <category term="softwaresummit" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">This week, I&apos;m attending the &lt;a href=&quot;http://softwaresummit.com&quot;&gt;Colorado Software Summit&lt;/a&gt; in Keystone, Colorado. Below are my notes from an &lt;strong&gt;OSGi at LinkedIn&lt;/strong&gt; presentation I attended by &lt;a href=&quot;http://www.linkedin.com/in/yan&quot;&gt;Yan Pujante&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
LinkedIn was created in March of 2003. Today there&apos;s close to 30M members. In the first 6 months, there was 60,000 members that signed up. Now, 1 million sign up every 2-3 weeks. LinkedIn is profitable with 5 revenue lines and there&apos;s 400 employees in Mountain View.
&lt;/p&gt;
&lt;p&gt;
Technologies: 2 datacenters (~600 machines). SOA with Java, Tomcat, Spring Framework, Oracle, MySQL, Servlets, JSP, Cloud/Graph, OSGi. Development is done on Mac OS X, production is on Solaris.
&lt;/p&gt;
&lt;p&gt;
The biggest challenges for LinkedIn are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Growing Engineering Team on a monolithic code base (it&apos;s modular, but only one source tree)&lt;/li&gt;
&lt;li&gt;Growing Product Team wanting more and more features faster&lt;/li&gt;
&lt;li&gt;Growing Operations Team deploying more and more servers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Front-end has many BL services in one webapp (in Tomcat). The backend is many wars in 5 containers (in Jetty) with 1 service per WAR. Production and Development environments are very different. Total services in backend is close to 100, front-end has 30-40.
&lt;p&gt;
&lt;strong&gt;Container Challenges&lt;/strong&gt;&lt;br/&gt;
1 WAR with N services does not scale for developers (conflicts, monolithic). N wars with 1 service does not scale for containers (no shared JARs). You can add containers, but there&apos;s only 12GB of RAM available.
&lt;/p&gt;
&lt;p&gt;
Upgrading back-end service to new version requires downtime (hardware load-balancer does not account for version). Upgrading front-end service to new version requires redeploy. Adding new backend services is also painful because there&apos;s lots of configuration (load-balancer, IPs, etc.).
&lt;/p&gt;
&lt;p&gt;
Is there a solution to all these issues? Yan believes that OSGi is a good solution.  OSGi stands for &lt;strong&gt;Open Services Gateway initiative&lt;/strong&gt;. Today that term doesn&apos;t really mean anything. Today it&apos;s a spec with several implementations: Equinox (Eclipse), Knoplerfish and Felix (Apache). 
&lt;/p&gt;
&lt;p&gt;
OSGi has some really, really good features. These include smart class loading (multiple versions of JARs is OK), it&apos;s highly dynamic (deploy/undeploy built-in), it has a service registry and is highly extensible/configurable. An OSGi bundle is simply a JAR file with an OSGi manifest.
&lt;/p&gt;
&lt;p&gt;
In LinkedIn&apos;s current architecture, services are exported with Spring/RPC and services in same WAR can see each other. The problem with this architecture comes to light when you want to move services to a 2nd web container. You cannot share JARs and can&apos;t talk directly to the other web app. With OSGi, the bundles (JARs) are shared, services are shared and bundles can be dynamically replaced. OSGi solves the container challenge.
&lt;/p&gt;
&lt;p&gt;
One thing missing from OSGi is allowing services to live on multiple containers. To solve this, LinkedIn has developed a way to have &lt;strong&gt;Distributed OSGi&lt;/strong&gt;. Multicast is used to see what&apos;s going on in other containers. Remote servers use the OSGi lifecycle and create dynamic proxies to export services using Spring RPC over HTTP. Then this service is registered in the service registry on the local server. 
&lt;/p&gt;
&lt;p&gt;
With Distributed OSGi, there&apos;s no more N-1 / 1-N problem. Libraries and services can be shared in one container (memory footprint is much smaller). Services can be shared across containers. The location of the services is transparent to the clients. There&apos;s no more configuration to change when adding/removing/moving services. This architecture allows the software to be the load balancer instead of using a hardware load balancer.
&lt;/p&gt;
&lt;p&gt;
Unfortunately, everything is not perfect. OSGi has quite a few problems. OSGi is great, but the tooling is not quite there yet. Not every library is a bundle and many JARs doesn&apos;t have OSGi manifests. OSGi was designed for embedded devices and using it for the server-side is very recent (but very active).
&lt;/p&gt;
&lt;p&gt;
OSGi is pretty low-level, but there is some work being done to hide the complexity. Spring DM helps, as do vendor containers. SpringSource has Spring dm Server, Sun has GlassFish, and Paremus has Infiniflow. OSGi is container centric, but next version will add distributed OSGi, but will have no support for load-balancing.
&lt;/p&gt;
&lt;p&gt;
Another big OSGi issue is version management. If you specify &lt;code&gt;version=1.0.0&lt;/code&gt;, it means &lt;code&gt;[1.0.0, &amp;#8734;]&lt;/code&gt;. You should at least use &lt;code&gt;version=[1.0.0,2.0.0]&lt;/code&gt;. When using OSGi, you have to be careful and follow something similar to &lt;a href=&quot;http://apr.apache.org/versioning.html&quot;&gt;Apache&apos;s APR Project Versioning Guidelines&lt;/a&gt; so that you can easily identify release compatibility.
&lt;/p&gt;
&lt;p&gt;At LinkedIn, the OSGi implementation is progressing, but there&apos;s still a lot of work to do. First of all, a bundle repository needs to be created. Ivy and bnd is used to generate bundles. Containers are being evaluated and Infiniflow is most likely the one that will be used. LinkedIn Spring (an enhanced version of Spring) and SCA will be used to deploy composites. Work on load-balancing and distribution is in progress as is work on tooling and build integration (Sigil from Paremus). 
&lt;/p&gt;
&lt;p&gt;In conclusion, LinkedIn will definitely use OSGi but they&apos;ll do their best to hide the complexity from the build system and from developers. For more information on OSGi at LinkedIn, stay tuned to the &lt;a href=&quot;http://blog.linkedin.com/blog/engineering/&quot;&gt;LinkedIn Engineering Blog&lt;/a&gt;. Yan has promised to blog about some of the challenges LinkedIn has faced and how he&apos;s fixed them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Yan has posted his presentation on the &lt;a href=&quot;http://blog.linkedin.com/blog/2008/10/colorado-softwa.html&quot;&gt;LinkedIn Engineering Blog&lt;/a&gt;.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/jetty_and_resin_closing_in</id>
        <title type="html">Jetty and Resin closing in on Tomcat&apos;s popularity</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/jetty_and_resin_closing_in"/>
        <published>2008-04-11T08:42:48-06:00</published>
        <updated>2014-05-08T19:47:19-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="jetty" scheme="http://roller.apache.org/ns/tags/" />
        <category term="resin" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">From Greg Wilkin&apos;s &lt;a href=&quot;http://blogs.webtide.com/gregw/2008/04/11/1207878698135.html&quot;&gt;Jetty Improves in Netcraft survey (again)&lt;/a&gt;:&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
As with most open source projects, it&apos;s very hard to get a measure of who/how/where/why Jetty is being used a deployed. Downloads long ago became meaningless with the advent of many available bundling and distribution channels. The &lt;a href=&quot;http://survey.netcraft.com/Reports/200804/&quot;&gt;Netcraft Web Survey&lt;/a&gt; is  one good measure, as it scans the internet and identifies which server sites run. In the results released April 2008, Jetty is identified for 278,501 public server, which is 80% of the market share of our closest &quot;competitor&quot; tomcat (identified as coyote in the survey). Jetty is currently 12th in the league table of identified servers of all types and will be top 10 in 6 months if the current trajectory continues.&lt;/p&gt;
&lt;p&gt;If you look at the Netcraft numbers, you might also notice that Resin isn&apos;t far behind Jetty. If you look at the Indeed Job Trends graphs for the three, there seems to be some interesting information there too. The first graph is absolute and the second is relative.&lt;/p&gt;
&lt;div style=&quot;width:540px&quot;&gt;
&lt;a href=&quot;http://www.indeed.com/jobtrends?q=tomcat%2C+resin%2C+jetty&quot; title=&quot;tomcat, resin, jetty Job Trends&quot;&gt;
&lt;img width=&quot;540&quot; height=&quot;300&quot; src=&quot;//www.indeed.com/trendgraph/jobgraph.png?q=tomcat%2C+resin%2C+jetty&quot; border=&quot;0&quot; alt=&quot;tomcat, resin, jetty Job Trends graph&quot;&gt;
&lt;/a&gt;
&lt;table width=&quot;100%&quot; cellpadding=&quot;6&quot; cellspacing=&quot;0&quot; border=&quot;0&quot; style=&quot;font-size:80%&quot;&gt;&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;http://www.indeed.com/jobtrends?q=tomcat%2C+resin%2C+jetty&quot;&gt;tomcat, resin, jetty Job Trends&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;a href=&quot;http://www.indeed.com/jobs?q=tomcat&quot;&gt;tomcat jobs&lt;/a&gt; - &lt;a href=&quot;http://www.indeed.com/jobs?q=resin&quot;&gt;resin jobs&lt;/a&gt; - &lt;a href=&quot;http://www.indeed.com/jobs?q=jetty&quot;&gt;jetty jobs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div style=&quot;width:540px&quot;&gt;
&lt;a href=&quot;http://www.indeed.com/jobtrends?q=tomcat%2C+resin%2C+jetty&amp;relative=1&amp;relative=1&quot; title=&quot;tomcat, resin, jetty Job Trends&quot;&gt;
&lt;img width=&quot;540&quot; height=&quot;300&quot; src=&quot;//www.indeed.com/trendgraph/jobgraph.png?q=tomcat%2C+resin%2C+jetty&amp;relative=1&quot; border=&quot;0&quot; alt=&quot;tomcat, resin, jetty Job Trends graph&quot;&gt;
&lt;/a&gt;
&lt;table width=&quot;100%&quot; cellpadding=&quot;6&quot; cellspacing=&quot;0&quot; border=&quot;0&quot; style=&quot;font-size:80%&quot;&gt;&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;http://www.indeed.com/jobtrends?q=tomcat%2C+resin%2C+jetty&amp;relative=1&amp;relative=1&quot;&gt;tomcat, resin, jetty Job Trends&lt;/a&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;a href=&quot;http://www.indeed.com/jobs?q=tomcat&quot;&gt;tomcat jobs&lt;/a&gt; - &lt;a href=&quot;http://www.indeed.com/jobs?q=resin&quot;&gt;resin jobs&lt;/a&gt; - &lt;a href=&quot;http://www.indeed.com/jobs?q=jetty&quot;&gt;jetty jobs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;If you&apos;re using &lt;a href=&quot;http://static.springframework.org/osgi/docs/current/reference/html/web.html&quot;&gt;Spring Dynamic Modules&lt;/a&gt; to deploy a web application, which server do you think is better? Both Tomcat 6 and Jetty 6 seem to work just fine in Equinox. </content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/glassfish_2_vs_tomcat_6</id>
        <title type="html">GlassFish 2 vs. Tomcat 6</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/glassfish_2_vs_tomcat_6"/>
        <published>2007-09-19T16:55:31-06:00</published>
        <updated>2012-10-19T21:01:02-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="glassfish" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">In &lt;a href=&quot;http://rollerweblogger.org/roller/entry/switched&quot;&gt;Switched&lt;/a&gt;, Dave says:&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
Now that Glassfish V2 is out I&apos;m switching from Tomcat to Glassfish for all of my development. It&apos;s more than fast enough. With Glassfish on my MacBook Pro, Roller restart time is about 8 seconds compared to 16 with Tomcat. And the quality is high; the admin console, the asadmin command-line utility and the docs are all excellent. The dog food is surprisingly tasty ;-)
&lt;/p&gt;
&lt;p&gt;I did some brief and very non-scientific performance comparisons myself:
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Startup Time with no applications deployed:&lt;/strong&gt;&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;Tomcat 6: 3 seconds&lt;/li&gt;
&lt;li&gt;GlassFish 2: 8 seconds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Startup Time with AppFuse 2.0 (Struts + Hibernate version) as a WAR&lt;/strong&gt;&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;Tomcat 6: 15 seconds&lt;/li&gt;
&lt;li&gt;GlassFish 2: 16 seconds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Environment:&lt;/strong&gt;&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;JAVA_OPTS=&quot;-Xms768M -Xmx768M -XX:PermSize=512m -XX:MaxPermSize=512m -Djava.awt.headless=true -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -XX:+UseConcMarkSweepGC -server&quot;&lt;/li&gt;
&lt;li&gt;OS X 10.4.10, 2.2 GHz Intel Core 2 Duo, 4 GB 667 MHz DDR2 SDRAM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since this was a very non-scientific experiment, it&apos;s possible the last two are actually the same. It&apos;s strange that Dave is seeing Roller startup twice as fast on GlassFish. Maybe they&apos;ve done some Roller deployment optimization?
&lt;/p&gt;
&lt;p&gt;I realize startup times aren&apos;t that important. However, as Dave mentions, they (and context reloading) can be extremely important when developing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I got to thinking that Dave is probably referring to context reloading. Here&apos;s a comparison of how long it takes for both servers to pick up a new WAR (and start the application) when it&apos;s dropped into their autodeploy directories.&lt;/p&gt;
&lt;ul class=&quot;glassList&quot;&gt;
&lt;li&gt;Tomcat 6: 14-16 seconds&lt;/li&gt;
&lt;li&gt;GlassFish 2: 9 seconds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The strange thing about Tomcat is it takes 6-8 seconds to recognize a new WAR has been deployed. Does Tomcat have a polling increment that can be increased during development? 
&lt;/p&gt;
&lt;p&gt;Regardless, it&apos;s impressive that the GlassFish guys have made things that much faster for developers. &lt;em&gt;Nice work folks!&lt;/em&gt;
&lt;p&gt;
These days, I try to use &lt;strong&gt;mvn jetty:run&lt;/strong&gt; on projects. Then I don&apos;t have to worry about deploying, just save and wait for the reload. Time to wait for AppFuse 2.0 to reload using the Maven Jetty Plugin (version 6.1.5)? &lt;strong&gt;7 seconds&lt;/strong&gt;. Of course, it&apos;d be nice if I could somehow get this down to 1 or 2 seconds.
&lt;/p&gt;
&lt;p&gt;Maybe Dave should use the &lt;a href=&quot;http://opensource.atlassian.com/projects/roller/browse/ROL-1527&quot;&gt;Maven&lt;/a&gt; &lt;a href=&quot;http://opensource.atlassian.com/projects/roller/browse/ROL-1537&quot;&gt;integration&lt;/a&gt; for Roller to decrease his reload times. ;-)</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/proposed_tomcat_enhancement_add_flag</id>
        <title type="html">Proposed Tomcat Enhancement: Add flag to escape JSP&apos;s EL by default</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/proposed_tomcat_enhancement_add_flag"/>
        <published>2007-09-19T16:29:11-06:00</published>
        <updated>2007-09-27T02:07:05-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">I &lt;a href=&quot;http://www.nabble.com/-Proposal--Add-flag-to-escape-JSP%27s-EL-by-default-tf4388103.html&quot;&gt;posted the following&lt;/a&gt; to the Tomcat Developers mailing list. Unfortunately, it didn&apos;t get any responses, which means (to me) that no one cares about this feature. I guess the good thing is they didn&apos;t veto it. &lt;/p&gt;
&lt;p class=&quot;smokey&quot; style=&quot;padding: 10px 15px; border: 1px solid #666&quot;&gt;
Hello all,
&lt;br/&gt;&lt;br/&gt;
I&apos;m working for a client that&apos;s using a proprietary Servlet/JSP-based framework that runs on Tomcat. They have their own custom JSP compiler and they&apos;re looking to move to a standard JSP compiler. One of the things their compiler supports is automatic escaping of XML in expressions. For example, ${foo} would be escaped so &amp;lt;body&amp;gt; -&amp;gt; &amp;amp;lt;body&amp;amp;gt;. JSP EL does not do this. It *doesn&apos;t* escape by default and instead requires you to wrap your expressions with &amp;lt;c:out/&amp;gt; if you want escaping.
&lt;br/&gt;&lt;br/&gt;
I&apos;d like to ask what developers think about adding a flag (similar to trimSpaces in conf/web.xml) that allows users to change the escaping behavior from false to true?
&lt;br/&gt;&lt;br/&gt;
I think this is a good option to have as it allows security-conscious organizations to paranoid and escape all content by default.
&lt;br/&gt;&lt;br/&gt;
Thanks,
&lt;br/&gt;&lt;br/&gt;
Matt
&lt;br/&gt;&lt;br/&gt;
Related: &lt;a href=&quot;http://raibledesigns.com/rd/entry/java_web_frameworks_and_xss&quot;&gt;http://raibledesigns.com/rd/entry/java_web_frameworks_and_xss&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;What do you think? Is there anything wrong with adding this (optional) feature to Tomcat? Enhancing security is a good thing - right?
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I&apos;ve entered an &lt;a href=&quot;http://issues.apache.org/bugzilla/show_bug.cgi?id=43497&quot;&gt;enhancement request&lt;/a&gt; for this feature and &lt;a href=&quot;http://issues.apache.org/bugzilla/attachment.cgi?id=20891&quot;&gt;attached a patch&lt;/a&gt;. 
</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/jetty_6_x_versus_tomcat</id>
        <title type="html">Jetty 6.x versus Tomcat 6.x</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/jetty_6_x_versus_tomcat"/>
        <published>2007-08-15T09:50:17-06:00</published>
        <updated>2012-11-11T02:00:40-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="jetty" scheme="http://roller.apache.org/ns/tags/" />
        <category term="resin" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">An AppFuse user &lt;a href=&quot;http://www.nabble.com/Jetty-6.1-versus-Tomcat-6.x-tf4270314s2369.html&quot;&gt;asks&lt;/a&gt;:&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
Has anyone done any performance benchmarking between Jetty 6.x and Tomcat 6.x to see  which one is better for production use in terms of scalability, performance and ease-of-use? I&apos;m gearing towards Jetty 6.1 but want to hear other&apos;s opinions first.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I admit, I completely changed the wording in this quote to make it more readable.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Most of the companies I&apos;ve worked with in recent years have been using Tomcat (very successfully) in production. However, I also know the Contegix and JavaLobby guys continue to swear by Resin for the most part. What&apos;s your opinion? 
&lt;/p&gt;
&lt;p&gt;
IMHO, I don&apos;t think it really matters - they&apos;re all good enough for production use.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/configuring_tomcat_for_production</id>
        <title type="html">Configuring Tomcat for Production</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/configuring_tomcat_for_production"/>
        <published>2007-04-16T16:05:03-06:00</published>
        <updated>2012-11-11T02:00:40-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <category term="oom" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">From &lt;a href=&quot;http://blogs.atlassian.com/developer/2007/04/4_more_days_in_a_leaky_boat.html&quot;&gt;The Atlassian Developer Blog&lt;/a&gt;:
&lt;/p&gt;
&lt;p class=&quot;quote&quot;&gt;
You appear to be running Tomcat in development mode.
(&lt;a href=&quot;http://tomcat.apache.org/tomcat-5.5-doc/jasper-howto.html&quot;&gt;http://tomcat.apache.org/tomcat-5.5-doc/jasper-howto.html&lt;/a&gt;)
&lt;br/&gt;&lt;br/&gt;
This means that source of every JSP is held in memory to provide
detailed messages in the event of an error. If you have large JSPs
this will hurt. It looks like this accounts for 50MB+
&lt;/p&gt;
&lt;p&gt;From Tomcat&apos;s &lt;a href=&quot;http://tomcat.apache.org/tomcat-5.5-doc/jasper-howto.html#Production%20Configuration&quot;&gt;Production Configuration&lt;/a&gt; documentation:&lt;/p&gt;
&lt;div class=&quot;quote&quot; style=&quot;color: #666; margin-left: 0; margin-bottom: 10px&quot;&gt;
&lt;p&gt;The main JSP optimization which can be done is precompilation of JSPs. However,
this might not be possible (for example, when using the jsp-property-group feature)
or practical, in which case the configuration of the Jasper servlet becomes critical.&lt;/p&gt;

&lt;p&gt;When using Jasper 2 in a production Tomcat server you should consider
making the following changes from the default configuration.
&lt;/p&gt;&lt;ul style=&quot;margin-bottom: 0&quot;&gt;
&lt;li&gt;&lt;strong&gt;development&lt;/strong&gt; - To disable on access checks for JSP
pages compilation set this to &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;genStringAsCharArray&lt;/strong&gt; - To generate slightly more efficient 
char arrays, set this to &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;modificationTestInterval&lt;/strong&gt; - If development has to be set to
&lt;code&gt;true&lt;/code&gt; for any reason (such as dynamic generation of JSPs), setting
this to a high value will improve performance a lot.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;trimSpaces&lt;/strong&gt; - To remove useless bytes from the response,
set this to &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Seems like good information to know.</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/mixing_apache_http_server_mod</id>
        <title type="html">Mixing Apache HTTP Server, mod_rewrite and mod_jk</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/mixing_apache_http_server_mod"/>
        <published>2007-04-16T12:07:10-06:00</published>
        <updated>2007-04-18T02:52:34-06:00</updated> 
        <category term="/Java" label="Java" />
        <category term="mod_rewrite" scheme="http://roller.apache.org/ns/tags/" />
        <category term="mod_jk" scheme="http://roller.apache.org/ns/tags/" />
        <category term="apache" scheme="http://roller.apache.org/ns/tags/" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">I&apos;m trying to configure Apache and Tomcat to work with a desired architecture for doing &lt;a href=&quot;http://www.clickz.com/showPage.html?page=3349901&quot;&gt;A/B Testing&lt;/a&gt; on my current project. Our basic idea is that we&apos;ll deploy entirely new WAR files when we have a test, then use the magic of Apache&apos;s mod_rewrite, mod_jk and possible the &lt;a href=&quot;http://tuckey.org/urlrewrite/&quot;&gt;UrlRewriteFilter&lt;/a&gt; to keep the URLs somewhat consistent between version A and version B. Here&apos;s some questions I have for those folks who might&apos;ve done this before:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Is it possible to use Apache&apos;s mod_rewrite to map http://www.domain.com/?v=1 to http://www.domain.com/1 (this allows us to have two different applications/wars served up to the same domain).&lt;/li&gt;
&lt;li&gt;If #1 is possible, what&apos;s the RewriteRule for allowing the parameter to be anywhere in the query string, but still allowing the target to use it as the context name?&lt;/li&gt;
&lt;li&gt;Is it possible to use something in the WAR (likely the UrlRewriteFilter) to produce HTML that has rewritten links (i.e. http://www.domain.com/?id=1 in the WAR whose context is 1)?
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
In other words, can Apache forward to the correct app going in, and can that app rewrite its URLs so those same URLs are used when going out?
&lt;br/&gt;&lt;br/&gt;
I believe this is all possible. However, I am having difficulty getting mod_jk to allow mod_rewrite to be processed first. If I have the following in httpd.conf, it seems like htdocs/.htaccess gets bypassed.
&lt;/p&gt;
&lt;pre&gt;
JkMount /* loadbalancer
&lt;/pre&gt;
&lt;p&gt;Is it possible to configure Apache/mod_jk so WARs can hang off the root, but still use mod_rewrite? If not, the only solution I can think of is to use UrlRewriteFilter in the WAR to forward to another context when a &quot;v&quot;  parameter is in the URL. Currently, the UrlRewriteFilter doesn&apos;t allow forwarding to another context. The good news is the &lt;a href=&quot;http://techpicks.wordpress.com/2007/01/16/howto-pass-request-and-response-from-one-servlet-to-another-servlet/&quot;&gt;Servlet API allows it&lt;/a&gt;. I got it working in Tomcat (with crossContext enabled) and &lt;a href=&quot;https://urlrewrite.dev.java.net/issues/show_bug.cgi?id=10&quot;&gt;wrote a patch&lt;/a&gt; for the UrlRewriteFilter&lt;/a&gt;.
&lt;br/&gt;&lt;br/&gt;
Anyone out there have experience doing A/B Testing in a Java webapp? If so, did you try to disguise the URLs for the different versions?&lt;br/&gt;&lt;br/&gt;
&lt;strong&gt;Update:&lt;/strong&gt;
I&apos;ve got a bit of this working. The magic formula seems to be don&apos;t try to hang things off the root - use mod_rewrite to make things &lt;em&gt;appear&lt;/em&gt; to hang off the root.
&lt;br/&gt;&lt;br/&gt;
First of all, I posted a &lt;a href=&quot;http://www.nabble.com/Mixing-Apache%27s-mod_rewrite-with-mod_proxy-tf3587361.html#a10025094&quot;&gt;message similar to this post&lt;/a&gt; to the tomcat-user mailing list. Before I did so, I discovered mod_proxy_ajp, which happens to look like &lt;a href=&quot;http://getahead.org/blog/joe/2006/02/01/mod_jk_is_dead_long_live_mod_proxy_ajp.html&quot;&gt;the successor to mod_jk&lt;/a&gt;. AFAICT, it doesn&apos;t allow fine-grained rules (i.e. only serve up *.jsp and *.do from Tomcat), so I&apos;ll stick with mod_jk for now.
&lt;br/&gt;&lt;br/&gt;
Rather than proxying all root-level requests to Tomcat, I changed my JkMount to expect all Tomcat applications to have a common prefix. For example, &quot;app&quot;.
&lt;/p&gt;
&lt;pre&gt;
JkMount /app* loadbalancer
&lt;/pre&gt;
&lt;p&gt;This allows me to create RewriteRules in htdocs/.htaccess to detect the &quot;v&quot; parameter and forward to Tomcat.&lt;/p&gt;
&lt;pre&gt;
RewriteEngine On

RewriteCond     %{QUERY_STRING}     ^v=(.*)$
RewriteRule     ^(.*)$              /app%1/ [L]
&lt;/pre&gt;
&lt;p&gt;This isn&apos;t that robust as adding another parameter causes the forward to fail. However, it does successfully forward http://localhost/?v=1 to /app1 on Tomcat and http://localhost/?v=2 to /app2 on Tomcat. 
&lt;br/&gt;&lt;br/&gt;
What about when ?v=3 is passed in? There&apos;s no /app3 installed on Tomcat, so Tomcat&apos;s ROOT application will be hit. Using the UrlRewriteFilter, I installed a root application (which we&apos;ll likely need anyway) with the following rule:&lt;/p&gt;
&lt;pre&gt;
    &amp;lt;rule&amp;gt;
        &amp;lt;from&amp;gt;^/app(.*)$&amp;lt;/from&amp;gt;
        &amp;lt;to type=&quot;forward&quot;&amp;gt;/&amp;lt;/to&amp;gt;
    &amp;lt;/rule&amp;gt;
&lt;/pre&gt;
&lt;p&gt;So I&apos;ve solved problem #1: Using URL parameters to serve up different web applications. To solve the second issue (webapps should rewrite their URLs to delete their context path), I found two solutions:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Use &lt;a href=&quot;http://apache.webthing.com/mod_proxy_html/&quot;&gt;mod_proxy_html&lt;/a&gt;. Sounds reasonable, but requires the use of mod_proxy.&lt;/li&gt;
    &lt;li&gt;Use the UrlRewriteFilter and outbound-rules.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Since I&apos;m using mod_jk, #2 is the reasonable choice. I added the following link in my /app1/index.jsp:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;a href=&quot;&amp;lt;c:url value=&quot;/products.jsp&quot;/&amp;gt;&quot;&amp;gt;link to products&amp;lt;/a&amp;gt;
&lt;/pre&gt;
&lt;p&gt;By default, this gets written out as http://localhost/app1/products.jsp. To change it to http://localhost/products.jsp?v=1, I added the following to urlrewrite.xml:
&lt;/p&gt;
&lt;pre&gt;
    &amp;lt;outbound-rule&amp;gt;
        &amp;lt;from&amp;gt;^/app1/(.*)$&amp;lt;/from&amp;gt;
        &amp;lt;to&amp;gt;/$1?v=1&amp;lt;/to&amp;gt;
    &amp;lt;/outbound-rule&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This produces the desired effect, except that when I click on the link, a new session is created every time. AFAICT, I probably need to do something with cookies so the jsessionid cookie is set for the proper path.
&lt;br/&gt;&lt;br/&gt;
Not bad for a day&apos;s work. Only 2 questions remain:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What&apos;s a more robust RewriteRule that doesn&apos;t care about other parameters being passed in?&lt;/li&gt;
&lt;li&gt;What do I need to do so new sessions aren&apos;t created when using an outbound-rule?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
It&apos;s entirely possible that mod_proxy_ajp with mod_rewrite_html is best tool for this. Can mod_proxy handle wildcards like JkMount can? I&apos;ve heard it&apos;s faster than mod_jk, so it probably warrants further investigation.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2:&lt;/strong&gt; I achieved the desired result using mod_rewrite, mod_jk and the UrlRewriteFilter (for outgoing links). Here&apos;s what I put in htdocs/.htaccess (on Apache):&lt;/p&gt;
&lt;pre&gt;
RewriteEngine On

# http://domain/?v=1 --&gt; http://domain/app1/?v=1
RewriteCond     %{QUERY_STRING}     v=([^&amp;]+)
RewriteRule     ^(.*)$              /app%1/$1 [L]

# http://domain --&gt; http://domain/app (default ROOT in Tomcat)
RewriteRule     ^$                  /app/ [L]
&lt;/pre&gt;
&lt;p&gt;And in the urlrewrite.xml of each webapp:&lt;/p&gt;
&lt;pre&gt;
   &amp;lt;outbound-rule&amp;gt;
       &amp;lt;from&amp;gt;^/app(&amp;#91;0-9&amp;#93;)/(&amp;#91;A-Za-z0-9&amp;#93;+)\.(&amp;#91;A-Za-z0-9&amp;#93;+)$&amp;lt;/from&amp;gt;
       &amp;lt;to&amp;gt;/$2.$3?v=$1&amp;lt;/to&amp;gt;
   &amp;lt;/outbound-rule&amp;gt;

   &amp;lt;outbound-rule&amp;gt;
       &amp;lt;from&amp;gt;^/app(&amp;#91;0-9&amp;#93;)/(&amp;#91;A-Za-z0-9&amp;#93;+)\.(&amp;#91;A-Za-z0-9&amp;#93;+)\?(.*)$&amp;lt;/from&amp;gt;
       &amp;lt;to&amp;gt;/$2.$3?$4&amp;amp;amp;v=$1&amp;lt;/to&amp;gt;
   &amp;lt;/outbound-rule&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Next I&apos;ll try to see if I can get it all working with &lt;a href=&quot;http://httpd.apache.org/docs/2.2/mod/mod_proxy_ajp.html&quot;&gt;mod_proxy_ajp&lt;/a&gt; and &lt;a href=&quot;http://apache.webthing.com/mod_proxy_html/&quot;&gt;mod_proxy_html&lt;/a&gt;. Anyone know the equivalent of &quot;JkMount /app*&quot; when using LocationMatch with mod_proxy?</content>
    </entry>
    <entry>
        <id>https://raibledesigns.com/rd/entry/upgrading_to_tomcat_6</id>
        <title type="html">Upgrading to Tomcat 6</title>
        <author><name>Matt Raible</name></author>
        <link rel="alternate" type="text/html" href="https://raibledesigns.com/rd/entry/upgrading_to_tomcat_6"/>
        <published>2007-03-02T00:44:46-07:00</published>
        <updated>2007-03-02T07:45:24-07:00</updated> 
        <category term="/Java" label="Java" />
        <category term="tomcat" scheme="http://roller.apache.org/ns/tags/" />
        <content type="html">&lt;a href=&quot;http://erik.thauvin.net/blog/news.jsp?date=2007-03-01#557&quot;&gt;Erik did it&lt;/a&gt;, so I tried it as well. This site is now running Tomcat 6.0.10 and it has to be the least painful major Tomcat upgrade I&apos;ve ever done. By &lt;em&gt;major&lt;/em&gt;, I mean upgrading from one version number (5.5.17) to the next. Apparently, no XML files changed (like they did from 4.1.x -&gt; 5.0.x -&gt; 5.5.x) because I was able to copy over conf/server.xml and conf/Catalina/** without any issues. The only change I had to make was to copy commons-logging.jar from Roller&apos;s WEB-INF/lib to JSPWiki&apos;s.&lt;br/&gt;&lt;br/&gt;
I have seen a couple of the following errors in my log files since I upgraded, so if you see any strange behavior, please let me know.&lt;/p&gt;
&lt;pre&gt;
2-Mar-2007 12:36:10 AM org.apache.tomcat.util.http.Parameters processParameters
WARNING: Parameters: Character decoding failed. Parameter skipped.
java.io.CharConversionException: EOF
        at org.apache.tomcat.util.buf.UDecoder.convert(UDecoder.java:83)
        at org.apache.tomcat.util.buf.UDecoder.convert(UDecoder.java:49)
        at org.apache.tomcat.util.http.Parameters.urlDecode(Parameters.java:410)
        at org.apache.tomcat.util.http.Parameters.processParameters(Parameters.java:392)
        at org.apache.tomcat.util.http.Parameters.processParameters(Parameters.java:508)
        at org.apache.tomcat.util.http.Parameters.handleQueryParameters(Parameters.java:266)
        at org.apache.catalina.connector.Request.parseParameters(Request.java:2404)
        at org.apache.catalina.connector.Request.getParameterValues(Request.java:1089)
        at org.apache.catalina.connector.RequestFacade.getParameterValues(RequestFacade.java:396)
        at javax.servlet.ServletRequestWrapper.getParameterValues(ServletRequestWrapper.java:189)
        at org.acegisecurity.wrapper.SavedRequestAwareWrapper.getParameter(SavedRequestAwareWrapper.java:325)
        at org.apache.roller.ui.rendering.velocity.deprecated.OldPageRequest.&lt;init&gt;(OldPageRequest.java:164)
        at org.apache.roller.ui.rendering.velocity.deprecated.RedirectServlet.figurePageRedirect(RedirectServlet.java:285)
        at org.apache.roller.ui.rendering.velocity.deprecated.RedirectServlet.doGet(RedirectServlet.java:131)
&lt;/pre&gt;
&lt;p&gt;I tested AppFuse 2.0 on Tomcat 6.0.10 earlier today and impressed that 1) Cargo worked perfectly and 2) most of the web frameworks worked. Which one didn&apos;t?  You guessed it - good ol&apos; JSF.  That&apos;s OK though, the JSF version of AppFuse (MyFaces 1.1.5 with Facelets 1.1.11) doesn&apos;t work with Jetty 6.1.1 either. The good news is I found a workaround - removing the el-api dependency from my pom.xml makes it work on both. &lt;/p&gt;
&lt;pre&gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;javax.el&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;el-api&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.2&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
&lt;/pre&gt;
&lt;p&gt;If I remove this dependency, everything works fine on Tomcat 6.0.10 and Jetty 6.1.1. Unfortunately, it seems this dependency is needed for Tomcat 5.x. Hopefully some fancy stuff with Maven profiles can fix this incompatibility.</content>
    </entry>
</feed>

