Skip to content
This repository
Browse code

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...
commit 0558a285eb59a0801cf7c0f274777b06b63883b3 1 parent 128b214
Nick Sieger nicksieger authored
13 Rakefile
@@ -33,9 +33,9 @@ begin
33 33 directory "pkg/classes"
34 34 CLEAN << "pkg"
35 35
36   - file jar_file => FileList['ext/**/*.java', 'pkg/classes'] do
  36 + file jar_file => FileList['ext/*.java', 'pkg/classes'] do
37 37 rm_rf FileList['pkg/classes/**/*']
38   - ant.javac :srcdir => "ext", :destdir => "pkg/classes",
  38 + ant.javac :srcdir => "ext", :includes => "*.java", :destdir => "pkg/classes",
39 39 :source => "1.5", :target => "1.5", :debug => true,
40 40 :classpath => "${java.class.path}:${sun.boot.class.path}",
41 41 :includeantRuntime => false
@@ -52,14 +52,7 @@ rescue LoadError
52 52 end
53 53
54 54 # Make sure jar gets compiled before the gem is built
55   -task Rake::Task['build'].prerequisites.first => :jar
56   -
57   -task :warbler_jar => 'pkg' do
58   - ruby "-rubygems", "-Ilib", "-S", "bin/warble"
59   - mv "warbler.jar", "pkg/warbler-#{Warbler::VERSION}.jar"
60   -end
61   -
62   -task :build => :warbler_jar
  55 +task :build => :jar
63 56
64 57 require 'rdoc/task'
65 58 RDoc::Task.new(:docs) do |rd|
79 ext/WarMain.java
@@ -13,10 +13,13 @@
13 13 import java.io.File;
14 14 import java.io.FileOutputStream;
15 15 import java.util.Arrays;
  16 +import java.util.Properties;
  17 +import java.util.Map;
