jubilee 2.1.0.Alpha1-java → 2.1.0.beta-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -2
  3. data/CHANGELOG +9 -0
  4. data/README.md +12 -7
  5. data/jars/vertx-core-2.1.1.jar +0 -0
  6. data/java/src/jubilee/JubileeService.java +3 -3
  7. data/java/src/org/jruby/jubilee/Const.java +1 -1
  8. data/java/src/org/jruby/jubilee/JubileeVerticle.java +29 -4
  9. data/java/src/org/jruby/jubilee/RackApplication.java +38 -35
  10. data/java/src/org/jruby/jubilee/RackEnvironment.java +57 -23
  11. data/java/src/org/jruby/jubilee/RackEnvironmentHash.java +64 -11
  12. data/java/src/org/jruby/jubilee/RackInput.java +13 -10
  13. data/java/src/org/jruby/jubilee/RubyCallable.java +52 -0
  14. data/java/src/org/jruby/jubilee/RubyChannel.java +89 -0
  15. data/java/src/org/jruby/jubilee/RubyHttpServerResponse.java +72 -60
  16. data/java/src/org/jruby/jubilee/RubyNetSocket.java +169 -0
  17. data/java/src/org/jruby/jubilee/RubyPlatformManager.java +129 -113
  18. data/java/src/org/jruby/jubilee/impl/RubyIORackInput.java +9 -9
  19. data/java/src/org/jruby/jubilee/impl/RubyNullIO.java +1 -1
  20. data/java/src/org/jruby/jubilee/utils/RubyHelper.java +0 -6
  21. data/java/src/org/jruby/jubilee/vertx/JubileeVertx.java +12 -11
  22. data/jubilee.gemspec +43 -20
  23. data/lib/jubilee.rb +0 -1
  24. data/lib/jubilee/cli.rb +5 -3
  25. data/lib/jubilee/configuration.rb +2 -7
  26. data/lib/jubilee/const.rb +30 -28
  27. data/lib/jubilee/response.rb +40 -5
  28. data/lib/jubilee/server.rb +0 -3
  29. data/lib/jubilee/version.rb +1 -1
  30. data/spec/apps/rails4/basic/Gemfile +0 -2
  31. data/spec/apps/rails4/basic/Gemfile.lock +0 -7
  32. data/spec/integration/basic_rack_spec.rb +4 -3
  33. data/spec/integration/basic_rails4_spec.rb +4 -3
  34. data/spec/integration/basic_sinatra_spec.rb +4 -4
  35. data/spec/spec_helper.rb +1 -0
  36. data/test/{config → apps}/app.rb +0 -0
  37. data/test/apps/checker.ru +5 -10
  38. data/test/apps/chunked.ru +3 -0
  39. data/test/{config → apps}/config.ru +0 -0
  40. data/test/apps/content_length.ru +3 -0
  41. data/test/apps/hex.ru +4 -0
  42. data/test/apps/hijack.ru +7 -0
  43. data/test/apps/hijack2.ru +7 -0
  44. data/test/apps/huge.ru +4 -0
  45. data/test/apps/method_override.ru +1 -1
  46. data/test/apps/overwrite_check.ru +3 -2
  47. data/test/apps/persistent.rb +14 -0
  48. data/test/apps/persistent.ru +3 -0
  49. data/test/apps/rack_input.ru +5 -0
  50. data/test/apps/self_chunked.ru +6 -0
  51. data/test/apps/sha1.ru +2 -0
  52. data/test/apps/simple.ru +10 -1
  53. data/test/jubilee/test_cli.rb +1 -1
  54. data/test/jubilee/test_configuration.rb +1 -3
  55. data/test/jubilee/test_hijack.rb +27 -0
  56. data/test/jubilee/test_persistent.rb +208 -0
  57. data/test/jubilee/test_rack_server.rb +29 -68
  58. data/test/jubilee/test_server.rb +49 -15
  59. data/test/jubilee/test_upload.rb +13 -60
  60. data/test/test_helper.rb +2 -2
  61. metadata +19 -9
  62. data/java/src/org/jruby/jubilee/RubyServer.java +0 -159
  63. data/lib/jubilee/jubilee.jar +0 -0
  64. data/lib/rack/chunked.rb +0 -38
  65. data/test/config/app.ru +0 -3
  66. data/test/jubilee/test_response.rb +0 -270
