jubilee 0.1.2

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.
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