16 18
17 19 public class WarMain implements Runnable {
18 20 public static final String MAIN = "/" + WarMain.class.getName().replace('.', '/') + ".class";
19   - public static final String WINSTONE_JAR = "/WEB-INF/webserver.jar";
  21 + public static final String WEBSERVER_PROPERTIES = "/WEB-INF/webserver.properties";
  22 + public static final String WEBSERVER_JAR = "/WEB-INF/webserver.jar";
20 23
21 24 private String[] args;
22 25 private String path, warfile;
@@ -29,16 +32,17 @@ public WarMain(String[] args) throws Exception {
29 32 this.path = mainClass.toURI().getSchemeSpecificPart();
30 33 this.warfile = this.path.replace("!" + MAIN, "").replace("file:", "");
31 34 this.debug = isDebug();
32   - this.webroot = File.createTempFile("winstone", "webroot");
  35 + this.webroot = File.createTempFile("warbler", "webroot");
33 36 this.webroot.delete();
34 37 this.webroot.mkdirs();
35 38 this.webroot = new File(this.webroot, new File(warfile).getName());
  39 + debug("webroot directory is " + this.webroot.getPath());
36 40 Runtime.getRuntime().addShutdownHook(new Thread(this));
37 41 }
38 42
39   - private URL extractWinstone() throws Exception {
40   - InputStream jarStream = new URL("jar:" + path.replace(MAIN, WINSTONE_JAR)).openStream();
41   - File jarFile = File.createTempFile("winstone", ".jar");
  43 + private URL extractWebserver() throws Exception {
  44 + InputStream jarStream = new URL("jar:" + path.replace(MAIN, WEBSERVER_JAR)).openStream();
  45 + File jarFile = File.createTempFile("webserver", ".jar");
42 46 jarFile.deleteOnExit();
43 47 FileOutputStream outStream = new FileOutputStream(jarFile);
44 48 try {
@@ -51,26 +55,69 @@ private URL extractWinstone() throws Exception {
51 55 jarStream.close();
52 56 outStream.close();
53 57 }
54   - debug("winstone.jar extracted to " + jarFile.getPath());
  58 + debug("webserver.jar extracted to " + jarFile.getPath());
55 59 return jarFile.toURI().toURL();
56 60 }
57 61
58   - private void launchWinstone(URL jar) throws Exception {
  62 + private Properties getWebserverProperties() throws Exception {
  63 + Properties props = new Properties();
  64 + try {
  65 + InputStream is = getClass().getResourceAsStream(WEBSERVER_PROPERTIES);
  66 + props.load(is);
  67 + } catch (Exception e) {
  68 + }
  69 +
  70 + for (Map.Entry entry : props.entrySet()) {
  71 + String val = (String) entry.getValue();
  72 + val = val.replace("{{warfile}}", warfile).replace("{{webroot}}", webroot.getAbsolutePath());
  73 + entry.setValue(val);
  74 + }
  75 +
  76 + if (props.getProperty("props") != null) {
  77 + String[] propsToSet = props.getProperty("props").split(",");
  78 + for (String key : propsToSet) {
  79 + System.setProperty(key, props.getProperty(key));
  80 + }
  81 + }
  82 +
  83 + return props;
  84 + }
  85 +
  86 + private void launchWebserver(URL jar) throws Exception {
59 87 URLClassLoader loader = new URLClassLoader(new URL[] {jar});
60   - Class klass = Class.forName("winstone.Launcher", true, loader);
  88 + Thread.currentThread().setContextClassLoader(loader);
  89 + Properties props = getWebserverProperties();
  90 + String mainClass = props.getProperty("mainclass");
  91 + if (mainClass == null) {
  92 + throw new IllegalArgumentException("unknown webserver main class ("
  93 + + WEBSERVER_PROPERTIES
  94 + + " is missing 'mainclass' property)");
  95 + }
  96 + Class klass = Class.forName(mainClass, true, loader);
61 97 Method main = klass.getDeclaredMethod("main", new Class[] {String[].class});
62   - String[] newargs = new String[args.length + 3];
63   - newargs[0] = "--warfile=" + warfile;
64   - newargs[1] = "--webroot=" + webroot;
65   - newargs[2] = "--directoryListings=false";
66   - System.arraycopy(args, 0, newargs, 3, args.length);
67   - debug("invoking Winstone with: " + Arrays.deepToString(newargs));
  98 + String[] newargs = launchArguments(props);
  99 + debug("invoking webserver with: " + Arrays.deepToString(newargs));
68 100 main.invoke(null, new Object[] {newargs});
69 101 }
70 102
  103 + private String[] launchArguments(Properties props) {
  104 + String[] newargs = args;
  105 +
  106 + if (props.getProperty("args") != null) {
  107 + String[] insertArgs = props.getProperty("args").split(",");
  108 + newargs = new String[args.length + insertArgs.length];
  109 + for (int i = 0; i < insertArgs.length; i++) {
  110 + newargs[i] = props.getProperty(insertArgs[i], "");
  111 + }
  112 + System.arraycopy(args, 0, newargs, insertArgs.length, args.length);
  113 + }
  114 +
  115 + return newargs;
  116 + }
  117 +
71 118 private void start() throws Exception {
72   - URL u = extractWinstone();
73   - launchWinstone(u);
  119 + URL u = extractWebserver();
  120 + launchWebserver(u);
74 121 }
75 122
76 123 private void debug(String msg) {
45 ext/jetty/src/main/java/JettyWarMain.java
@@ -4,28 +4,51 @@
4 4 import org.eclipse.jetty.server.nio.SelectChannelConnector;
5 5 import org.eclipse.jetty.webapp.WebAppContext;
6 6
  7 +import java.io.File;
  8 +import java.io.FileOutputStream;
  9 +import java.io.InputStream;
  10 +
7 11 public class JettyWarMain {
  12 +
8 13 public static void main(String[] args) throws Exception {
9   - String war = "test.war";
10   - if (args.length > 0) {
11   - war = args[0];
  14 + if (args.length == 0) {
  15 + throw new IllegalArgumentException("missing war file name");
12 16 }
13 17
14   - Server server = new Server();
15   -
16   - Connector connector = new SelectChannelConnector();
17   - connector.setPort(Integer.getInteger("jetty.port",8080).intValue());
18   - server.setConnectors(new Connector[]{connector});
  18 + // Ensure we have a "work" directory for the webapp
  19 + if (System.getProperty("jetty.home") != null) {
  20 + new File(System.getProperty("jetty.home"), "work").mkdirs();
  21 + }
19 22
20 23 WebAppContext webapp = new WebAppContext();
21 24 webapp.setContextPath("/");
22 25 webapp.setExtractWAR(true);
23   - webapp.setWar(war);
24   - webapp.setDefaultsDescriptor("src/main/resources/webdefault.xml");
  26 + webapp.setWar(args[0]);
  27 + webapp.setDefaultsDescriptor(webdefaultPath());
25 28
  29 + Server server = new Server();
  30 + Connector connector = new SelectChannelConnector();
  31 + connector.setPort(Integer.getInteger("jetty.port",8080).intValue());
  32 + server.setConnectors(new Connector[]{connector});
26 33 server.setHandler(webapp);
27   -
28 34 server.start();
29 35 server.join();
30 36 }
  37 +
  38 + private static String webdefaultPath() throws Exception {
  39 + String path = System.getProperty("jetty.home", System.getProperty("java.io.tmpdir")) + System.getProperty("file.separator") + "webdefault.xml";
  40 + FileOutputStream out = new FileOutputStream(path);
  41 + InputStream is = JettyWarMain.class.getResourceAsStream("/webdefault.xml");
  42 + try {
  43 + byte[] buf = new byte[4096];
  44 + int bytesRead = 0;
  45 + while ((bytesRead = is.read(buf)) != -1) {
  46 + out.write(buf, 0, bytesRead);
  47 + }
  48 + } finally {
  49 + is.close();
  50 + out.close();
  51 + }
  52 + return path;
  53 + }
31 54 }
1  lib/warbler/config.rb
@@ -146,6 +146,7 @@ class Config
146 146 # Embedded webserver to use. Currently supported webservers are:
147 147 # * <tt>winstone</tt> (default) - Winstone 0.9.10 from sourceforge
148 148 # * <tt>jenkins-ci.winstone</tt> - Improved Winstone from Jenkins CI
  149 + # * <tt>jetty</tt> - Embedded Jetty from Eclipse
149 150 attr_accessor :webserver
150 151
151 152 attr_reader :warbler_templates
50 lib/warbler/web_server.rb
@@ -35,14 +35,8 @@ def local_path
35 35 end
36 36 end
37 37
38   - def initialize(artifacts)
39   - @artifacts = artifacts
40   - end
41   -
42 38 def add(jar)
43   - artifacts.each do |a|
44   - jar.files["WEB-INF/#{a.artifact_id}.jar"] = a.local_path
45   - end
  39 + jar.files["WEB-INF/webserver.jar"] = @artifact.local_path
46 40 end
47 41
48 42 def main_class
@@ -52,25 +46,47 @@ def main_class
52 46
53 47 class WinstoneServer < WebServer
54 48 def initialize
55   - super([Artifact.new(ENV["MAVEN_REPO"] || "http://repo2.maven.org/maven2",
56   - "net.sourceforge.winstone", "winstone-lite",
57   - ENV["WEBSERVER_VERSION"] || "0.9.10")])
  49 + @artifact = Artifact.new(ENV["MAVEN_REPO"] || "http://repo2.maven.org/maven2",
  50 + "net.sourceforge.winstone", "winstone-lite",
  51 + ENV["WEBSERVER_VERSION"] || "0.9.10")
  52 + end
  53 +
  54 + def add(jar)
  55 + super
  56 + jar.files["WEB-INF/webserver.properties"] = StringIO.new(<<-PROPS)
  57 +mainclass = winstone.Launcher
  58 +args = args0,args1,args2
  59 +args0 = --warfile={{warfile}}
  60 +args1 = --webroot={{webroot}}
  61 +args2 = --directoryListings=false
  62 +PROPS
58 63 end
59 64 end
60 65
61   - class JenkinsWinstoneServer < WebServer
  66 + class JenkinsWinstoneServer < WinstoneServer
62 67 def initialize
63   - super([Artifact.new("http://maven.jenkins-ci.org/content/groups/artifacts",
64   - "org.jenkins-ci", "winstone",
65   - ENV["WEBSERVER_VERSION"] || "0.9.10-jenkins-35")])
  68 + @artifact = Artifact.new("http://maven.jenkins-ci.org/content/groups/artifacts",
  69 + "org.jenkins-ci", "winstone",
  70 + ENV["WEBSERVER_VERSION"] || "0.9.10-jenkins-35")
66 71 end
67 72 end
68 73
69 74 class JettyServer < WebServer
70 75 def initialize
71   - super([Artifact.new(ENV["MAVEN_REPO"] || "http://repo2.maven.org/maven2",
72   - "org.jruby.warbler", "warbler-embedded-jetty",
73   - ENV["WEBSERVER_VERSION"] || "1.0.0")])
  76 + @artifact = Artifact.new(ENV["MAVEN_REPO"] || "http://repo2.maven.org/maven2",
  77 + "org.jruby.warbler", "warbler-embedded-jetty",
  78 + ENV["WEBSERVER_VERSION"] || "1.0.0")
  79 + end
  80 +
  81 + def add(jar)
  82 + super
  83 + jar.files["WEB-INF/webserver.properties"] = StringIO.new(<<-PROPS)
  84 +mainclass = JettyWarMain
  85 +args = args0
  86 +props = jetty.home
  87 +args0 = {{warfile}}
  88 +jetty.home = {{webroot}}
  89 +PROPS
74 90 end
75 91 end
76 92
BIN  lib/warbler_jar.jar
Binary file not shown

0 comments on commit 0558a28

Please sign in to comment.
Something went wrong with that request. Please try again.