@@ -6,19 +6,19 @@ import org.jruby.runtime.builtin.IRubyObject;
6
6
 
7
7
  /**
8
8
  * @author isaiah
9
+ * @author nicksieger
9
10
  * @since Nov 26, 2012
10
- *
11
+ * <p/>
11
12
  * Specification for Rack input, translated to a Java interface.
12
- * @author nicksieger
13
13
  */
14
- public interface RackInput
15
- {
14
+ public interface RackInput {
16
15
  /**
17
16
  * gets must be called without arguments and return a string, or nil on EOF.
17
+ *
18
18
  * @param context it's a JRuby thing
19
19
  * @return a string, or nil on EOF
20
20
  */
21
- IRubyObject gets( ThreadContext context );
21
+ IRubyObject gets(ThreadContext context);
22
22
 
23
23
  /**
24
24
  * read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
@@ -29,29 +29,32 @@ public interface RackInput
29
29
  * method returns nil if length is given and not nil, or "" if length is not
30
30
  * given or is nil. If buffer is given, then the read data will be placed into
31
31
  * buffer instead of a newly created String object.
32
+ *
32
33
  * @param context it's a JRuby thing
33
- * @param args [length, [buffer]]
34
+ * @param args [length, [buffer]]
34
35
  * @return nil if length is given and not nil, or "" if length is not given or nil
35
36
  */
36
- IRubyObject read( ThreadContext context, IRubyObject[] args );
37
+ IRubyObject read(ThreadContext context, IRubyObject[] args);
37
38
 
38
39
  /**
39
40
  * each must be called without arguments and only yield Strings.
41
+ *
40
42
  * @param context it's a JRuby thing
41
- * @param block that receives yield of Strings
43
+ * @param block that receives yield of Strings
42
44
  * @return pretty much nil
43
45
  */
44
- public IRubyObject each( ThreadContext context, Block block );
46
+ public IRubyObject each(ThreadContext context, Block block);
45
47
 
46
48
  /**
47
49
  * rewind must be called without arguments. It rewinds the input stream back
48
50
  * to the beginning. It must not raise Errno::ESPIPE: that is, it may not be
49
51
  * a pipe or a socket. Therefore, handler developers must buffer the input
50
52
  * data into some rewindable object if the underlying input stream is not rewindable.
53
+ *
51
54
  * @param context it's a JRuby thing
52
55
  * @return pretty much nil
53
56
  */
54
- public IRubyObject rewind( ThreadContext context );
57
+ public IRubyObject rewind(ThreadContext context);
55
58
 
56
59
  /**
57
60
  * Close the input. Exposed only to the Java side because the Rack spec says
@@ -0,0 +1,52 @@
1
+ package org.jruby.jubilee;
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.runtime.ObjectAllocator;
9
+ import org.jruby.runtime.ThreadContext;
10
+ import org.jruby.runtime.builtin.IRubyObject;
11
+
12
+ /**
13
+ * A RubyClass that expose a call method, like a proc
14
+ * There must be a class in JRuby for this, but I just couldn't find it.
15
+ */
16
+ public class RubyCallable extends RubyObject {
17
+ private Callable callable;
18
+
19
+ public static RubyClass createClallableClass(final Ruby runtime) {
20
+ RubyModule jubilee = runtime.getOrCreateModule("Jubilee");
21
+ RubyClass klazz = jubilee.defineClassUnder("Callable", runtime.getObject(), new ObjectAllocator() {
22
+ @Override
23
+ public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
24
+ return new RubyCallable(ruby, rubyClass);
25
+ }
26
+ });
27
+ klazz.defineAnnotatedMethods(RubyCallable.class);
28
+ return klazz;
29
+ }
30
+
31
+ public RubyCallable(Ruby ruby, RubyClass rubyClass) {
32
+ super(ruby, rubyClass);
33
+ }
34
+
35
+ public RubyCallable(Ruby ruby, RubyClass rubyClass, Callable callable) {
36
+ super(ruby, rubyClass);
37
+ this.callable = callable;
38
+ }
39
+
40
+ @JRubyMethod
41
+ public IRubyObject call(ThreadContext context) {
42
+ this.callable.call();
43
+ return context.runtime.getNil();
44
+ }
45
+
46
+ public static abstract class Callable {
47
+ public void call() {
48
+ }
49
+
50
+ ;
51
+ }
52
+ }
@@ -0,0 +1,89 @@
1
+ package org.jruby.jubilee;
2
+
3
+ import io.netty.channel.Channel;
4
+ import org.jruby.Ruby;
5
+ import org.jruby.RubyClass;
6
+ import org.jruby.RubyModule;
7
+ import org.jruby.RubyObject;
8
+ import org.jruby.anno.JRubyClass;
9
+ import org.jruby.anno.JRubyMethod;
10
+ import org.jruby.runtime.ObjectAllocator;
11
+ import org.jruby.runtime.ThreadContext;
12
+ import org.jruby.runtime.builtin.IRubyObject;
13
+
14
+ /**
15
+ * Created by isaiah on 25/12/2013.
16
+ */
17
+ @JRubyClass(name = "Channel")
18
+ public class RubyChannel extends RubyObject {
19
+ private Channel chan;
20
+
21
+ public static RubyClass createChannelClass(final Ruby runtime) {
22
+ RubyModule vertxModule = runtime.getOrCreateModule("Jubilee");
23
+ RubyClass klazz = vertxModule.defineClassUnder("Channel", runtime.getObject(), new ObjectAllocator() {
24
+ @Override
25
+ public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
26
+ return new RubyChannel(ruby, rubyClass);
27
+ }
28
+ });
29
+ klazz.defineAnnotatedMethods(RubyChannel.class);
30
+ return klazz;
31
+ }
32
+
33
+ public RubyChannel(Ruby ruby, RubyClass rubyClass) {
34
+ super(ruby, rubyClass);
35
+ }
36
+
37
+ @JRubyMethod
38
+ public IRubyObject read(ThreadContext context) throws InterruptedException {
39
+ return context.runtime.getNil();
40
+ }
41
+
42
+ @JRubyMethod
43
+ public IRubyObject write(ThreadContext context) {
44
+ return context.runtime.getNil();
45
+
46
+ }
47
+
48
+ @JRubyMethod
49
+ public IRubyObject readNonBlock(ThreadContext context) {
50
+
51
+ return context.runtime.getNil();
52
+ }
53
+
54
+ @JRubyMethod
55
+ public IRubyObject writeNonBlock(ThreadContext context) {
56
+
57
+ return context.runtime.getNil();
58
+ }
59
+
60
+ @JRubyMethod
61
+ public IRubyObject flush(ThreadContext context) {
62
+
63
+ return context.runtime.getNil();
64
+ }
65
+
66
+ @JRubyMethod
67
+ public IRubyObject close(ThreadContext context) {
68
+
69
+ return context.runtime.getNil();
70
+ }
71
+
72
+ @JRubyMethod
73
+ public IRubyObject closeRead(ThreadContext context) {
74
+
75
+ return context.runtime.getNil();
76
+ }
77
+
78
+ @JRubyMethod
79
+ public IRubyObject closeWrite(ThreadContext context) {
80
+
81
+ return context.runtime.getNil();
82
+ }
83
+
84
+ @JRubyMethod(name = "closed?")
85
+ public IRubyObject isClosed(ThreadContext context) {
86
+
87
+ return context.runtime.getNil();
88
+ }
89
+ }
@@ -6,6 +6,8 @@ import org.jruby.anno.JRubyMethod;
6
6
  import org.jruby.runtime.ObjectAllocator;
