buildr 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/java/jetty.rb CHANGED
@@ -1,123 +1,234 @@
1
- require 'net/http'
2
-
3
- # Monkeypatching: forcing FileUtils to ignore .svn files when
4
- # copying files around. We may want to implement our own deep
5
- # copy instead of hacking FileUtils in the future, but the cases
6
- # where you effectively want to copy .svn files are very, very
7
- # rare.
8
- module FileUtils
9
- class Entry_
10
- alias original_cp copy
11
- def copy(dest)
12
- unless path['.svn']
13
- original_cp(dest)
14
- end
15
- end
16
- end
17
- end
1
+ require "uri"
2
+ require "net/http"
3
+ require "core/project"
4
+ require "java/artifact"
18
5
 
19
6
  module Buildr
20
7
 
21
- module Jetty
8
+ # Provides a collection of tasks and methods for using Jetty, specifically as a server
9
+ # for testing your application.
10
+ #
11
+ # Build files should always start Jetty by invoking the #use task, typically as
12
+ # a prerequisite. This task will start Jetty once during the build, and shut it down
13
+ # when the build completes.
14
+ #
15
+ # If you want to keep Jetty running across builds, and look at error messages, you can
16
+ # start Jetty in a separate console with:
17
+ # rake jetty:start
18
+ # To stop this instance of Jetty, simply kill the process (Ctrl-C) or run:
19
+ # rake jetty:stop
20
+ #
21
+ # If you start Jetty separately from the build, the #use task will connect to that
22
+ # existing server. Since you are using Jetty across several builds, you will want to
23
+ # cleanup any mess created by each build. You can use the #setup and #teardown tasks,
24
+ # which are called when Jetty is first used in the build, and when the build ends.
25
+ class Jetty
26
+
27
+ class << self
22
28
 
23
- VERSION = "6.1.1"
29
+ # :call-seq:
30
+ # instance() => Jetty
31
+ #
32
+ # Returns an instance of Jetty.
33
+ def instance()
34
+ @instance ||= Jetty.new
35
+ end
24
36
 
25
- REQUIRES = [ "org.mortbay.jetty:jetty:jar:#{VERSION}",
26
- "org.mortbay.jetty:jetty-util:jar:#{VERSION}",
27
- "org.mortbay.jetty:servlet-api-2.5:jar:#{VERSION}",
28
- "log4j:log4j:jar:1.2.13",
29
- "commons-logging:commons-logging:jar:1.1"
30
- ]
37
+ end
31
38
 
32
- OPTIONS = [ :classpath, :war_path, :context_path, :noop, :base_url, :process_alias ]
39
+ # Artifacts required to run Jetty.
40
+ REQUIRES = [ "org.mortbay.jetty:jetty:jar:6.1.1", "org.mortbay.jetty:jetty-util:jar:6.1.1",
41
+ "org.mortbay.jetty:server-api-2.5:jar:6.1.1", "log4j:log4j:jar:1.2.13",
42
+ "commons-logging:commons-logging:jar:1.1" ]
33
43
 
34
- # Bouncing a webapp deployed in the Jetty web server. Just does a post
35
- # to a buildr specific handler. If there's nothing on the other side,
36
- # a new Jetty instance is spawned.
37
- def self.bounce(options)
38
- fu_check_options options, *OPTIONS
39
- options[:classpath] ||= []
40
-
41
- begin
42
- puts "Bouncing webapp #{options[:war_path]}" if verbose
43
- res = jetty_call('/bounce', :post, options)
44
- puts "done." if verbose
45
- rescue Errno::ECONNREFUSED => e
46
- puts "Web server not found, spawning it."
47
- runtool options.merge(:class=>"JettyWrapper",
48
- :args=>[ options[:war_path], options[:context_path] ],
49
- :classpath=>options[:classpath] + ['../buildr/lib/java/jetty'])
50
- end
44
+ # Default URL for Jetty.
45
+ URL = "http://localhost:8080"
51
46
 
