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...
1 parent 128b214 commit 0558a285eb59a0801cf7c0f274777b06b63883b3 @nicksieger nicksieger committed Mar 13, 2012
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
View
@@ -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|
View
@@ -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;
+ }
}
View
@@ -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
View
@@ -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
View
Binary file not shown.

0 comments on commit 0558a28

Please sign in to comment.