buildr 0.18.0 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
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);