7
7
  import org.jruby.runtime.ThreadContext;
8
8
  import org.jruby.runtime.builtin.IRubyObject;
9
+ import org.vertx.java.core.http.HttpServer;
10
+ import org.vertx.java.core.http.HttpServerRequest;
9
11
  import org.vertx.java.core.http.HttpServerResponse;
10
12
 
11
13
  import java.util.Arrays;
@@ -15,74 +17,84 @@ import java.util.Arrays;
15
17
  */
16
18
  @JRubyClass(name = "HttpServerResponse")
17
19
  public class RubyHttpServerResponse extends RubyObject {
18
- private HttpServerResponse resp;
19
- private String lineSeparator;
20
+ private HttpServerResponse resp;
21
+ private HttpServerRequest req;
22
+ private String lineSeparator;
20
23
 
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
- }
24
+ public static RubyClass createHttpServerResponseClass(final Ruby runtime) {
25
+ RubyModule mJubilee = runtime.getOrCreateModule("Jubilee");
26
+ RubyClass klazz = mJubilee.defineClassUnder("HttpServerResponse", runtime.getObject(), new ObjectAllocator() {
27
+ @Override
28
+ public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
29
+ return new RubyHttpServerResponse(ruby, rubyClass);
30
+ }
31
+ });
32
+ klazz.defineAnnotatedMethods(RubyHttpServerResponse.class);
33
+ return klazz;
34
+ }
32
35
 