52
- case res
53
- when Net::HTTPNotFound
54
- fail "A web server seems to be already running without Buildr deployment hooks."
55
- when Net::HTTPInternalServerError
56
- fail "Server error occured when redeploying the WAR, see the web server logs."
47
+ def initialize() #:nodoc:
48
+ @url = URL
49
+ namespace "jetty" do
50
+ @setup = task("setup")
51
+ @teardown = task("teardown")
52
+ @use = task("use") { fire }
57
53
  end
58
54
  end
59
55
 
60
- # Sends an http request to the buildr handler deployed in Jetty.
61
- def self.jetty_call(rel_url, get_post, options)
62
- base_url = URI.parse((options[:base_url] || 'http://localhost:8080/buildr') + rel_url)
63
- req = get_post == :post ? Net::HTTP::Post.new(base_url.path) : Net::HTTP::Get.new(base_url.path)
64
- res = Net::HTTP.start(base_url.host, base_url.port) {|http| http.request(req) }
56
+ # The URL for the Jetty server. Leave as is if you want to use the default server
57
+ # (http://localhost:8080).
58
+ attr_accessor :url
59
+
60
+ # :call-seq:
61
+ # start(pipe?)
62
+ #
63
+ # Starts Jetty. This method does not return, it keeps the thread running until
64
+ # Jetty is stopped. If you want to run Jetty parallel with other tasks in the build,
65
+ # invoke the #use task instead.
66
+ def start(pipe = nil)
67
+ begin
68
+ Java.rjb.classpath += REQUIRES
69
+ Java.rjb.classpath << File.join(__DIR__, "jetty")
70
+ Java.rjb do
71
+ port = URI.parse(url).port
72
+ puts "Starting Jetty at http://localhost:#{port}"
73
+ jetty = Rjb::import("JettyWrapper").new(port)
74
+ if pipe
75
+ pipe.puts "Started"
76
+ pipe.close
77
+ end
78
+ sleep # Forever
79
+ end
80
+ rescue Interrupt # Stopped from console
81
+ end
82
+ exit! # No at_exit
65
83
  end
66
84
 
67
- protected
85
+ # :call-seq:
86
+ # stop()
87
+ #
88
+ # Stops Jetty. Stops a server running in a separate process.
89
+ def stop()
90
+ uri = URI.parse(url)
91
+ begin
92
+ Net::HTTP.start(uri.host, uri.port) do |http|
93
+ http.request_post "/buildr/stop", ""
94
+ end
95
+ rescue Errno::ECONNREFUSED
96
+ # Expected if Jetty server not running.
97
+ rescue EOFError
98
+ # We get EOFError because Jetty is brutally killed.
99
+ end
100
+ puts "Jetty server stopped"
101
+ end
68
102
 
69
- def self.runtool(options)
70
- classpath = REQUIRES + (options[:classpath] || []).collect | (options[:cp] || []).collect
71
- classpath = artifacts(classpath).each { |t| t.invoke if t.respond_to?(:invoke) }.map(&:to_s)
72
- cmd_args = ["-cp", classpath.join(File::PATH_SEPARATOR)]
73
- cmd_args << options[:class]
74
- cmd_args += options[:args]
75
- unless options[:noop]
76
- if fork.nil?
77
- STDOUT.reopen File.new("stdout.log", "w")
78
- STDERR.reopen File.new("stderr.log", "w")
79
- exec ([Java.path_to_bin("java")] + cmd_args).join(' ')
103
+ # :call-seq:
104
+ # running?() => boolean
105
+ #
106
+ # Returns true if it finds a running Jetty server that supports the Buildr
107
+ # requests for deploying, stopping, etc.
108
+ def running?()
109
+ uri = URI.parse(url)
110
+ begin
111
+ Net::HTTP.start(uri.host, uri.port) do |http|
112
+ response = http.request_get("/buildr/")
113
+ response.is_a?(Net::HTTPSuccess) && response.body =~ /Alive/
80
114
  end
