| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with this |
| # work for additional information regarding copyright ownership. The ASF |
| # licenses this file to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| |
| require 'uri' |
| require 'net/http' |
| require 'thread' |
| |
| module Buildr |
| |
| # Provides a collection of tasks and methods for using Jetty, specifically as a server |
| # for testing your application. |
| # |
| # Build files should always start Jetty by invoking the #use task, typically as |
| # a prerequisite. This task will start Jetty once during the build, and shut it down |
| # when the build completes. |
| # |
| # If you want to keep Jetty running across builds, and look at error messages, you can |
| # start Jetty in a separate console with: |
| # buildr jetty:start |
| # To stop this instance of Jetty, simply kill the process (Ctrl-C) or run: |
| # buildr jetty:stop |
| # |
| # If you start Jetty separately from the build, the #use task will connect to that |
| # existing server. Since you are using Jetty across several builds, you will want to |
| # cleanup any mess created by each build. You can use the #setup and #teardown tasks, |
| # which are called when Jetty is first used in the build, and when the build ends. |
| class Jetty |
| |
| # Which version of Jetty we're using by default (change with options.jetty.version). |
| VERSION = '9.4.6.v20170531' |
| SLF4J_VERSION = '1.7.25' |
| |
| # Libraries used by Jetty. |
| REQUIRES = [ "org.eclipse.jetty:jetty-server:jar:#{VERSION}", |
| "org.eclipse.jetty:jetty-webapp:jar:#{VERSION}", |
| "org.eclipse.jetty:jetty-http:jar:#{VERSION}", |
| "org.eclipse.jetty:jetty-util:jar:#{VERSION}", |
| "org.eclipse.jetty:jetty-io:jar:#{VERSION}", |
| "org.eclipse.jetty:jetty-servlet:jar:#{VERSION}", |
| "org.eclipse.jetty:jetty-security:jar:#{VERSION}", |
| "org.eclipse.jetty:jetty-xml:jar:#{VERSION}", |
| "org.slf4j:slf4j-api:jar:#{SLF4J_VERSION}", |
| "org.slf4j:slf4j-simple:jar:#{SLF4J_VERSION}", |
| "org.slf4j:jcl-over-slf4j:jar:#{SLF4J_VERSION}", |
| 'javax.servlet:javax.servlet-api:jar:3.1.0' ] |
| |
| Java.classpath << REQUIRES |
| Java.classpath << File.dirname(__FILE__) |
| |
| # Default URL for Jetty (change with options.jetty.url). |
| URL = "http://localhost:8080" |
| |
| class << self |
| |
| # :call-seq: |
| # instance() => Jetty |
| # |
| # Returns an instance of Jetty. |
| def instance() |
| @instance ||= Jetty.new("jetty", URL) |
| end |
| |
| end |
| |
| def initialize(name, url) #:nodoc: |
| @url = url |
| namespace name do |
| @setup = task("setup") |
| @teardown = task("teardown") |
| @use = task("use") { fire } |
| end |
| end |
| |
| # The URL for the Jetty server. Leave as is if you want to use the default server |
| # (http://localhost:8080). |
| attr_accessor :url |
| |
| # :call-seq: |
| # start(pipe?) |
| # |
| # Starts Jetty. This method does not return, it keeps the thread running until |
| # Jetty is stopped. If you want to run Jetty parallel with other tasks in the build, |
| # invoke the #use task instead. |
| def start(sync = nil) |
| begin |
| puts "classpath #{Java.classpath.inspect}" |
| port = URI.parse(url).port |
| puts "Starting Jetty at http://localhost:#{port}" if verbose |
| Java.load |
| jetty = Java.org.apache.buildr.JettyWrapper.new(port) |
| sync << "Started" if sync |
| sleep # Forever |
| rescue Interrupt # Stopped from console |
| rescue Exception=>error |
| puts "#{error.class}: #{error.message}" |
| end |
| exit! # No at_exit |
| end |
| |
| # :call-seq: |
| # stop() |
| # |
| # Stops Jetty. Stops a server running in a separate process. |
| def stop() |
| uri = URI.parse(url) |
| begin |
| Net::HTTP.start(uri.host, uri.port) do |http| |
| http.request_post "/buildr/stop", "" |
| end |
| rescue Errno::ECONNREFUSED |
| # Expected if Jetty server not running. |
| rescue EOFError |
| # We get EOFError because Jetty is brutally killed. |
| end |
| puts "Jetty server stopped" |
| end |
| |
| # :call-seq: |
| # running?() => boolean |
| # |
| # Returns true if it finds a running Jetty server that supports the Buildr |
| # requests for deploying, stopping, etc. |
| def running?() |
| uri = URI.parse(url) |
| begin |
| Net::HTTP.start(uri.host, uri.port) do |http| |
| response = http.request_get("/buildr/") |
| response.is_a?(Net::HTTPSuccess) && response.body =~ /Alive/ |
| end |
| rescue Errno::ECONNREFUSED, Errno::EBADF |
| false |
| end |
| end |
| |
| # :call-seq: |
| # deploy(url, webapp) => path |
| # |
| # Deploy a WAR in the specified URL. |
| def deploy(url, webapp) |
| use.invoke |
| uri = URI.parse(url) |
| Net::HTTP.start(uri.host, uri.port) do |http| |
| response = http.request_post("/buildr/deploy", "webapp=#{webapp}&path=#{uri.path}") |
| if Net::HTTPOK === response && response.body =~ /Deployed/ |
| path = response.body.split[1] |
| puts "Deployed #{webapp}, context path #{uri.path}" if trace? |
| path |
| else |
| fail "Deployment failed: #{response}" |
| end |
| end |
| end |
| |
| # :call-seq: |
| # undeploy(url) => boolean |
| # |
| # Undeploys a WAR from the specified URL. |
| def undeploy(url) |
| use.invoke |
| uri = URI.parse(url) |
| Net::HTTP.start(uri.host, uri.port) do |http| |
| response = http.request_post("/buildr/undeploy", "path=#{uri.path}") |
| if Net::HTTPOK === response && response.body =~ /Undeployed/ |
| true |
| else |
| fail "Deployment failed: #{response}" |
| end |
| end |
| end |
| |
| # :call-seq: |
| # setup(*prereqs) => task |
| # setup(*prereqs) { |task| .. } => task |
| # |
| # This task executes when Jetty is first used in the build. You can use it to |
| # deploy artifacts into Jetty. |
| def setup(*prereqs, &block) |
| @setup.enhance prereqs, &block |
| end |
| |
| # :call-seq: |
| # teardown(*prereqs) => task |
| # teardown(*prereqs) { |task| .. } => task |
| # |
| # This task executes when the build is done. You can use it to undeploy artifacts |
| # previously deployed into Jetty. |
| def teardown(*prereqs, &block) |
| @teardown.enhance prereqs, &block |
| end |
| |
| # :call-seq: |
| # use(*prereqs) => task |
| # use(*prereqs) { |task| .. } => task |
| # |
| # If you intend to use Jetty, invoke this task. It will start a new instance of |
| # Jetty and close it when the build is done. However, if you already have a server |
| # running in the background (e.g. jetty:start), it will use that server and will |
| # not close it down. |
| def use(*prereqs, &block) |
| @use.enhance prereqs, &block |
| end |
| |
| protected |
| |
| # If you want to start Jetty inside the build, call this method instead of #start. |
| # It will spawn a separate process that will run Jetty, and will stop Jetty when |
| # the build ends. However, if you already started Jetty from the console (with |
| # take jetty:start), it will use the existing instance without shutting it down. |
| def fire() |
| unless running? |
| sync = Queue.new |
| Thread.new { start sync } |
| # Wait for Jetty to fire up before doing anything else. |
| sync.pop == "Started" or fail "Jetty not started" |
| puts "Jetty started" if verbose |
| at_exit { stop } |
| end |
| @setup.invoke |
| at_exit { @teardown.invoke } |
| end |
| |
| end |
| |
| namespace "jetty" do |
| desc "Start an instance of Jetty running in the background" |
| task("start") { Jetty.instance.start } |
| desc "Stop an instance of Jetty running in the background" |
| task("stop") { Jetty.instance.stop } |
| end |
| |
| # :call-seq: |
| # jetty() => Jetty |
| # |
| # Returns a Jetty object. You can use this to discover the Jetty#use task, |
| # configure the Jetty#setup and Jetty#teardown tasks, deploy and undeploy to Jetty. |
| def jetty() |
| @jetty ||= Jetty.instance |
| end |
| |
| end |