jubilee 1.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/CHANGELOG +32 -0
- data/Gemfile +35 -0
- data/Gemfile.lock +244 -0
- data/Guardfile +24 -0
- data/KNOWN_ISSUES +6 -0
- data/LICENSE.txt +20 -0
- data/README.md +147 -0
- data/ROADMAP +5 -0
- data/Rakefile +98 -0
- data/bin/jubilee +6 -0
- data/bin/jubilee_d +13 -0
- data/examples/chatapp/Gemfile +5 -0
- data/examples/chatapp/Gemfile.lock +27 -0
- data/examples/chatapp/README.md +17 -0
- data/examples/chatapp/app.rb +57 -0
- data/examples/chatapp/config.ru +3 -0
- data/examples/chatapp/public/assets/javascripts/application.js +67 -0
- data/examples/chatapp/public/assets/javascripts/jquery.js +5 -0
- data/examples/chatapp/public/assets/javascripts/sockjs-0.3.4.min.js +27 -0
- data/examples/chatapp/public/assets/javascripts/vertxbus.js +216 -0
- data/examples/chatapp/public/assets/stylesheets/application.css +29 -0
- data/examples/client/sockjs-0.3.4.min.js +27 -0
- data/examples/client/vertxbus.js +216 -0
- data/examples/jubilee.conf.rb +12 -0
- data/examples/jubilee/keystore.jks +0 -0
- data/examples/jubilee/server-keystore.jks +0 -0
- data/jars/hazelcast-2.6.3.jar +0 -0
- data/jars/jackson-annotations-2.2.2.jar +0 -0
- data/jars/jackson-core-2.2.2.jar +0 -0
- data/jars/jackson-databind-2.2.2.jar +0 -0
- data/jars/netty-all-4.0.13.Final.jar +0 -0
- data/jars/vertx-core-2.1M3-SNAPSHOT.jar +0 -0
- data/jars/vertx-hazelcast-2.1M3-SNAPSHOT.jar +0 -0
- data/java/src/jubilee/JubileeService.java +20 -0
- data/java/src/org/jruby/jubilee/Const.java +32 -0
- data/java/src/org/jruby/jubilee/RackApplication.java +103 -0
- data/java/src/org/jruby/jubilee/RackEnvironment.java +150 -0
- data/java/src/org/jruby/jubilee/RackEnvironmentHash.java +449 -0
- data/java/src/org/jruby/jubilee/RackInput.java +62 -0
- data/java/src/org/jruby/jubilee/RackResponse.java +11 -0
- data/java/src/org/jruby/jubilee/RubyHttpServerResponse.java +88 -0
- data/java/src/org/jruby/jubilee/RubyServer.java +171 -0
- data/java/src/org/jruby/jubilee/deploy/Starter.java +26 -0
- data/java/src/org/jruby/jubilee/impl/RubyIORackInput.java +201 -0
- data/java/src/org/jruby/jubilee/impl/RubyNullIO.java +107 -0
- data/java/src/org/jruby/jubilee/utils/RubyHelper.java +37 -0
- data/java/src/org/jruby/jubilee/vertx/JubileeVertx.java +38 -0
- data/jubilee.gemspec +201 -0
- data/lib/jubilee.rb +17 -0
- data/lib/jubilee/application.rb +13 -0
- data/lib/jubilee/cli.rb +127 -0
- data/lib/jubilee/configuration.rb +177 -0
- data/lib/jubilee/const.rb +40 -0
- data/lib/jubilee/jubilee.jar +0 -0
- data/lib/jubilee/response.rb +69 -0
- data/lib/jubilee/server.rb +12 -0
- data/lib/jubilee/version.rb +10 -0
- data/lib/rack/chunked.rb +38 -0
- data/lib/rack/handler/jubilee.rb +44 -0
- data/lib/vertx.rb +26 -0
- data/lib/vertx/README.md +7 -0
- data/lib/vertx/buffer.rb +251 -0
- data/lib/vertx/event_bus.rb +206 -0
- data/lib/vertx/shared_data.rb +214 -0
- data/spec/apps/rack/basic/config.ru +50 -0
- data/spec/apps/rails4/basic/.gitignore +16 -0
- data/spec/apps/rails4/basic/Gemfile +41 -0
- data/spec/apps/rails4/basic/Gemfile.lock +127 -0
- data/spec/apps/rails4/basic/README.rdoc +28 -0
- data/spec/apps/rails4/basic/Rakefile +6 -0
- data/spec/apps/rails4/basic/app/assets/images/.keep +0 -0
- data/spec/apps/rails4/basic/app/assets/images/rails.png +0 -0
- data/spec/apps/rails4/basic/app/assets/javascripts/application.js +12 -0
- data/spec/apps/rails4/basic/app/assets/stylesheets/application.css +13 -0
- data/spec/apps/rails4/basic/app/controllers/application_controller.rb +5 -0
- data/spec/apps/rails4/basic/app/controllers/concerns/.keep +0 -0
- data/spec/apps/rails4/basic/app/controllers/reloader_controller.rb +11 -0
- data/spec/apps/rails4/basic/app/controllers/reloader_controller.rb.erb +11 -0
- data/spec/apps/rails4/basic/app/controllers/root_controller.rb +14 -0
- data/spec/apps/rails4/basic/app/helpers/application_helper.rb +2 -0
- data/spec/apps/rails4/basic/app/mailers/.keep +0 -0
- data/spec/apps/rails4/basic/app/models/.keep +0 -0
- data/spec/apps/rails4/basic/app/models/concerns/.keep +0 -0
- data/spec/apps/rails4/basic/app/views/layouts/application.html.erb +14 -0
- data/spec/apps/rails4/basic/app/views/reloader/index.html.erb +1 -0
- data/spec/apps/rails4/basic/app/views/root/index.html.erb +8 -0
- data/spec/apps/rails4/basic/app/views/root/streaming.html.erb +6 -0
- data/spec/apps/rails4/basic/bin/bundle +3 -0
- data/spec/apps/rails4/basic/bin/rails +4 -0
- data/spec/apps/rails4/basic/bin/rake +4 -0
- data/spec/apps/rails4/basic/config.ru +4 -0
- data/spec/apps/rails4/basic/config/application.rb +23 -0
- data/spec/apps/rails4/basic/config/boot.rb +4 -0
- data/spec/apps/rails4/basic/config/database.yml +20 -0
- data/spec/apps/rails4/basic/config/environment.rb +5 -0
- data/spec/apps/rails4/basic/config/environments/development.rb +29 -0
- data/spec/apps/rails4/basic/config/environments/production.rb +80 -0
- data/spec/apps/rails4/basic/config/environments/test.rb +36 -0
- data/spec/apps/rails4/basic/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/apps/rails4/basic/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/apps/rails4/basic/config/initializers/inflections.rb +16 -0
- data/spec/apps/rails4/basic/config/initializers/mime_types.rb +5 -0
- data/spec/apps/rails4/basic/config/initializers/secret_token.rb +12 -0
- data/spec/apps/rails4/basic/config/initializers/session_store.rb +2 -0
- data/spec/apps/rails4/basic/config/initializers/wrap_parameters.rb +14 -0
- data/spec/apps/rails4/basic/config/locales/en.yml +23 -0
- data/spec/apps/rails4/basic/config/routes.rb +5 -0
- data/spec/apps/rails4/basic/db/seeds.rb +7 -0
- data/spec/apps/rails4/basic/lib/assets/.keep +0 -0
- data/spec/apps/rails4/basic/lib/tasks/.keep +0 -0
- data/spec/apps/rails4/basic/public/404.html +58 -0
- data/spec/apps/rails4/basic/public/422.html +58 -0
- data/spec/apps/rails4/basic/public/500.html +57 -0
- data/spec/apps/rails4/basic/public/favicon.ico +0 -0
- data/spec/apps/rails4/basic/public/robots.txt +5 -0
- data/spec/apps/rails4/basic/public/some_page.html +7 -0
- data/spec/apps/rails4/basic/test/controllers/.keep +0 -0
- data/spec/apps/rails4/basic/test/fixtures/.keep +0 -0
- data/spec/apps/rails4/basic/test/helpers/.keep +0 -0
- data/spec/apps/rails4/basic/test/integration/.keep +0 -0
- data/spec/apps/rails4/basic/test/mailers/.keep +0 -0
- data/spec/apps/rails4/basic/test/models/.keep +0 -0
- data/spec/apps/rails4/basic/test/test_helper.rb +15 -0
- data/spec/apps/rails4/basic/vendor/assets/javascripts/.keep +0 -0
- data/spec/apps/rails4/basic/vendor/assets/stylesheets/.keep +0 -0
- data/spec/apps/sinatra/basic/Gemfile +4 -0
- data/spec/apps/sinatra/basic/Gemfile.lock +20 -0
- data/spec/apps/sinatra/basic/basic.rb +27 -0
- data/spec/apps/sinatra/basic/config.ru +7 -0
- data/spec/apps/sinatra/basic/public/some_page.html +7 -0
- data/spec/apps/sinatra/basic/views/index.erb +4 -0
- data/spec/apps/sinatra/basic/views/posted.haml +2 -0
- data/spec/apps/sinatra/basic/views/poster.haml +4 -0
- data/spec/apps/sinatra/basic/views/request_mapping.haml +4 -0
- data/spec/integration/basic_rack_spec.rb +89 -0
- data/spec/integration/basic_rails4_spec.rb +64 -0
- data/spec/integration/basic_sinatra_spec.rb +80 -0
- data/spec/spec_helper.rb +13 -0
- data/test/.ruby-version +1 -0
- data/test/config/app.rb +5 -0
- data/test/jubilee/test_cli.rb +11 -0
- data/test/jubilee/test_configuration.rb +31 -0
- data/test/jubilee/test_rack_server.rb +137 -0
- data/test/jubilee/test_response.rb +272 -0
- data/test/jubilee/test_server.rb +72 -0
- data/test/jubilee/test_upload.rb +301 -0
- data/test/sinatra_app/app.rb +31 -0
- data/test/sinatra_app/config.ru +6 -0
- data/test/sinatra_app/public/test.html +10 -0
- data/test/sinatra_app/unicorn.conf.rb +29 -0
- data/test/test_helper.rb +93 -0
- metadata +242 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
package org.jruby.jubilee;
|
2
|
+
|
3
|
+
import org.jruby.runtime.Block;
|
4
|
+
import org.jruby.runtime.ThreadContext;
|
5
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
6
|
+
|
7
|
+
/**
|
8
|
+
* @author isaiah
|
9
|
+
* @since Nov 26, 2012
|
10
|
+
*
|
11
|
+
* Specification for Rack input, translated to a Java interface.
|
12
|
+
* @author nicksieger
|
13
|
+
*/
|
14
|
+
public interface RackInput
|
15
|
+
{
|
16
|
+
/**
|
17
|
+
* gets must be called without arguments and return a string, or nil on EOF.
|
18
|
+
* @param context it's a JRuby thing
|
19
|
+
* @return a string, or nil on EOF
|
20
|
+
*/
|
21
|
+
IRubyObject gets( ThreadContext context );
|
22
|
+
|
23
|
+
/**
|
24
|
+
* read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
|
25
|
+
* length must be an non-negative Integer (>= 0) or nil, and buffer must be a
|
26
|
+
* String and may not be nil. If length is given and not nil, then this method
|
27
|
+
* reads at most length bytes from the input stream. If length is not given or
|
28
|
+
* nil, then this method reads all data until EOF. When EOF is reached, this
|
29
|
+
* method returns nil if length is given and not nil, or "" if length is not
|
30
|
+
* given or is nil. If buffer is given, then the read data will be placed into
|
31
|
+
* buffer instead of a newly created String object.
|
32
|
+
* @param context it's a JRuby thing
|
33
|
+
* @param args [length, [buffer]]
|
34
|
+
* @return nil if length is given and not nil, or "" if length is not given or nil
|
35
|
+
*/
|
36
|
+
IRubyObject read( ThreadContext context, IRubyObject[] args );
|
37
|
+
|
38
|
+
/**
|
39
|
+
* each must be called without arguments and only yield Strings.
|
40
|
+
* @param context it's a JRuby thing
|
41
|
+
* @param block that receives yield of Strings
|
42
|
+
* @return pretty much nil
|
43
|
+
*/
|
44
|
+
public IRubyObject each( ThreadContext context, Block block );
|
45
|
+
|
46
|
+
/**
|
47
|
+
* rewind must be called without arguments. It rewinds the input stream back
|
48
|
+
* to the beginning. It must not raise Errno::ESPIPE: that is, it may not be
|
49
|
+
* a pipe or a socket. Therefore, handler developers must buffer the input
|
50
|
+
* data into some rewindable object if the underlying input stream is not rewindable.
|
51
|
+
* @param context it's a JRuby thing
|
52
|
+
* @return pretty much nil
|
53
|
+
*/
|
54
|
+
public IRubyObject rewind( ThreadContext context );
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Close the input. Exposed only to the Java side because the Rack spec says
|
58
|
+
* that application code must not call close, so we don't expose a close method to Ruby.
|
59
|
+
*/
|
60
|
+
public IRubyObject close(ThreadContext context);
|
61
|
+
}
|
62
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
package org.jruby.jubilee;
|
2
|
+
|
3
|
+
import org.jruby.*;
|
4
|
+
import org.jruby.anno.JRubyClass;
|
5
|
+
import org.jruby.anno.JRubyMethod;
|
6
|
+
import org.jruby.runtime.ObjectAllocator;
|
7
|
+
import org.jruby.runtime.ThreadContext;
|
8
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
9
|
+
import org.vertx.java.core.http.HttpServerResponse;
|
10
|
+
|
11
|
+
import java.util.Arrays;
|
12
|
+
|
13
|
+
/**
|
14
|
+
* Created by isaiah on 21/12/2013.
|
15
|
+
*/
|
16
|
+
@JRubyClass(name = "HttpServerResponse")
|
17
|
+
public class RubyHttpServerResponse extends RubyObject {
|
18
|
+
private HttpServerResponse resp;
|
19
|
+
private String lineSeparator;
|
20
|
+
|
21
|
+
public static RubyClass createHttpServerResponseClass(final Ruby runtime) {
|
22
|
+
RubyModule mJubilee = runtime.getOrCreateModule("Jubilee");
|
23
|
+
RubyClass klazz = mJubilee.defineClassUnder("HttpServerResponse", runtime.getObject(), new ObjectAllocator() {
|
24
|
+
@Override
|
25
|
+
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
26
|
+
return new RubyHttpServerResponse(ruby, rubyClass);
|
27
|
+
}
|
28
|
+
});
|
29
|
+
klazz.defineAnnotatedMethods(RubyHttpServerResponse.class);
|
30
|
+
return klazz;
|
31
|
+
}
|
32
|
+
|
33
|
+
public RubyHttpServerResponse(Ruby ruby, RubyClass rubyClass) {
|
34
|
+
super(ruby, rubyClass);
|
35
|
+
}
|
36
|
+
|
37
|
+
public RubyHttpServerResponse(Ruby ruby, RubyClass rubyClass, HttpServerResponse resp) {
|
38
|
+
super(ruby, rubyClass);
|
39
|
+
this.resp = resp;
|
40
|
+
this.lineSeparator = System.getProperty("line.separator");
|
41
|
+
}
|
42
|
+
|
43
|
+
@JRubyMethod
|
44
|
+
public IRubyObject write(ThreadContext context, IRubyObject string) {
|
45
|
+
this.resp.write(string.asJavaString());
|
46
|
+
return context.runtime.getNil();
|
47
|
+
}
|
48
|
+
|
49
|
+
@JRubyMethod(name = "status_code=")
|
50
|
+
public IRubyObject setStatusCode(ThreadContext context, IRubyObject statusCode) {
|
51
|
+
this.resp.setStatusCode(RubyNumeric.num2int(statusCode));
|
52
|
+
return context.runtime.getNil();
|
53
|
+
}
|
54
|
+
|
55
|
+
@JRubyMethod(name = "chunked=")
|
56
|
+
public IRubyObject setChunked(ThreadContext context, IRubyObject chunked) {
|
57
|
+
this.resp.setChunked(chunked.isTrue());
|
58
|
+
return context.runtime.getNil();
|
59
|
+
}
|
60
|
+
|
61
|
+
@JRubyMethod(name = "put_header")
|
62
|
+
public IRubyObject putHeader(ThreadContext context, IRubyObject key, IRubyObject val) {
|
63
|
+
String cookie = val.asJavaString();
|
64
|
+
if (cookie.indexOf(this.lineSeparator) != -1)
|
65
|
+
this.resp.putHeader(key.asJavaString(),
|
66
|
+
Arrays.asList(val.asJavaString().split(this.lineSeparator)));
|
67
|
+
else this.resp.putHeader(key.asJavaString(), val.asJavaString());
|
68
|
+
return context.runtime.getNil();
|
69
|
+
}
|
70
|
+
|
71
|
+
@JRubyMethod(name = "send_file")
|
72
|
+
public IRubyObject sendFile(ThreadContext context, IRubyObject filePath) {
|
73
|
+
this.resp.sendFile(filePath.asJavaString());
|
74
|
+
return context.runtime.getNil();
|
75
|
+
}
|
76
|
+
|
77
|
+
@JRubyMethod
|
78
|
+
public IRubyObject end(ThreadContext context) {
|
79
|
+
this.resp.end();
|
80
|
+
return context.runtime.getNil();
|
81
|
+
}
|
82
|
+
|
83
|
+
@JRubyMethod(name = "put_default_headers")
|
84
|
+
public IRubyObject putDefaultHeaders(ThreadContext context) {
|
85
|
+
this.resp.putHeader("Server", Const.JUBILEE_VERSION);
|
86
|
+
return context.runtime.getNil();
|
87
|
+
}
|
88
|
+
}
|
@@ -0,0 +1,171 @@
|
|
1
|
+
package org.jruby.jubilee;
|
2
|
+
|
3
|
+
import org.jruby.*;
|
4
|
+
import org.jruby.anno.JRubyMethod;
|
5
|
+
import org.jruby.jubilee.vertx.JubileeVertx;
|
6
|
+
import org.jruby.runtime.Block;
|
7
|
+
import org.jruby.runtime.ObjectAllocator;
|
8
|
+
import org.jruby.runtime.ThreadContext;
|
9
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
10
|
+
import org.vertx.java.core.Handler;
|
11
|
+
import org.vertx.java.core.Vertx;
|
12
|
+
import org.vertx.java.core.http.HttpServer;
|
13
|
+
import org.vertx.java.core.http.HttpServerRequest;
|
14
|
+
import org.vertx.java.core.json.JsonArray;
|
15
|
+
import org.vertx.java.core.json.JsonObject;
|
16
|
+
|
17
|
+
import java.io.IOException;
|
18
|
+
|
19
|
+
public class RubyServer extends RubyObject {
|
20
|
+
private Vertx vertx;
|
21
|
+
private HttpServer httpServer;
|
22
|
+
private RackApplication app;
|
23
|
+
private boolean running = false;
|
24
|
+
private boolean ssl = false;
|
25
|
+
private String keyStorePath;
|
26
|
+
private String keyStorePassword;
|
27
|
+
private String eventBusPrefix;
|
28
|
+
private int port;
|
29
|
+
private String host;
|
30
|
+
private int clusterPort;
|
31
|
+
private String clusterHost;
|
32
|
+
|
33
|
+
public static void createServerClass(Ruby runtime) {
|
34
|
+
RubyModule mJubilee = runtime.defineModule("Jubilee");
|
35
|
+
RubyClass serverClass = mJubilee.defineClassUnder("VertxServer", runtime.getObject(), ALLOCATOR);
|
36
|
+
serverClass.defineAnnotatedMethods(RubyServer.class);
|
37
|
+
}
|
38
|
+
|
39
|
+
private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
40
|
+
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
41
|
+
return new RubyServer(ruby, rubyClass);
|
42
|
+
}
|
43
|
+
};
|
44
|
+
|
45
|
+
public RubyServer(Ruby ruby, RubyClass rubyClass) {
|
46
|
+
super(ruby, rubyClass);
|
47
|
+
}
|
48
|
+
|
49
|
+
/**
|
50
|
+
* Initialize jubilee server, take a rack application and a configuration hash as parameter
|
51
|
+
*
|
52
|
+
* @param context
|
53
|
+
* @param app
|
54
|
+
* @param config
|
55
|
+
* @param block
|
56
|
+
* @return
|
57
|
+
*/
|
58
|
+
@JRubyMethod(name = "initialize")
|
59
|
+
public IRubyObject initialize(ThreadContext context, IRubyObject app, IRubyObject config, Block block) {
|
60
|
+
Ruby runtime = getRuntime();
|
61
|
+
/* configuration keys */
|
62
|
+
RubyHash options = config.convertToHash();
|
63
|
+
RubySymbol port_k = runtime.newSymbol("Port");
|
64
|
+
RubySymbol host_k = runtime.newSymbol("Host");
|
65
|
+
RubySymbol cluster_port_k = runtime.newSymbol("cluster_port");
|
66
|
+
RubySymbol cluster_host_k = runtime.newSymbol("cluster_host");
|
67
|
+
RubySymbol ssl_k = runtime.newSymbol("ssl");
|
68
|
+
RubySymbol keystore_path_k = runtime.newSymbol("keystore_path");
|
69
|
+
RubySymbol keystore_password_k = runtime.newSymbol("keystore_password");
|
70
|
+
RubySymbol eventbus_prefix_k = runtime.newSymbol("eventbus_prefix");
|
71
|
+
|
72
|
+
/* retrieve from passed in options */
|
73
|
+
this.port = Integer.parseInt(options.op_aref(context, port_k).toString());
|
74
|
+
this.host = options.op_aref(context, host_k).toString();
|
75
|
+
|
76
|
+
this.ssl = options.op_aref(context, ssl_k).isTrue();
|
77
|
+
if (options.has_key_p(keystore_path_k).isTrue()) {
|
78
|
+
this.keyStorePath = options.op_aref(context, keystore_path_k).toString();
|
79
|
+
this.keyStorePassword = options.op_aref(context, keystore_password_k).toString();
|
80
|
+
}
|
81
|
+
if (options.has_key_p(eventbus_prefix_k).isTrue())
|
82
|
+
this.eventBusPrefix = options.op_aref(context, eventbus_prefix_k).toString();
|
83
|
+
|
84
|
+
/* init vertx */
|
85
|
+
if (options.has_key_p(cluster_host_k).isTrue()) {
|
86
|
+
this.clusterHost = options.op_aref(context, cluster_host_k).toString();
|
87
|
+
if (options.has_key_p(cluster_port_k).isTrue()) {
|
88
|
+
this.clusterPort = Integer.parseInt(options.op_aref(context, cluster_port_k).toString());
|
89
|
+
this.vertx = JubileeVertx.init(clusterPort, clusterHost);
|
90
|
+
}
|
91
|
+
this.vertx = JubileeVertx.init(clusterHost);
|
92
|
+
} else {
|
93
|
+
this.vertx = JubileeVertx.init();
|
94
|
+
}
|
95
|
+
|
96
|
+
httpServer = vertx.createHttpServer();
|
97
|
+
try {
|
98
|
+
this.app = new RackApplication(vertx, context, app, this.ssl);
|
99
|
+
if (block.isGiven()) block.yieldSpecific(context, this);
|
100
|
+
} catch (IOException e) {
|
101
|
+
// noop
|
102
|
+
}
|
103
|
+
return this;
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* Start http server, initialize states
|
108
|
+
*
|
109
|
+
* @param context
|
110
|
+
* @param block
|
111
|
+
* @return
|
112
|
+
*/
|
113
|
+
@JRubyMethod(name = "start")
|
114
|
+
public IRubyObject start(final ThreadContext context, final Block block) {
|
115
|
+
httpServer.setAcceptBacklog(10000);
|
116
|
+
httpServer.requestHandler(new Handler<HttpServerRequest>() {
|
117
|
+
public void handle(final HttpServerRequest req) {
|
118
|
+
app.call(req);
|
119
|
+
}
|
120
|
+
});
|
121
|
+
if (eventBusPrefix != null) {
|
122
|
+
JsonObject config = new JsonObject().putString("prefix", eventBusPrefix);
|
123
|
+
JsonArray allowAll = new JsonArray();
|
124
|
+
allowAll.add(new JsonObject());
|
125
|
+
// TODO read inbounds and outbounds from config file
|
126
|
+
vertx.createSockJSServer(httpServer).bridge(config, allowAll, allowAll);
|
127
|
+
}
|
128
|
+
if (ssl) httpServer.setSSL(true).setKeyStorePath(this.keyStorePath)
|
129
|
+
.setKeyStorePassword(this.keyStorePassword);
|
130
|
+
httpServer.listen(this.port, this.host);
|
131
|
+
this.running = true;
|
132
|
+
if (block.isGiven()) block.yieldSpecific(context, this);
|
133
|
+
return this;
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
* Set timeout for keep alive connection
|
138
|
+
*
|
139
|
+
* @param context
|
140
|
+
* @param timeout (in TimeUnit.SECONDS)
|
141
|
+
* @return this
|
142
|
+
*/
|
143
|
+
@JRubyMethod(name = "persistent_timeout=")
|
144
|
+
public IRubyObject setPersistentTimeout(final ThreadContext context, final IRubyObject timeout) {
|
145
|
+
// FIXME
|
146
|
+
//httpServer.setPersistentTimeout(RubyInteger.fix2long(timeout) * 1000);
|
147
|
+
return this;
|
148
|
+
}
|
149
|
+
|
150
|
+
/**
|
151
|
+
* Stop the HttpServer
|
152
|
+
*
|
153
|
+
* @param context
|
154
|
+
* @param args if shutdown abruptly
|
155
|
+
* @param block callback on close
|
156
|
+
* @return
|
157
|
+
*/
|
158
|
+
@JRubyMethod(name = {"stop", "close"}, optional = 1)
|
159
|
+
public IRubyObject close(ThreadContext context, IRubyObject[] args, Block block) {
|
160
|
+
if (running) {
|
161
|
+
this.running = false;
|
162
|
+
httpServer.close();
|
163
|
+
// DO I need to stop?
|
164
|
+
//vertx.stop();
|
165
|
+
if (block.isGiven()) block.yieldSpecific(context);
|
166
|
+
} else {
|
167
|
+
getRuntime().getOutputStream().println("jubilee server not running?");
|
168
|
+
}
|
169
|
+
return getRuntime().getNil();
|
170
|
+
}
|
171
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
package org.jruby.jubilee.deploy;
|
2
|
+
|
3
|
+
import java.util.concurrent.CountDownLatch;
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Created with IntelliJ IDEA.
|
7
|
+
* User: isaiah
|
8
|
+
* Date: 12/3/12
|
9
|
+
* Time: 7:37 PM
|
10
|
+
*/
|
11
|
+
public class Starter {
|
12
|
+
private CountDownLatch stopLatch = new CountDownLatch(1);
|
13
|
+
|
14
|
+
public void block() {
|
15
|
+
while(true) {
|
16
|
+
try {
|
17
|
+
stopLatch.await();
|
18
|
+
break;
|
19
|
+
} catch (InterruptedException ignore) {}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
public void unblock() {
|
24
|
+
stopLatch.countDown();
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,201 @@
|
|
1
|
+
package org.jruby.jubilee.impl;
|
2
|
+
|
3
|
+
import io.netty.buffer.ByteBuf;
|
4
|
+
import org.jcodings.specific.ASCIIEncoding;
|
5
|
+
import org.jcodings.Encoding;
|
6
|
+
import org.jruby.*;
|
7
|
+
import org.jruby.anno.JRubyMethod;
|
8
|
+
import org.jruby.jubilee.Const;
|
9
|
+
import org.jruby.jubilee.RackInput;
|
10
|
+
import org.jruby.runtime.Block;
|
11
|
+
import org.jruby.runtime.ObjectAllocator;
|
12
|
+
import org.jruby.runtime.ThreadContext;
|
13
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
14
|
+
import org.jruby.util.ByteList;
|
15
|
+
import org.jruby.util.StringSupport;
|
16
|
+
import org.vertx.java.core.http.HttpServerRequest;
|
17
|
+
|
18
|
+
import java.util.concurrent.atomic.AtomicBoolean;
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Created with IntelliJ IDEA.
|
22
|
+
* User: isaiah
|
23
|
+
* Date: 11/26/12
|
24
|
+
* Time: 10:12 PM
|
25
|
+
*/
|
26
|
+
public class RubyIORackInput extends RubyObject implements RackInput {
|
27
|
+
private Encoding BINARY = ASCIIEncoding.INSTANCE;
|
28
|
+
private int len;
|
29
|
+
private boolean chunked;
|
30
|
+
private ByteBuf buf;
|
31
|
+
private AtomicBoolean eof;
|
32
|
+
|
33
|
+
public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
34
|
+
@Override
|
35
|
+
public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
|
36
|
+
return new RubyIORackInput(ruby, rubyClass);
|
37
|
+
}
|
38
|
+
};
|
39
|
+
|
40
|
+
public static RubyClass createIORackInputClass(Ruby runtime) {
|
41
|
+
RubyModule jModule = runtime.getOrCreateModule("Jubilee");
|
42
|
+
RubyClass rackIOInputClass = jModule.defineClassUnder("IORackInput", runtime.getObject(), ALLOCATOR);
|
43
|
+
rackIOInputClass.defineAnnotatedMethods(RubyIORackInput.class);
|
44
|
+
return rackIOInputClass;
|
45
|
+
}
|
46
|
+
|
47
|
+
public RubyIORackInput(Ruby runtime, RubyClass metaClass) {
|
48
|
+
super(runtime, metaClass);
|
49
|
+
}
|
50
|
+
|
51
|
+
public RubyIORackInput(Ruby runtime, RubyClass rubyClass, HttpServerRequest request, ByteBuf buf, AtomicBoolean eof) {
|
52
|
+
this(runtime, rubyClass);
|
53
|
+
String hdr = request.headers().get(Const.Vertx.CONTENT_LENGTH);
|
54
|
+
this.chunked = hdr == null;
|
55
|
+
this.len = this.chunked ? 0 : Integer.parseInt(hdr);
|
56
|
+
this.buf = buf;
|
57
|
+
this.eof = eof;
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* gets must be called without arguments and return a string, or nil on EOF.
|
62
|
+
* <p/>
|
63
|
+
* this method return one line a time.
|
64
|
+
*
|
65
|
+
* @param context it's a JRuby thing
|
66
|
+
* @return a string, or nil on EOF
|
67
|
+
*/
|
68
|
+
@Override
|
69
|
+
@JRubyMethod
|
70
|
+
public IRubyObject gets(ThreadContext context) {
|
71
|
+
Ruby runtime = context.runtime;
|
72
|
+
RubyString line = RubyString.newEmptyString(context.runtime, BINARY);
|
73
|
+
|
74
|
+
if (isEOF()) return runtime.getNil();
|
75
|
+
|
76
|
+
int lineEnd = -1;
|
77
|
+
while (lineEnd == -1 && !eof.get()) {
|
78
|
+
lineEnd = buf.indexOf(buf.readerIndex(), buf.writerIndex(), Const.EOL);
|
79
|
+
}
|
80
|
+
|
81
|
+
// No line break found, read all
|
82
|
+
if (lineEnd == -1)
|
83
|
+
return readAll(runtime, line);
|
84
|
+
|
85
|
+
int readLength = lineEnd - buf.readerIndex();
|
86
|
+
byte[] dst = new byte[readLength + 1];
|
87
|
+
buf.readBytes(dst);
|
88
|
+
return line.cat(dst);
|
89
|
+
}
|
90
|
+
|
91
|
+
/**
|
92
|
+
* read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
|
93
|
+
* length must be an non-negative Integer (>= 0) or nil, and buffer must be a
|
94
|
+
* String and may not be nil. If length is given and not nil, then this method
|
95
|
+
* reads at most length bytes from the input stream. If length is not given or
|
96
|
+
* nil, then this method reads all data until EOF. When EOF is reached, this
|
97
|
+
* method returns nil if length is given and not nil, or "" if) length is not
|
98
|
+
* given or is nil. If buffer is given, then the read data will be placed into
|
99
|
+
* buffer instead of a newly created String object.
|
100
|
+
*
|
101
|
+
* @param context it's a JRuby thing
|
102
|
+
* @param args [length, [buffer]]
|
103
|
+
* @return nil if length is given and not nil, or "" if length is not given or nil
|
104
|
+
*/
|
105
|
+
@Override
|
106
|
+
@JRubyMethod(optional = 2)
|
107
|
+
public IRubyObject read(ThreadContext context, IRubyObject[] args) {
|
108
|
+
Ruby runtime = context.runtime;
|
109
|
+
RubyString dst = RubyString.newStringNoCopy(context.runtime, new ByteList(), BINARY, StringSupport.CR_VALID);
|
110
|
+
if (isEOF())
|
111
|
+
return runtime.getNil();
|
112
|
+
int length;
|
113
|
+
switch (args.length) {
|
114
|
+
case 0:
|
115
|
+
return readAll(runtime, dst);
|
116
|
+
case 1:
|
117
|
+
length = RubyNumeric.num2int(args[0]);
|
118
|
+
break;
|
119
|
+
default:
|
120
|
+
length = RubyNumeric.num2int(args[0]);
|
121
|
+
dst = (RubyString) args[1];
|
122
|
+
}
|
123
|
+
if (length < 0)
|
124
|
+
runtime.newArgumentError("Negative length " + length + " given");
|
125
|
+
byte[] buffer = new byte[length];
|
126
|
+
int toRead = length;
|
127
|
+
while (toRead > 0 && !isEOF()) {
|
128
|
+
int len = Math.min(toRead, readableBytes());
|
129
|
+
buf.readBytes(buffer, length - toRead, len);
|
130
|
+
toRead = toRead - len;
|
131
|
+
}
|
132
|
+
if (toRead > 0) length -= toRead;
|
133
|
+
return dst.cat(buffer, 0, length);
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
* each must be called without arguments and only yield Strings.
|
138
|
+
*
|
139
|
+
* @param context it's a JRuby thing
|
140
|
+
* @param block that receives yield of Strings
|
141
|
+
* @return pretty much nil
|
142
|
+
*/
|
143
|
+
@Override
|
144
|
+
@JRubyMethod
|
145
|
+
public IRubyObject each(ThreadContext context, Block block) {
|
146
|
+
IRubyObject str;
|
147
|
+
while (!(str = gets(context)).isNil()) {
|
148
|
+
block.yield(context, str);
|
149
|
+
}
|
150
|
+
return context.runtime.getNil();
|
151
|
+
}
|
152
|
+
|
153
|
+
/**
|
154
|
+
* rewind must be called without arguments. It rewinds the input stream back
|
155
|
+
* to the beginning. It must not raise Errno::ESPIPE: that is, it may not be
|
156
|
+
* a pipe or a socket. Therefore, handler developers must buffer the input
|
157
|
+
* data into some rewindable object if the underlying input stream is not rewindable.
|
158
|
+
*
|
159
|
+
* @param context it's a JRuby thing
|
160
|
+
* @return pretty much nil
|
161
|
+
*/
|
162
|
+
@Override
|
163
|
+
@JRubyMethod
|
164
|
+
public IRubyObject rewind(ThreadContext context) {
|
165
|
+
buf.readerIndex(0);
|
166
|
+
return context.runtime.getNil();
|
167
|
+
}
|
168
|
+
|
169
|
+
/**
|
170
|
+
* Close the input. Exposed only to the Java side because the Rack spec says
|
171
|
+
* that application code must not call close, so we don't expose a close method to Ruby.
|
172
|
+
*/
|
173
|
+
@JRubyMethod
|
174
|
+
public IRubyObject close(ThreadContext context) {
|
175
|
+
buf.clear();
|
176
|
+
return context.runtime.getNil();
|
177
|
+
}
|
178
|
+
|
179
|
+
private int readableBytes() {
|
180
|
+
if (! this.chunked) {
|
181
|
+
return Math.min(buf.readableBytes(), this.len - buf.readerIndex());
|
182
|
+
}
|
183
|
+
return buf.readableBytes();
|
184
|
+
}
|
185
|
+
|
186
|
+
private boolean isEOF() {
|
187
|
+
while (buf.readableBytes() == 0 && !eof.get())
|
188
|
+
; // wait while there is nothing to read
|
189
|
+
return buf.readableBytes() == 0 && eof.get();
|
190
|
+
}
|
191
|
+
|
192
|
+
private IRubyObject readAll(Ruby runtime, RubyString dst) {
|
193
|
+
while(!eof.get())
|
194
|
+
; // wait until all data received
|
195
|
+
int length = this.chunked ? buf.readableBytes() : Math.min(this.len, buf.readableBytes());
|
196
|
+
byte[] data = new byte[length];
|
197
|
+
buf.readBytes(data);
|
198
|
+
dst.cat(data);
|
199
|
+
return dst.isEmpty() ? runtime.getNil() : dst;
|
200
|
+
}
|
201
|
+
}
|