115
+ rescue Errno::ECONNREFUSED
116
+ false
81
117
  end
82
118
  end
83
-
84
- class JettyTask < Rake::Task
85
- def initialize(*args)
86
- super
87
- enhance do |task|
88
- Jetty.bounce task.options
119
+
120
+ # :call-seq:
121
+ # deploy(url, webapp) => path
122
+ #
123
+ # Deploy a WAR in the specified URL.
124
+ def deploy(url, webapp)
125
+ use.invoke
126
+ uri = URI.parse(url)
127
+ Net::HTTP.start(uri.host, uri.port) do |http|
128
+ response = http.request_post("/buildr/deploy", "webapp=#{webapp}&path=#{uri.path}")
129
+ if Net::HTTPOK === response && response.body =~ /Deployed/
130
+ path = response.body.split[1]
131
+ puts "Deployed #{webapp}, context path #{uri.path}" if Rake.application.options.trace
132
+ path
133
+ else
134
+ fail "Deployment failed: #{response}"
89
135
  end
90
136
  end
137
+ end
91
138
 
92
- def options()
93
- @options ||= {}
139
+ # :call-seq:
140
+ # undeploy(url) => boolean
141
+ #
142
+ # Undeploys a WAR from the specified URL.
143
+ def undeploy(url)
144
+ use.invoke
145
+ uri = URI.parse(url)
146
+ Net::HTTP.start(uri.host, uri.port) do |http|
147
+ response = http.request_post("/buildr/undeploy", "path=#{uri.path}")
148
+ if Net::HTTPOK === response && response.body =~ /Undeployed/
149
+ true
150
+ else
151
+ fail "Deployment failed: #{response}"
152
+ end
94
153
  end
154
+ end
155
+
156
+ # :call-seq:
157
+ # setup(*prereqs) => task
158
+ # setup(*prereqs) { |task| .. } => task
159
+ #
160
+ # This task executes when Jetty is first used in the build. You can use it to
161
+ # deploy artifacts into Jetty.
162
+ def setup(*prereqs, &block)
163
+ @setup.enhance prereqs, &block
164
+ end
165
+
166
+ # :call-seq:
167
+ # teardown(*prereqs) => task
168
+ # teardown(*prereqs) { |task| .. } => task
169
+ #
170
+ # This task executes when the build is done. You can use it to undeploy artifacts
171
+ # previously deployed into Jetty.
172
+ def teardown(*prereqs, &block)
173
+ @teardown.enhance prereqs, &block
174
+ end
175
+
176
+ # :call-seq:
177
+ # use(*prereqs) => task
178
+ # use(*prereqs) { |task| .. } => task
179
+ #
180
+ # If you intend to use Jetty, invoke this task. It will start a new instance of
181
+ # Jetty and close it when the build is done. However, if you already have a server
182
+ # running in the background (e.g. jetty:start), it will use that server and will
183
+ # not close it down.
184
+ def use(*prereqs, &block)
185
+ @use.enhance prereqs, &block
186
+ end
187
+
188
+ protected
95
189
 
96
- def using(options)
97
- self.options.merge!(options)
98
- self
190
+ # If you want to start Jetty inside the build, call this method instead of #start.
191
+ # It will spawn a separate process that will run Jetty, and will stop Jetty when
192
+ # the build ends. However, if you already started Jetty from the console (with
193
+ # take jetty:start), it will use the existing instance without shutting it down.
194
+ def fire()
195
+ unless running?
196
+ reader, writer = IO.pipe
197
+ if pid = fork
198
+ # Wait for Jetty to fire up before doing anything else.
199
+ if reader.gets == "Started"
200
+ puts "Jetty started"
201
+ reader.close
202
+ end
203
+ at_exit { stop }
204
+ else
205
+ start writer
206
+ end
99
207
  end
