jubilee 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.rbenv-version +1 -0
  2. data/Gemfile +16 -0
  3. data/Gemfile.lock +54 -0
  4. data/Guardfile +24 -0
  5. data/README.md +61 -0
  6. data/Rakefile +94 -0
  7. data/VERSION +1 -0
  8. data/bin/jubilee +6 -0
  9. data/bin/jubilee_d +10 -0
  10. data/examples/jubilee/keystore.jks +0 -0
  11. data/examples/jubilee/server-keystore.jks +0 -0
  12. data/examples/ssl/ServerTest.java +19 -0
  13. data/examples/ssl/webroot/index.html +10 -0
  14. data/jars/netty-3.6.0.Beta1.jar +0 -0
  15. data/jars/vertx-core-1.3.0.final.jar +0 -0
  16. data/java/.idea/ant.xml +7 -0
  17. data/java/.idea/libraries/jruby.xml +9 -0
  18. data/java/.idea/libraries/netty_3_6_0_Beta1.xml +9 -0
  19. data/java/.idea/libraries/vertx_core_1_3_0_final.xml +9 -0
  20. data/java/src/jubilee/JubileeService.java +21 -0
  21. data/java/src/org/jruby/jubilee/Const.java +148 -0
  22. data/java/src/org/jruby/jubilee/RackApplication.java +78 -0
  23. data/java/src/org/jruby/jubilee/RackEnvironment.java +13 -0
  24. data/java/src/org/jruby/jubilee/RackErrors.java +44 -0
  25. data/java/src/org/jruby/jubilee/RackInput.java +62 -0
  26. data/java/src/org/jruby/jubilee/RackResponse.java +16 -0
  27. data/java/src/org/jruby/jubilee/Server.java +104 -0
  28. data/java/src/org/jruby/jubilee/deploy/Starter.java +26 -0
  29. data/java/src/org/jruby/jubilee/impl/DefaultRackEnvironment.java +98 -0
  30. data/java/src/org/jruby/jubilee/impl/NullIO.java +111 -0
  31. data/java/src/org/jruby/jubilee/impl/RubyIORackErrors.java +68 -0
  32. data/java/src/org/jruby/jubilee/impl/RubyIORackInput.java +164 -0
  33. data/lib/jubilee.rb +11 -0
  34. data/lib/jubilee/application.rb +13 -0
  35. data/lib/jubilee/cli.rb +74 -0
  36. data/lib/jubilee/configuration.rb +52 -0
  37. data/lib/jubilee/const.rb +39 -0
  38. data/lib/jubilee/jubilee.jar +0 -0
  39. data/lib/jubilee/response.rb +64 -0
  40. data/lib/jubilee/server.rb +16 -0
  41. data/lib/rack/handler/jubilee.rb +43 -0
  42. data/test/.rbenv-version +1 -0
  43. data/test/config/app.rb +5 -0
  44. data/test/jubilee/test_cli.rb +11 -0
  45. data/test/jubilee/test_config.rb +14 -0
  46. data/test/jubilee/test_persistent.rb +238 -0
  47. data/test/jubilee/test_rack_server.rb +116 -0
  48. data/test/jubilee/test_server.rb +68 -0
  49. data/test/sinatra_app/app.rb +31 -0
  50. data/test/sinatra_app/config.ru +6 -0
  51. data/test/sinatra_app/public/test.html +10 -0
  52. data/test/sinatra_app/unicorn.conf.rb +29 -0
  53. data/test/test_helper.rb +21 -0
  54. metadata +160 -0
