Fri 28 Oct 2011
Executable WAR file
Recently Adam, Steve (the Chief) and myself have been working on a new service that involves a brand new web-application. I won’t bore you with details of what it does because it won’t be publicly facing. Regardless, we had to consider deployment options and after a few false starts we decided to build an “executable WAR”. Basically a war file that you can start up by calling “java -jar mywebapp.war”.
Why?
First we liked the idea of having a fully contained application in a neat and tidy package. Second, this isn’t a case where we can build the war and let our operations team pick the container. Our application requires a servlet 3.0 container so our options were limited. And finally, we just wanted to learn how to do it
How?
Our first naive thought was that if a war file has a manifest with a Main-Class declaration that everything would just work. We were very, very wrong. Since war files keep their classes in WEB-INF/classes and not in the root of the jar this failed. Next we put our main class in the root of the jar, it started but our app server classes couldn’t be found because we put them in WEB-INF/lib, *sigh*. Then it all started coming together, any dependency that we typically consider “provided” will get un-jarred along with our main class into the root of the jar, then the rest will be the typical war format. It looks like this:

We did this all in buildr by adding our own packager and calling it :executable_war.
module Rally
module Packaging
module ExecutableWar
class ExecutableWarTask < Buildr::Packaging::Java::JarTask
attr_accessor :main_class, :libs, :provided, :classes
def initialize(*args) #:nodoc:
super
enhance { |jar|
libs.each { |lib| lib.invoke if lib.respond_to?(:invoke) }
classes.each { |dir| jar.include dir, :as => 'WEB-INF/classes' }
classes.each do |dir|
class_dir = dir.to_s
class_dir_classes = "#{class_dir}/**/*.class"
main_class_path = main_class.gsub("\.", "/")
Dir.glob(class_dir_classes) do |file|
jar.path(File.dirname(file.sub(class_dir, ""))).include(file) if file.include?(main_class_path)
end
end
provided_target_dir = "target/provided"
mkdir_p(provided_target_dir)
cd(provided_target_dir) do
provided.each do |dependency|
`jar -xf #{Buildr.artifact(dependency)}`
end
end
jar.path("/").include("#{provided_target_dir}/*")
jar.path('WEB-INF/lib').include Buildr.artifacts(libs)
}
end
def main_class=(main_class)
@main_class = main_class
add_to_manifest({'Main-Class' => main_class})
end
def version=(version)
@version = version
add_to_manifest({'Implementation-Build' => version})
end
private
def add_to_manifest(options)
if self.manifest
self.manifest = self.manifest.merge(options)
else
self.manifest = options
end
end
end
def package_as_executable_war_spec(spec) #:nodoc:
spec.merge(:type=>:jar)
end
def package_as_executable_war(file_name) #:nodoc:
ExecutableWarTask.define_task(file_name).tap do |war|
war.with path_to(:source, :main, :webapp)
war.with :classes => [compile.target, resources.target]
end
end
end
end
end
class Buildr::Project
include Rally::Packaging::ExecutableWar
end
And here is how we use it from our buildfile, where PROVIDED represents the buildr dependencies on things like Jetty and the Servlet API
package(:executable_war).with(
:libs => compile.dependencies - PROVIDED,
:main_class => "com.rallydev.server.jetty.EmbeddedJetty",
:provided => PROVIDED,
:version => "1.0")
And to start the server, as alluded to above chose Jetty 8, here is our code. Note the DEV_MODE flag so we can still do in place development when not deploying the jar file.
package com.rallydev.server.jetty;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import java.net.InetSocketAddress;
public class EmbeddedJetty {
public static void main(String[] args) throws Exception {
InetSocketAddress address = new InetSocketAddress("0.0.0.0", 8080);
String warPath = Boolean.getBoolean("DEV_MODE") ?
"src/main/webapp" :
EmbeddedJetty.class.getProtectionDomain().getCodeSource().getLocation().getPath();
Server server = new Server(address);
WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setWar(warPath);
server.setHandler(context);
server.start();
server.join();
}
}
What does everyone think? Leave a comment and tell us what we screwed up

Other than potentially not needing to explode the war file, what advantages does this technique provide over zipping up the war, config, and possibly the appserver itself? The single war model seems to make it difficult to ship any configuration files or helper scripts that are needed by the deployment system.
i needed to make a similar thing …
we also wanted to package our whole application in a single file, for easy release-deployment in server-environments, and mainly that none of our developers could change the release with other versions
sadly our release also contains main-applications, not only servlets …
so instead of an executable-war i decided to pack all stuff in a thing i called “launcher.jar” … this launcher extracts all containing jars in a temporary folder, and starts tomcat-embedded or just a main-application if wanted …
for my solution i needed to use a custom-classloader that loads all libraries and then starts tomcat-embedded, so there is no WAR-File needed anymore …
very hacky solution
but it satisfied our requirements.