33
- public RubyHttpServerResponse(Ruby ruby, RubyClass rubyClass) {
34
- super(ruby, rubyClass);
35
- }
36
+ public RubyHttpServerResponse(Ruby ruby, RubyClass rubyClass) {
37
+ super(ruby, rubyClass);
38
+ }
36
39
 
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
- }
40
+ public RubyHttpServerResponse(Ruby ruby, RubyClass rubyClass, HttpServerRequest request) {
41
+ super(ruby, rubyClass);
42
+ this.resp = request.response();
43
+ this.req = request;
44
+ this.lineSeparator = System.getProperty("line.separator");
45
+ }
42
46
 
43
- @JRubyMethod
44
- public IRubyObject write(ThreadContext context, IRubyObject string) {
45
- this.resp.write(string.asJavaString());
46
- return context.runtime.getNil();
47
- }
47
+ @JRubyMethod
48
+ public IRubyObject write(ThreadContext context, IRubyObject string) {
49
+ this.resp.write(string.asJavaString());
50
+ return context.runtime.getNil();
51
+ }
48
52
 
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
- }
53
+ @JRubyMethod(name = "status_code=")
54
+ public IRubyObject setStatusCode(ThreadContext context, IRubyObject statusCode) {
55
+ this.resp.setStatusCode(RubyNumeric.num2int(statusCode));
56
+ return context.runtime.getNil();
57
+ }
54
58
 
55
- @JRubyMethod(name = "chunked=")
56
- public IRubyObject setChunked(ThreadContext context, IRubyObject chunked) {
57
- this.resp.setChunked(chunked.isTrue());
58
- return context.runtime.getNil();
59
- }
59
+ @JRubyMethod(name = "chunked=")
60
+ public IRubyObject setChunked(ThreadContext context, IRubyObject chunked) {
61
+ this.resp.setChunked(chunked.isTrue());
62
+ return context.runtime.getNil();
63
+ }
60
64
 
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
- }
65
+ @JRubyMethod(name = "put_header")
66
+ public IRubyObject putHeader(ThreadContext context, IRubyObject key, IRubyObject val) {
67
+ String cookie = val.asJavaString();
68
+ if (cookie.indexOf(this.lineSeparator) != -1)
69
+ this.resp.putHeader(key.asJavaString(),
70
+ Arrays.asList(val.asJavaString().split(this.lineSeparator)));
71
+ else this.resp.putHeader(key.asJavaString(), val.asJavaString());
72
+ return context.runtime.getNil();
73
+ }
70
74
 
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
- }
75
+ @JRubyMethod(name = "send_file")
76
+ public IRubyObject sendFile(ThreadContext context, IRubyObject filePath) {
77
+ this.resp.sendFile(filePath.asJavaString());
78
+ return context.runtime.getNil();
79
+ }
76
80
 