208
+ @setup.invoke
209
+ at_exit { @teardown.invoke }
100
210
  end
211
+
212
+ end
213
+
214
+ namespace "jetty" do
215
+ desc "Start an instance of Jetty running in the background"
216
+ task("start") { Jetty.instance.start }
217
+ desc "Stop an instance of Jetty running in the background"
218
+ task("stop") { Jetty.instance.stop }
101
219
  end
102
220
 
103
221
  class Project
104
- def webserve(&block)
105
- task "jetty:shutdown" do
106
- begin
107
- res = Jetty.jetty_call('/stop', :put, @webserve_task.options)
108
- puts "Response #{res}" if verbose
109
- rescue Errno::ECONNREFUSED
110
- puts "Jetty server couldn't be contacted, nothing done."
111
- rescue EOFError
112
- puts "Shutdown successful."
113
- rescue Exception => e
114
- puts "Unexpected error: #{e.class}"
115
- end
116
- end
117
- returning(@webserve_task ||= Jetty::JettyTask.define_task("jetty:bounce"=>package(:war))) do |task|
118
- task.enhance &block if block
119
- end
222
+
223
+ # :call-seq:
224
+ # jetty() => Jetty
225
+ #
226
+ # Returns a Jetty object. You can use this to discover the Jetty#use task,
227
+ # configure the Jetty#setup and Jetty#teardown tasks, deploy and undeploy to Jetty.
228
+ def jetty()
229
+ @jetty ||= Jetty.instance
120
230
  end
231
+
121
232
  end
122
233
 
123
234
  end
Binary file
@@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletRequest;
10
10
  import javax.servlet.http.HttpServletResponse;
11
11
  import javax.servlet.ServletException;
12
12
  import java.io.IOException;
13
+ import java.util.HashMap;
13
14
 
