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

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 (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
+ }