77
- @JRubyMethod
78
- public IRubyObject end(ThreadContext context) {
79
- this.resp.end();
80
- return context.runtime.getNil();
81
- }
81
+ @JRubyMethod
82
+ public IRubyObject end(ThreadContext context) {
83
+ this.resp.end();
84
+ return context.runtime.getNil();
85
+ }
82
86
 
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
- }
87
+ @JRubyMethod(name = "put_default_headers")
88
+ public IRubyObject putDefaultHeaders(ThreadContext context) {
89
+ this.resp.putHeader("Server", Const.JUBILEE_VERSION);
90
+ return context.runtime.getNil();
91
+ }
92
+
93
+ //TODO(isaiah) At the moment Vertx doesn't support hijack the response socket,
94
+ // between request.response() and request.netSocket() only one can be invoked.
95
+ @JRubyMethod
96
+ public IRubyObject net_socket(ThreadContext context) {
97
+ RubyClass netSocketClass = (RubyClass) context.runtime.getClassFromPath("Jubilee::NetSocket");
98
+ return new RubyNetSocket(context.runtime, netSocketClass, this.req.netSocket());
99
+ }
88
100
  }
@@ -0,0 +1,169 @@
1
+ package org.jruby.jubilee;
2
+
3
+ import io.netty.buffer.ByteBuf;
4
+ import io.netty.buffer.Unpooled;
5
+ import org.jruby.*;
6
+ import org.jruby.anno.JRubyClass;
7
+ import org.jruby.anno.JRubyMethod;
8
+ import org.jruby.runtime.ObjectAllocator;
9
+ import org.jruby.runtime.ThreadContext;
10
+ import org.jruby.runtime.builtin.IRubyObject;
11
+ import org.jruby.util.ByteList;
12
+ import org.vertx.java.core.Handler;
13
+ import org.vertx.java.core.VoidHandler;
14
+ import org.vertx.java.core.buffer.Buffer;
15
+ import org.vertx.java.core.net.NetSocket;
16
+ import org.vertx.java.core.streams.WriteStream;
17
+
18
+ import java.util.concurrent.atomic.AtomicBoolean;
19
+
20
+ /**
21
+ * This class create a ruby IO interface by wrapping a Vertx NetSocket object.
22
+ * <p/>
23
+ * Not threadsafe.
24
+ */
25
+ @JRubyClass(name="NetSocket")
26
+ public class RubyNetSocket extends RubyObject {
27
+ private NetSocket sock;
28
+ private ByteBuf buf;
29
+ private AtomicBoolean eof;
30
+ private boolean readClosed = false;
31
+ private boolean writeClosed = false;
32
+ private boolean closed = false;
33
+
34
+ private final static int BUFSIZE = 4096 * 2;
35
+
36
+ public static RubyClass createNetSocketClass(final Ruby runtime) {
37
+ RubyModule jubilee = runtime.getOrCreateModule("Jubilee");
38
+ RubyClass klazz = jubilee.defineClassUnder("NetSocket", runtime.getObject(), new ObjectAllocator() {
39
+ @Override
40
+ public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
41
+ return new RubyNetSocket(ruby, rubyClass);
42
+ }
43
+ });
44
+ klazz.defineAnnotatedMethods(RubyNetSocket.class);
45
+ return klazz;
46
+ }
47
+
48
+ public RubyNetSocket(Ruby ruby, RubyClass rubyClass) {
49
+ super(ruby, rubyClass);
50
+ }
51
+
52
+ public RubyNetSocket(Ruby ruby, RubyClass rubyClass, NetSocket socket) {
53
+ super(ruby, rubyClass);
54
+ this.sock = socket;
55
+ this.buf = Unpooled.buffer(BUFSIZE);
56
+ this.eof = new AtomicBoolean(false);
57
+ this.sock.dataHandler(new Handler<Buffer>() {
58
+ @Override
59
+ public void handle(Buffer buffer) {
60
+ if (buf.isWritable(buffer.length()))
61
+ buf.writeBytes(buffer.getByteBuf());
62
+ else sock.pause();
63
+ }
64
+ });
65
+
66
+ this.sock.endHandler(new VoidHandler() {
67
+ @Override
68
+ protected void handle() {
69
+ eof.set(true);
70
+ }
71
+ });
72
+ }
73
+
74
+ /**
75
+ * Both of the calls block
76
+ *
77
+ * @param context
78
+ * @param args
79
+ * @return
80
+ */
81
+ @JRubyMethod(name = {"read", "read_nonblock"}, required = 1, optional = 1)
82
+ public IRubyObject read(ThreadContext context, IRubyObject[] args) {
83
+ if (this.readClosed) throw context.runtime.newIOError("closed stream");
84
+ int length = RubyNumeric.num2int(args[0]);
85
+ byte[] data;
86
+ if (args.length == 1)
87
+ data = new byte[length];
88
+ else data = ((RubyString) args[1]).getBytes();
89
+ if (!(eof.get() || buf.isReadable())) {
90
+ this.buf.clear();
91
+ this.sock.resume();
92
+ }
93
+ waitReadable(this.buf);
94
+ while (!eof.get() && length > 0) {
95
+ int readedLength = Math.min(this.buf.readableBytes(), length);
96
+ this.buf.readBytes(data, this.buf.readerIndex(), readedLength);
97
+ length -= readedLength;
98
+ }
99
+ return context.runtime.newString(new ByteList(data));
100
+ }
101
+
102
+ /**
103
+ * Though required by rack spec to impelement write_nonblock, it's just easier to block both of the calls.
104
+ *
105
+ * @param context the calling threadcontext
106
+ * @param str the string to write to the underline stream
107
+ * @return the length written
108
+ */
109
+ @JRubyMethod(name = {"write", "write_nonblock"}, required = 1)
110
+ public IRubyObject write(ThreadContext context, IRubyObject str) {
111
+ if (this.writeClosed) throw context.runtime.newIOError("closed stream");
112
+ RubyString data;
113
+ if (str instanceof RubyString)
114
+ data = (RubyString) str;
115
+ else
116
+ data = (RubyString) str.callMethod(context, "to_s");
117
+ if (this.sock.writeQueueFull())
118
+ waitWritable(this.sock);
119
+ this.sock.write(data.asJavaString());
120
+ // TODO return the length actually written
121
+ return data.length();
122
+ }
123
+
124
+ @JRubyMethod(name = "close_write")
125
+ public IRubyObject closeWrite(ThreadContext context) {
126
+ this.writeClosed = true;
127
+ return context.runtime.getTrue();
128
+ }
129
+
130
+ @JRubyMethod(name = "closeRead")
131
+ public IRubyObject closeRead(ThreadContext context) {
132
+ this.readClosed = true;
133
+ return context.runtime.getTrue();
134
+ }
135
+
136
+ @JRubyMethod(name = "close")
137
+ public IRubyObject close(ThreadContext context) {
138
+ this.sock.close();
139
+ this.closed = true;
140
+ return context.runtime.getTrue();
141
+ }
142
+
143
+ @JRubyMethod(name = "closed?")
144
+ public IRubyObject isClosed(ThreadContext context) {
145
+ return context.runtime.newBoolean(this.closed);
146
+ }
147
+
148
+ @JRubyMethod(name = "flush")
149
+ public IRubyObject flush(ThreadContext context) {
150
+ return context.runtime.getTrue();
151
+ }
152
+
153
+ private void waitWritable(WriteStream<?> stream) {
154
+ final AtomicBoolean writable = new AtomicBoolean(false);
155
+ stream.drainHandler(new Handler<Void>() {
156
+ @Override
157
+ public void handle(Void empty) {
158
+ writable.set(true);
159
+ }
160
+ });
161
+ while (!writable.get())
162
+ ;
163
+ }
164
+
165
+ private void waitReadable(ByteBuf buf) {
166
+ while (!buf.isReadable())
167
+ ;
168
+ }
169
+ }