@@ -0,0 +1,111 @@
1
+ package org.jruby.jubilee.impl;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyClass;
5
+ import org.jruby.RubyModule;
6
+ import org.jruby.RubyObject;
7
+ import org.jruby.anno.JRubyMethod;
8
+ import org.jruby.jubilee.RackInput;
9
+ import org.jruby.runtime.Block;
10
+ import org.jruby.runtime.ObjectAllocator;
11
+ import org.jruby.runtime.ThreadContext;
12
+ import org.jruby.runtime.builtin.IRubyObject;
13
+
14
+ /**
15
+ * Created with IntelliJ IDEA.
16
+ * User: isaiah
17
+ * Date: 11/26/12
18
+ * Time: 12:11 PM
19
+ */
20
+ public class NullIO extends RubyObject implements RackInput {
21
+ public static RubyClass createNullIOClass(Ruby ruby) {
22
+ RubyModule jModule = ruby.defineModule("Jubilee");
23
+ RubyClass nullIOClass = jModule.defineClassUnder("NullIO", ruby.getObject(), ALLOCATOR);
24
+ nullIOClass.defineAnnotatedMethods(NullIO.class);
25
+ return nullIOClass;
26
+ }
27
+
28
+ public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
29
+ @Override
30
+ public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
31
+ return new NullIO(ruby, rubyClass);
32
+ }
33
+ };
34
+
35
+ public NullIO(Ruby ruby) {
36
+ this(ruby, createNullIOClass(ruby));
37
+ }
38
+
39
+ public NullIO(Ruby runtime, RubyClass metaClass) {
40
+ super(runtime, metaClass);
41
+ }
42
+
43
+ /**
44
+ * gets must be called without arguments and return a string, or nil on EOF.
45
+ *
46
+ * @param context it's a JRuby thing
47
+ * @return a string, or nil on EOF
48
+ */
49
+ @Override
50
+ @JRubyMethod(name = "gets")
51
+ public IRubyObject gets(ThreadContext context) {
52
+ return getRuntime().getNil();
53
+ }
54
+
55
+ /**
56
+ * read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
57
+ * length must be an non-negative Integer (>= 0) or nil, and buffer must be a
58
+ * String and may not be nil. If length is given and not nil, then this method
59
+ * reads at most length bytes from the input stream. If length is not given or
60
+ * nil, then this method reads all data until EOF. When EOF is reached, this
61
+ * method returns nil if length is given and not nil, or "" if length is not
62
+ * given or is nil. If buffer is given, then the read data will be placed into
63
+ * buffer instead of a newly created String object.
64
+ *
65
+ * @param context it's a JRuby thing
66
+ * @param args [length, [buffer]]
67
+ * @return nil if length is given and not nil, or "" if length is not given or nil
68
+ */
69
+ @Override
70
+ @JRubyMethod(optional = 2)
71
+ public IRubyObject read(ThreadContext context, IRubyObject[] args) {
72
+ return getRuntime().getNil();
73
+ }
74
+
75
+ /**
76
+ * each must be called without arguments and only yield Strings.
77
+ *
78
+ * @param context it's a JRuby thing
79
+ * @param block that receives yield of Strings
80
+ * @return pretty much nil
81
+ */
82
+ @Override
83
+ @JRubyMethod
84
+ public IRubyObject each(ThreadContext context, Block block) {
85
+ return getRuntime().getNil();
86
+ }
87
+
88
+ /**
89
+ * rewind must be called without arguments. It rewinds the input stream back
90
+ * to the beginning. It must not raise Errno::ESPIPE: that is, it may not be
91
+ * a pipe or a socket. Therefore, handler developers must buffer the input
92
+ * data into some rewindable object if the underlying input stream is not rewindable.
93
+ *
94
+ * @param context it's a JRuby thing
95
+ * @return pretty much nil
96
+ */
97
+ @Override
98
+ @JRubyMethod
99
+ public IRubyObject rewind(ThreadContext context) {
100
+ return getRuntime().getNil();
101
+ }
102
+
103
+ /**
104
+ * Close the input. Exposed only to the Java side because the Rack spec says
105
+ * that application code must not call close, so we don't expose a close method to Ruby.
106
+ */
107
+ @Override
108
+ public IRubyObject close(ThreadContext context) {
109
+ return getRuntime().getNil();
110
+ }
111
+ }
@@ -0,0 +1,68 @@
1
+ package org.jruby.jubilee.impl;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyClass;
5
+ import org.jruby.RubyModule;
6
+ import org.jruby.RubyObject;
7
+ import org.jruby.anno.JRubyMethod;
8
+ import org.jruby.jubilee.RackErrors;
9
+ import org.jruby.runtime.ObjectAllocator;
10
+ import org.jruby.runtime.ThreadContext;
11
+ import org.jruby.runtime.builtin.IRubyObject;
12
+
13
+ /**
14
+ * Created with IntelliJ IDEA.
15
+ * User: isaiah
16
+ * Date: 11/26/12
17
+ * Time: 12:03 PM
18
+ */
19
+ public class RubyIORackErrors extends RubyObject implements RackErrors {
20
+
21
+ public static RubyClass createRubyIORackErrorsClass(Ruby runtime) {
22
+ RubyModule jModule = runtime.defineModule("Jubilee");
23
+ RubyClass rackErrorsClass = jModule.defineClassUnder("RubyIORackErrors", runtime.getObject(), ALLOCATOR);
24
+ rackErrorsClass.defineAnnotatedMethods(RubyIORackErrors.class);
25
+ return rackErrorsClass;
26
+ }
27
+
28
+ public static final ObjectAllocator ALLOCATOR = new ObjectAllocator() {
29
+ @Override
30
+ public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
31
+ return new RubyIORackErrors(ruby, rubyClass);
32
+ }
33
+ };
34
+
35
+ public RubyIORackErrors(Ruby runtime, RubyClass metaClass) {
36
+ super(runtime, metaClass);
37
+ }
38
+
39
+ public RubyIORackErrors(Ruby runtime) {
40
+ super(runtime, createRubyIORackErrorsClass(runtime));
41
+ }
42
+
43
+ @Override
44
+ @JRubyMethod(name = "puts")
45
+ public IRubyObject puts(ThreadContext context, IRubyObject arg) {
46
+ //getRuntime().getOutputStream().println(arg.toString());
47
+ return null; //To change body of implemented methods use File | Settings | File Templates.
48
+ }
49
+
50
+ @Override
51
+ @JRubyMethod
52
+ public IRubyObject write(ThreadContext context, IRubyObject string) {
53
+ //getRuntime().getOutputStream().println(string.toString());
54
+ return null; //To change body of implemented methods use File | Settings | File Templates.
55
+ }
56
+
57
+ @Override
58
+ @JRubyMethod
59
+ public IRubyObject flush() {
60
+ return null; //To change body of implemented methods use File | Settings | File Templates.
61
+ }
62
+
63
+ @Override
64
+ @JRubyMethod
65
+ public IRubyObject close() {
66
+ return null; //To change body of implemented methods use File | Settings | File Templates.
67
+ }
68
+ }
@@ -0,0 +1,164 @@
1
+ package org.jruby.jubilee.impl;
2
+
3
+ import org.jboss.netty.buffer.ChannelBuffer;
4
+ import org.jruby.*;
5
+ import org.jruby.anno.JRubyMethod;
6
+ import org.jruby.jubilee.Const;
7
+ import org.jruby.jubilee.RackInput;
8
+ import org.jruby.runtime.Block;
9
+ import org.jruby.runtime.ObjectAllocator;
10
+ import org.jruby.runtime.ThreadContext;
11
+ import org.jruby.runtime.builtin.IRubyObject;
12
+ import org.vertx.java.core.buffer.Buffer;
13
+
14
+ import java.util.concurrent.CountDownLatch;
15
+ import java.util.concurrent.TimeUnit;
16
+
17
+ /**
18
+ * Created with IntelliJ IDEA.
19
+ * User: isaiah
20
+ * Date: 11/26/12
21
+ * Time: 10:12 PM
22
+ */
23
+ public class RubyIORackInput extends RubyObject implements RackInput {
24
+ private ChannelBuffer buf;
25
+ private CountDownLatch bodyLatch;
26
+
27
+ public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
28
+ @Override
29
+ public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
30
+ return new RubyIORackInput(ruby, rubyClass);
31
+ }
32
+ };
33
+
34
+ public static RubyClass createRubyIORackInputClass(Ruby runtime) {
35
+ RubyModule jModule = runtime.defineModule("Jubilee");
36
+ RubyClass rackIOInputClass = jModule.defineClassUnder("RubyIORackInput", runtime.getObject(), ALLOCATOR);
37
+ rackIOInputClass.defineAnnotatedMethods(RubyIORackInput.class);
38
+ return rackIOInputClass;
39
+ }
40
+
41
+ public RubyIORackInput(Ruby runtime, RubyClass metaClass) {
42
+ super(runtime, metaClass);
43
+ }
44
+
45
+ public RubyIORackInput(Ruby runtime, Buffer buf, CountDownLatch bodyLatch) {
46
+ this(runtime, createRubyIORackInputClass(runtime));
47
+ this.buf = buf.getChannelBuffer();
48
+ this.bodyLatch = bodyLatch;
49
+ }
50
+
51
+ /**
52
+ * gets must be called without arguments and return a string, or nil on EOF.
53
+ * <p/>
54
+ * this method return one line a time.
55
+ *
56
+ * @param context it's a JRuby thing
57
+ * @return a string, or nil on EOF
58
+ */
59
+ @Override
60
+ @JRubyMethod
61
+ public IRubyObject gets(ThreadContext context) {
62
+ // TODO this is not the optimistic way. remove the latch and implement tee_input as unicorn
63
+ try {
64
+ bodyLatch.await(10, TimeUnit.SECONDS);
65
+ } catch (InterruptedException ignore) {
66
+ return getRuntime().getNil();
67
+ }
68
+ if (buf.readableBytes() == 0)
69
+ return getRuntime().getNil();
70
+ int lineEnd = buf.indexOf(buf.readerIndex(), buf.capacity(), Const.EOL);
71
+ int readLength;
72
+ if ((readLength = lineEnd - buf.readerIndex()) > 0) {
73
+ byte[] dst = new byte[readLength + 1];
74
+ buf.readBytes(dst, 0, readLength + 1);
75
+ return RubyString.newString(getRuntime(), dst);
76
+ }
77
+ return getRuntime().getNil();
78
+ }
79
+
80
+ /**
81
+ * read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
82
+ * length must be an non-negative Integer (>= 0) or nil, and buffer must be a
83
+ * String and may not be nil. If length is given and not nil, then this method
84
+ * reads at most length bytes from the input stream. If length is not given or
85
+ * nil, then this method reads all data until EOF. When EOF is reached, this
86
+ * method returns nil if length is given and not nil, or "" if) length is not
87
+ * given or is nil. If buffer is given, then the read data will be placed into
88
+ * buffer instead of a newly created String object.
89
+ *
90
+ * @param context it's a JRuby thing
91
+ * @param args [length, [buffer]]
92
+ * @return nil if length is given and not nil, or "" if length is not given or nil
93
+ */
94
+ @Override
95
+ @JRubyMethod(optional = 2)
96
+ public IRubyObject read(ThreadContext context, IRubyObject[] args) {
97
+ try {
98
+ bodyLatch.await(10, TimeUnit.SECONDS);
99
+ } catch (InterruptedException ignore) {
100
+ return getRuntime().getNil();
101
+ }
102
+ if (buf.readableBytes() == 0)
103
+ return getRuntime().getNil();
104
+ int length;
105
+ switch (args.length) {
106
+ case 0:
107
+ length = buf.readableBytes();
108
+ break;
109
+ case 1:
110
+ int len = RubyInteger.num2int(args[0]);
111
+ length = len > buf.readableBytes() ? buf.readableBytes() : len;
112
+ break;
113
+ default:
114
+ len = RubyInteger.num2int(args[0]);
115
+ length = len > buf.readableBytes() ? buf.readableBytes() : len;
116
+ }
117
+ byte[] dst = new byte[length];
118
+ buf.readBytes(dst, 0, length);
119
+ return RubyString.newString(getRuntime(), dst);
120
+ }
121
+
122
+ /**
123
+ * each must be called without arguments and only yield Strings.
124
+ *
125
+ * @param context it's a JRuby thing
126
+ * @param block that receives yield of Strings
127
+ * @return pretty much nil
128
+ */
129
+ @Override
130
+ @JRubyMethod
131
+ public IRubyObject each(ThreadContext context, Block block) {
132
+ IRubyObject str;
133
+ while (!(str = gets(context)).isNil()) {
134
+ block.yield(context, str);
135
+ }
136
+ return getRuntime().getNil();
137
+ }
138
+
139
+ /**
140
+ * rewind must be called without arguments. It rewinds the input stream back
141
+ * to the beginning. It must not raise Errno::ESPIPE: that is, it may not be
142
+ * a pipe or a socket. Therefore, handler developers must buffer the input
143
+ * data into some rewindable object if the underlying input stream is not rewindable.
144
+ *
145
+ * @param context it's a JRuby thing
146
+ * @return pretty much nil
147
+ */
148
+ @Override
149
+ @JRubyMethod
150
+ public IRubyObject rewind(ThreadContext context) {
151
+ buf.readerIndex(0);
152
+ return getRuntime().getNil();
153
+ }
154
+
155
+ /**
156
+ * Close the input. Exposed only to the Java side because the Rack spec says
157
+ * that application code must not call close, so we don't expose a close method to Ruby.
158
+ */
159
+ @JRubyMethod
160
+ public IRubyObject close(ThreadContext context) {
161
+ buf.clear();
162
+ return getRuntime().getNil();
163
+ }
164
+ }
@@ -0,0 +1,11 @@
1
+ require File.join(File.dirname(__FILE__), "../jars/vertx-core-1.3.0.final.jar")
2
+ require File.join(File.dirname(__FILE__), "../jars/netty-3.6.0.Beta1.jar")
3
+
4
+ require 'jubilee/jubilee.jar'
5
+ require 'rack'
6
+ require 'jubilee/const'
7
+ require 'jubilee/server'
8
+ require 'jubilee/application'
9
+ require 'jubilee/configuration'
10
+ require 'jubilee/response'
11
+ require 'rack/handler/jubilee'
@@ -0,0 +1,13 @@
1
+ module Jubilee
2
+ class Application
3
+ def initialize(rack_app)
4
+ unless @app = rack_app
5
+ raise "rack application not found, make sure the rackup file path is correct"
6
+ end
7
+ end
8
+
9
+ def call(env)
10
+ Response.new(@app.call(env))
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,74 @@
1
+ require 'optparse'
2
+ require 'jubilee'
3
+ require 'java'
4
+
5
+ module Jubilee
6
+ class CLI
7
+ # Parsed options
8
+ attr_accessor :options
9
+ def initialize(argv)
10
+ @argv = argv
11
+ setup_options
12
+ end
13
+
14
+ def parse_options
15
+ @parser.parse! @argv
16
+ if @argv.last
17
+ @options[:rackup] = @argv.shift
18
+ end
19
+ end
20
+
21
+ def run
22
+ parse_options
23
+ @config = Jubilee::Configuration.new(@options)
24
+ @config.load
25
+ server = Jubilee::Server.new(@config.app, {port: @config.port, ssl: @config.ssl})
26
+ server.start
27
+ puts "Jubilee is listening on port #{@config.port}, press Ctrl+C to quit"
28
+ starter = org.jruby.jubilee.deploy.Starter.new
29
+ starter.block
30
+ end
31
+
32
+ def setup_options
33
+ @options = {
34
+ debug: false,
35
+ daemon: false,
36
+ port: 3215,
37
+ ssl: false,
38
+ environment: "development"
39
+ }
40
+ @parser = OptionParser.new do |o|
41
+ #o.on "-c", "--config PATH", "Load PATH as a config file" do |arg|
42
+ # @options[:config_file] = arg
43
+ #end
44
+ #o.on "-d", "--daemon", "Daemonize the server" do
45
+ # @options[:daemon] = true
46
+ #end
47
+ o.on "--dir DIR", "Change to DIR before starting" do |arg|
48
+ @options[:chdir] = arg
49
+ end
50
+ o.on "-p", "--port PORT", "Defind which PORT the server should bind" do |arg|
51
+ @options[:port] = arg
52
+ end
53
+ o.on "--ssl", "Enable SSL connection" do
54
+ @options[:ssl] = true
55
+ end
56
+ o.on "--verbose", "Log low level debug information" do
57
+ @options[:debug] = true
58
+ end
59
+ o.on "-e", "--environment ENV", "Rack environment" do |arg|
60
+ @options[:environment] = arg
61
+ end
62
+ o.on "-q", "--quiet" do
63
+ @options[:quiet] = true
64
+ end
65
+ end
66
+
67
+ @parser.banner = "jubilee <options> <rackup file>"
68
+ @parser.on_tail "-h", "--help", "Show this message" do
69
+ puts @parser
70
+ exit 1
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,52 @@
1
+ module Jubilee
2
+ class Configuration
3
+ def initialize(options, &block)
4
+ @options = options
5
+ @block = block
6
+ end
7
+
8
+ def load
9
+ @app = load_rack_adapter(@options, &@block)
10
+ end
11
+
12
+ def app
13
+ if !@options[:quiet] and @options[:environment] == "development"
14
+ logger = @options[:logger] || STDOUT
15
+ Rack::CommonLogger.new(@app, logger)
16
+ else
17
+ @app
18
+ end
19
+ end
20
+
21
+ def port
22
+ @options[:port]
23
+ end
24
+
25
+ def ssl
26
+ @options[:ssl]
27
+ end
28
+
29
+ #def self.load(config)
30
+ # rackup_code = ::File.read(config)
31
+ # eval("Rack::Builder.new {( #{rackup_code}\n )}.to_app", TOPLEVEL_BINDING, config)
32
+ #end
33
+
34
+ private
35
+ def load_rack_adapter(options, &block)
36
+ if block
37
+ app = Rack::Builder.new(&block).to_app
38
+ else
39
+ if options[:rackup]
40
+ Kernel.load(options[:rackup])
41
+ app = Object.const_get(File.basename(options[:rackup], '.rb').capitalize.to_sym).new
42
+ else
43
+ Dir.chdir options[:chdir] if options[:chdir]
44
+ app, opts = Rack::Builder.parse_file "config.ru"
45
+ end
46
+ end
47
+ app
48
+ #Rack::Lint.new(Rack::CommonLogger.new(app, STDOUT))
49
+ end
50
+
51
+ end
52
+ end