Permalink
Browse files

Working Jetty (experimental).

To try out the embedded Jetty server before the initial release, you
need to build the Warbler Embedded Jetty support. Change to the
`ext/jetty` directory and type `mvn install`. This creates a single
jar file with all of the Jetty dependencies as well as a main class to
launch the embedded server. That jar file is then embedded in the
resulting executable war created by Warbler.
  • Loading branch information...
nicksieger committed Mar 13, 2012
1 parent 128b214 commit 0558a285eb59a0801cf7c0f274777b06b63883b3
Showing with 134 additions and 54 deletions.
  1. +3 −10 Rakefile
  2. +63 −16 ext/WarMain.java
  3. +34 −11 ext/jetty/src/main/java/JettyWarMain.java
  4. +1 −0 lib/warbler/config.rb
  5. +33 −17 lib/warbler/web_server.rb
  6. BIN lib/warbler_jar.jar
@@ -33,9 +33,9 @@ begin
directory "pkg/classes"
CLEAN << "pkg"
file jar_file => FileList['ext/**/*.java', 'pkg/classes'] do
file jar_file => FileList['ext/*.java', 'pkg/classes'] do
rm_rf FileList['pkg/classes/**/*']
ant.javac :srcdir => "ext", :destdir => "pkg/classes",
ant.javac :srcdir => "ext", :includes => "*.java", :destdir => "pkg/classes",
:source => "1.5", :target => "1.5", :debug => true,
:classpath => "${java.class.path}:${sun.boot.class.path}",
:includeantRuntime => false
@@ -52,14 +52,7 @@ rescue LoadError
end
# Make sure jar gets compiled before the gem is built
task Rake::Task['build'].prerequisites.first => :jar
task :warbler_jar => 'pkg' do
ruby "-rubygems", "-Ilib", "-S", "bin/warble"
mv "warbler.jar", "pkg/warbler-#{Warbler::VERSION}.jar"
end
task :build => :warbler_jar
task :build => :jar
require 'rdoc/task'
RDoc::Task.new(:docs) do |rd|
@@ -13,10 +13,13 @@
import java.io.File;
import java.io.FileOutputStream;
import java.util.Arrays;
import java.util.Properties;
import java.util.Map;
public class WarMain implements Runnable {
public static final String MAIN = "/" + WarMain.class.getName().replace('.', '/') + ".class";
public static final String WINSTONE_JAR = "/WEB-INF/webserver.jar";
public static final String WEBSERVER_PROPERTIES = "/WEB-INF/webserver.properties";
public static final String WEBSERVER_JAR = "/WEB-INF/webserver.jar";
private String[] args;
private String path, warfile;
@@ -29,16 +32,17 @@ public WarMain(String[] args) throws Exception {
this.path = mainClass.toURI().getSchemeSpecificPart();
this.warfile = this.path.replace("!" + MAIN, "").replace("file:", "");
this.debug = isDebug();
this.webroot = File.createTempFile("winstone", "webroot");
this.webroot = File.createTempFile("warbler", "webroot");
this.webroot.delete();
this.webroot.mkdirs();
this.webroot = new File(this.webroot, new File(warfile).getName());
debug("webroot directory is " + this.webroot.getPath());
Runtime.getRuntime().addShutdownHook(new Thread(this));
}
private URL extractWinstone() throws Exception {
InputStream jarStream = new URL("jar:" + path.replace(MAIN, WINSTONE_JAR)).openStream();
File jarFile = File.createTempFile("winstone", ".jar");
private URL extractWebserver() throws Exception {
InputStream jarStream = new URL("jar:" + path.replace(MAIN, WEBSERVER_JAR)).openStream();
File jarFile = File.createTempFile("webserver", ".jar");
jarFile.deleteOnExit();
FileOutputStream outStream = new FileOutputStream(jarFile);
try {
@@ -51,26 +55,69 @@ private URL extractWinstone() throws Exception {
jarStream.close();
outStream.close();
}
debug("winstone.jar extracted to " + jarFile.getPath());
debug("webserver.jar extracted to " + jarFile.getPath());
return jarFile.toURI().toURL();
}
private void launchWinstone(URL jar) throws Exception {
private Properties getWebserverProperties() throws Exception {
Properties props = new Properties();
try {
InputStream is = getClass().getResourceAsStream(WEBSERVER_PROPERTIES);
props.load(is);
} catch (Exception e) {
}
for (Map.Entry entry : props.entrySet()) {
String val = (String) entry.getValue();
val = val.replace("{{warfile}}", warfile).replace("{{webroot}}", webroot.getAbsolutePath());
entry.setValue(val);
}
if (props.getProperty("props") != null) {
String[] propsToSet = props.getProperty("props").split(",");
for (String key : propsToSet) {
System.setProperty(key, props.getProperty(key));
}
}
return props;
}
private void launchWebserver(URL jar) throws Exception {
URLClassLoader loader = new URLClassLoader(new URL[] {jar});
Class klass = Class.forName("winstone.Launcher", true, loader);
Thread.currentThread().setContextClassLoader(loader);
Properties props = getWebserverProperties();
String mainClass = props.getProperty("mainclass");
if (mainClass == null) {
throw new IllegalArgumentException("unknown webserver main class ("
+ WEBSERVER_PROPERTIES
+ " is missing 'mainclass' property)");
}
Class klass = Class.forName(mainClass, true, loader);
Method main = klass.getDeclaredMethod("main", new Class[] {String[].class});
String[] newargs = new String[args.length + 3];
newargs[0] = "--warfile=" + warfile;
newargs[1] = "--webroot=" + webroot;
newargs[2] = "--directoryListings=false";
System.arraycopy(args, 0, newargs, 3, args.length);
debug("invoking Winstone with: " + Arrays.deepToString(newargs));
String[] newargs = launchArguments(props);
debug("invoking webserver with: " + Arrays.deepToString(newargs));
main.invoke(null, new Object[] {newargs});
}
private String[] launchArguments(Properties props) {
String[] newargs = args;
if (props.getProperty("args") != null) {
String[] insertArgs = props.getProperty("args").split(",");
newargs = new String[args.length + insertArgs.length];
for (int i = 0; i < insertArgs.length; i++) {
newargs[i] = props.getProperty(insertArgs[i], "");
}
System.arraycopy(args, 0, newargs, insertArgs.length, args.length);
}
return newargs;
}
private void start() throws Exception {
URL u = extractWinstone();
launchWinstone(u);
URL u = extractWebserver();
launchWebserver(u);
}
private void debug(String msg) {
@@ -4,28 +4,51 @@
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.webapp.WebAppContext;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
public class JettyWarMain {
public static void main(String[] args) throws Exception {
String war = "test.war";
if (args.length > 0) {
war = args[0];
if (args.length == 0) {
throw new IllegalArgumentException("missing war file name");
}
Server server = new Server();
Connector connector = new SelectChannelConnector();
connector.setPort(Integer.getInteger("jetty.port",8080).intValue());
server.setConnectors(new Connector[]{connector});
// Ensure we have a "work" directory for the webapp
if (System.getProperty("jetty.home") != null) {
new File(System.getProperty("jetty.home"), "work").mkdirs();
}
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setExtractWAR(true);
webapp.setWar(war);
webapp.setDefaultsDescriptor("src/main/resources/webdefault.xml");
webapp.setWar(args[0]);
webapp.setDefaultsDescriptor(webdefaultPath());
Server server = new Server();
Connector connector = new SelectChannelConnector();
connector.setPort(Integer.getInteger("jetty.port",8080).intValue());
server.setConnectors(new Connector[]{connector});
server.setHandler(webapp);
server.start();
server.join();
}
private static String webdefaultPath() throws Exception {
String path = System.getProperty("jetty.home", System.getProperty("java.io.tmpdir")) + System.getProperty("file.separator") + "webdefault.xml";
FileOutputStream out = new FileOutputStream(path);
InputStream is = JettyWarMain.class.getResourceAsStream("/webdefault.xml");
try {
byte[] buf = new byte[4096];
int bytesRead = 0;
while ((bytesRead = is.read(buf)) != -1) {
out.write(buf, 0, bytesRead);
}
} finally {
is.close();
out.close();
}
return path;
}
}
@@ -146,6 +146,7 @@ class Config
# Embedded webserver to use. Currently supported webservers are:
# * <tt>winstone</tt> (default) - Winstone 0.9.10 from sourceforge
# * <tt>jenkins-ci.winstone</tt> - Improved Winstone from Jenkins CI
# * <tt>jetty</tt> - Embedded Jetty from Eclipse
attr_accessor :webserver
attr_reader :warbler_templates
@@ -35,14 +35,8 @@ def local_path
end
end
def initialize(artifacts)
@artifacts = artifacts
end
def add(jar)
artifacts.each do |a|
jar.files["WEB-INF/#{a.artifact_id}.jar"] = a.local_path
end
jar.files["WEB-INF/webserver.jar"] = @artifact.local_path
end
def main_class
@@ -52,25 +46,47 @@ def main_class
class WinstoneServer < WebServer
def initialize
super([Artifact.new(ENV["MAVEN_REPO"] || "http://repo2.maven.org/maven2",
"net.sourceforge.winstone", "winstone-lite",
ENV["WEBSERVER_VERSION"] || "0.9.10")])
@artifact = Artifact.new(ENV["MAVEN_REPO"] || "http://repo2.maven.org/maven2",
"net.sourceforge.winstone", "winstone-lite",
ENV["WEBSERVER_VERSION"] || "0.9.10")
end
def add(jar)
super
jar.files["WEB-INF/webserver.properties"] = StringIO.new(<<-PROPS)
mainclass = winstone.Launcher
args = args0,args1,args2
args0 = --warfile={{warfile}}
args1 = --webroot={{webroot}}
args2 = --directoryListings=false
PROPS
end
end
class JenkinsWinstoneServer < WebServer
class JenkinsWinstoneServer < WinstoneServer
def initialize
super([Artifact.new("http://maven.jenkins-ci.org/content/groups/artifacts",
"org.jenkins-ci", "winstone",
ENV["WEBSERVER_VERSION"] || "0.9.10-jenkins-35")])
@artifact = Artifact.new("http://maven.jenkins-ci.org/content/groups/artifacts",
"org.jenkins-ci", "winstone",
ENV["WEBSERVER_VERSION"] || "0.9.10-jenkins-35")
end
end
class JettyServer < WebServer
def initialize
super([Artifact.new(ENV["MAVEN_REPO"] || "http://repo2.maven.org/maven2",
"org.jruby.warbler", "warbler-embedded-jetty",
ENV["WEBSERVER_VERSION"] || "1.0.0")])
@artifact = Artifact.new(ENV["MAVEN_REPO"] || "http://repo2.maven.org/maven2",
"org.jruby.warbler", "warbler-embedded-jetty",
ENV["WEBSERVER_VERSION"] || "1.0.0")
end
def add(jar)
super
jar.files["WEB-INF/webserver.properties"] = StringIO.new(<<-PROPS)
mainclass = JettyWarMain
args = args0
props = jetty.home
args0 = {{warfile}}
jetty.home = {{webroot}}
PROPS
end
end
BIN +967 Bytes (110%) lib/warbler_jar.jar
Binary file not shown.

0 comments on commit 0558a28

Please sign in to comment.