14
15
  /**
15
16
  * @author Matthieu Riou <mriou at apache dot org>
@@ -22,16 +23,16 @@ public class JettyWrapper {
22
23
  private String _webAppDir;
23
24
  private String _contextPath;
24
25
 
25
- public JettyWrapper(String webAppDir, String contextPath) {
26
- _server = new Server(8080);
27
- _webAppDir = webAppDir;
28
- _contextPath = contextPath;
26
+ public JettyWrapper(int port/*String webAppDir, String contextPath*/) throws Exception {
27
+ _server = new Server(port);
28
+ //_webAppDir = webAppDir;
29
+ //_contextPath = contextPath;
29
30
 
30
31
  // Adding handler for the war to deploy
31
- _webAppHandler = new WebAppContext(_webAppDir, _contextPath);
32
- _webAppHandler.setConfigurationClasses(new String[] {
33
- "org.mortbay.jetty.webapp.WebInfConfiguration",
34
- "org.mortbay.jetty.webapp.WebXmlConfiguration"});
32
+ //_webAppHandler = new WebAppContext(_webAppDir, _contextPath);
33
+ //_webAppHandler.setConfigurationClasses(new String[] {
34
+ // "org.mortbay.jetty.webapp.WebInfConfiguration",
35
+ // "org.mortbay.jetty.webapp.WebXmlConfiguration"});
35
36
 
36
37
  // Adding the buildr handler to control our server lifecycle
37
38
  ContextHandler context = new ContextHandler();
@@ -40,20 +41,21 @@ public class JettyWrapper {
40
41
  context.setHandler(handler);
41
42
 
42
43
  _handlerColl = new ContextHandlerCollection();
43
- _handlerColl.setHandlers(new Handler[] {_webAppHandler, context});
44
+ _handlerColl.setHandlers(new Handler[] {/*_webAppHandler,*/ context});
44
45
 
45
46
  _server.addHandler(_handlerColl);
47
+ _server.start();
46
48
  }
47
49
 
48
50
  public void start() {
49
51
  try {
50
- _server.start();
52
+ //_server.start();
51
53
  _server.join();
52
54
  } catch (Exception e) {
53
55
  e.printStackTrace();
54
56
  }
55
57
  }
56
-
58
+ /*
57
59
  public static void main(String[] args) {
58
60
  if (args.length != 2) {
59
61
  System.out.println("Please provide the webapp directory and the context path.");
@@ -63,22 +65,69 @@ public class JettyWrapper {
63
65
  JettyWrapper jetwrap = new JettyWrapper(webAppDir, contextPath);
64
66
  jetwrap.start();
65
67
  }
68
+ */
66
69
 
67
70
  private class BuildrHandler extends AbstractHandler {
68
71
 
72
+ private HashMap _apps = new HashMap();
73
+
69
74
  public void handle(String string, HttpServletRequest request,
70
75
  HttpServletResponse response, int i) throws IOException, ServletException {
71
76
  response.setContentType("text/html");
72
- if (request.getPathInfo().equals("/bounce")) {
77
+ if (request.getPathInfo().equals("/")) {
78
+ response.getWriter().println("Alive");
79
+ ((Request)request).setHandled(true);
80
+ return;
81
+ } else if (request.getPathInfo().equals("/deploy")) {
82
+ try {
83
+ String webapp = request.getParameter("webapp");
84
+ String path = request.getParameter("path");
85
+ System.out.println("Deploying " + webapp + " in " + path);
86
+ WebAppContext context;
87
+
88
+ context = (WebAppContext) _apps.get(path);
89
+ if (context != null) {
90
+ context.stop();
91
+ _handlerColl.removeHandler(context);
92
+ _apps.remove(path);
93
+ }
94
+
95
+ context = new WebAppContext(webapp, path);
96
+ context.setConfigurationClasses(new String[] {
97
+ "org.mortbay.jetty.webapp.WebInfConfiguration",
98
+ "org.mortbay.jetty.webapp.WebXmlConfiguration"});
99
+ _handlerColl.addHandler(context);
100
+ context.start();
101
+ _apps.put(path, context);
102
+ //_webAppHandler.stop();
103
+ //_handlerColl.removeHandler(_webAppHandler);
104
+ //_webAppHandler = new WebAppContext(_webAppDir, _contextPath);
105
+ //_webAppHandler.setConfigurationClasses(new String[] {
106
+ // "org.mortbay.jetty.webapp.WebInfConfiguration",
107
+ // "org.mortbay.jetty.webapp.WebXmlConfiguration"});
108
+ //_handlerColl.addHandler(_webAppHandler);
109
+ //_webAppHandler.start();
110
+ response.getWriter().println("Deployed");
111
+ response.getWriter().println(context.getTempDirectory());
112
+ ((Request)request).setHandled(true);
113
+ } catch (Throwable e) {
114
+ e.printStackTrace();
115
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
116
+ ((Request)request).setHandled(true);
117
+ return;
118
+ }
119
+ } else if (request.getPathInfo().equals("/undeploy")) {
73
120
  try {
74
- _webAppHandler.stop();
75
- _handlerColl.removeHandler(_webAppHandler);
76
- _webAppHandler = new WebAppContext(_webAppDir, _contextPath);
77
- _webAppHandler.setConfigurationClasses(new String[] {
78
- "org.mortbay.jetty.webapp.WebInfConfiguration",
79
- "org.mortbay.jetty.webapp.WebXmlConfiguration"});
80
- _handlerColl.addHandler(_webAppHandler);
81
- _webAppHandler.start();
121
+ String path = request.getParameter("path");
122
+ WebAppContext context = (WebAppContext) _apps.get(path);
123
+ if (context != null) {
124
+ System.out.println("Undeploying app at " + path);
125
+ context.stop();
126
+ _handlerColl.removeHandler(context);
127
+ _apps.remove(path);
128
+ }
129
+ response.getWriter().println("Undeployed");
130
+ ((Request)request).setHandled(true);
82
131
  } catch (Throwable e) {
83
132
  e.printStackTrace();
84
133
  response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);