Skip to content
This repository has been archived by the owner on Feb 6, 2022. It is now read-only.

Commit

Permalink
Moved NIO stuff into abstractions for server and connection.
Browse files Browse the repository at this point in the history
  • Loading branch information
aslakhellesoy committed Feb 7, 2011
1 parent 72ecb6e commit 58b36d5
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 69 deletions.
2 changes: 1 addition & 1 deletion src/main/java/dnode/Callback.java
@@ -1,5 +1,5 @@
package dnode;

public interface Callback {
void call(Object... args) throws RuntimeException;
void call(Object... args) throws RuntimeException;
}
11 changes: 11 additions & 0 deletions src/main/java/dnode/Connection.java
@@ -0,0 +1,11 @@
package dnode;

import java.io.IOException;

public interface Connection {
void send(String data);

String read() throws IOException;

void close() throws IOException;
}
4 changes: 4 additions & 0 deletions src/main/java/dnode/ConnectionHandler.java
@@ -0,0 +1,4 @@
package dnode;

public interface ConnectionHandler {
}
78 changes: 22 additions & 56 deletions src/main/java/dnode/DNode.java
@@ -1,46 +1,41 @@
package dnode;

import com.google.gson.*;
import dnode.nio.NIOServer;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.HashMap;
import java.util.Map;

public class DNode {
private static Charset charset = Charset.forName("UTF-8");
private static CharsetEncoder encoder = charset.newEncoder();
private static CharsetDecoder decoder = charset.newDecoder();

private final DNodeObject instance;
private SocketChannel sc;
private Map<String, Callback> callbacks = new HashMap<String, Callback>();
private ServerSocketChannel ssc;
private Server server;

public DNode(Object instance) {
this.instance = new DNodeObject(instance);
}

public void listen(int port) throws IOException {
sc = connect(port);
send(methods());
String clientMethods = read();
String invocation = read();
public void shutdown() throws IOException {
this.server.shutdown();
}

public void listen(Server server) throws IOException {
this.server = server;
server.listen(this);
}

public void handle(final Connection connection) {
try {
connection.send(methods());
String clientMethods = connection.read();
String invocation = connection.read();
invoke(invocation, new Callback() {
public void call(Object... args) {
JsonArray jsonArgs = transform(args);
send(responseString(0, jsonArgs, new JsonObject(), new JsonArray()));
connection.send(responseString(0, jsonArgs, new JsonObject(), new JsonArray()));
try {
shutdown();
connection.close();
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
Expand All @@ -52,6 +47,10 @@ public void call(Object... args) {
}
}

public void listen(int port) throws IOException {
listen(new NIOServer(port));
}

private void invoke(String invocation, Callback callback) throws Throwable {
JsonObject invocationJson = (JsonObject) new JsonParser().parse(invocation);
instance.invoke(invocationJson, callback);
Expand All @@ -77,43 +76,10 @@ private JsonElement toJson(Object o) {
return e;
}

private void shutdown() throws IOException {
ssc.close();
sc.close();
}

private SocketChannel connect(int port) throws IOException {
ssc = ServerSocketChannel.open();
InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), port);
ssc.socket().bind(isa);
emit("ready");
return ssc.accept();
}

private void emit(String event, Object... args) {
public void emit(String event, Object... args) {
callbacks.get(event).call(args);
}

private String read() throws IOException {
ByteBuffer bb = ByteBuffer.allocate(1024);
sc.read(bb);
bb.flip();
CharBuffer response = decoder.decode(bb);
return response.toString();
}

private void send(String data) {
try {
sc.write(encoder.encode(CharBuffer.wrap(data + "\r\n")));
} catch (IOException e) {
try {
sc.close();
} catch (IOException e1) {
e1.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}

private String methods() {
JsonArray arguments = new JsonArray();
arguments.add(instance.getSignature());
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/dnode/DNodeObject.java
Expand Up @@ -19,7 +19,7 @@ public DNodeObject(Object instance) {
public JsonElement getSignature() {
Class<?> klass = this.instance.getClass();
JsonObject signature = new JsonObject();
for(Method m : klass.getDeclaredMethods()) {
for (Method m : klass.getDeclaredMethods()) {
signature.addProperty(m.getName(), "[Function]");
}
return signature;
Expand All @@ -29,10 +29,10 @@ public JsonElement getCallbacks() {
Class<?> klass = this.instance.getClass();
JsonObject callbacks = new JsonObject();
int index = 0;
for(Method m : klass.getDeclaredMethods()) {
for (Method m : klass.getDeclaredMethods()) {
Class<?>[] parameterTypes = m.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
if(Callback.class.isAssignableFrom(parameterType)) {
if (Callback.class.isAssignableFrom(parameterType)) {
JsonArray path = new JsonArray();
path.add(new JsonPrimitive("0"));
path.add(new JsonPrimitive(m.getName()));
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/dnode/Server.java
@@ -0,0 +1,9 @@
package dnode;

import java.io.IOException;

public interface Server {
void listen(DNode dnode) throws IOException;

void shutdown() throws IOException;
}
47 changes: 47 additions & 0 deletions src/main/java/dnode/nio/NIOConnection.java
@@ -0,0 +1,47 @@
package dnode.nio;

import dnode.Connection;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;

public class NIOConnection implements Connection {
private static Charset charset = Charset.forName("UTF-8");
private static CharsetEncoder encoder = charset.newEncoder();
private static CharsetDecoder decoder = charset.newDecoder();

private final SocketChannel channel;

public NIOConnection(SocketChannel channel) {
this.channel = channel;
}

public void send(String data) {
try {
channel.write(encoder.encode(CharBuffer.wrap(data + "\r\n")));
} catch (IOException e) {
try {
close();
} catch (IOException e1) {
e1.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}

public String read() throws IOException {
ByteBuffer bb = ByteBuffer.allocate(1024);
channel.read(bb);
bb.flip();
CharBuffer response = decoder.decode(bb);
return response.toString();
}

public void close() throws IOException {
channel.close();
}
}
36 changes: 36 additions & 0 deletions src/main/java/dnode/nio/NIOServer.java
@@ -0,0 +1,36 @@
package dnode.nio;

import dnode.Connection;
import dnode.DNode;
import dnode.Server;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class NIOServer implements Server {
private ServerSocketChannel ssc;
private final int port;

public NIOServer(int port) {
this.port = port;
}

public void listen(DNode dnode) throws IOException {
ssc = ServerSocketChannel.open();
InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), port);
ssc.socket().bind(isa);
dnode.emit("ready");
SocketChannel channel = ssc.accept();

Connection conn = new NIOConnection(channel);
dnode.handle(conn);
}

public void shutdown() throws IOException {
ssc.close();
}

}
5 changes: 3 additions & 2 deletions src/test/java/dnode/DNodeObjectTest.java
Expand Up @@ -7,10 +7,11 @@
public class DNodeObjectTest {
public static class Cat {
public void say(Callback callback) {

}

public void meow(Callback callback) {

}
}

Expand Down
24 changes: 17 additions & 7 deletions src/test/java/dnode/DNodeTest.java
@@ -1,13 +1,18 @@
package dnode;

import junit.framework.AssertionFailedError;
import org.junit.After;
import org.junit.Test;

import java.io.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import static org.junit.Assert.assertEquals;

public class DNodeTest {
private DNode dNode;

public static class Mooer {
private final int moo;

Expand All @@ -20,29 +25,34 @@ public void moo(Callback cb) {
}

public void boo(Callback cb) {
cb.call(moo*10);
cb.call(moo * 10);
}
}

@After
public void shutdownServer() throws IOException {
dNode.shutdown();
}

private final Object signals = new Object();

@Test
public void shouldTalk() throws IOException, InterruptedException {
final DNode dNode = new DNode(new Mooer(100));
dNode = new DNode(new Mooer(100));
runServer(dNode);
assertEquals("100\n", runClient("moo"));
}

@Test
public void shouldUseDataInInstance() throws IOException, InterruptedException {
final DNode dNode = new DNode(new Mooer(200));
dNode = new DNode(new Mooer(200));
runServer(dNode);
assertEquals("200\n", runClient("moo"));
}

@Test
public void shouldCallRightMethod() throws IOException, InterruptedException {
final DNode dNode = new DNode(new Mooer(300));
dNode = new DNode(new Mooer(300));
runServer(dNode);
assertEquals("3000\n", runClient("boo"));
}
Expand Down Expand Up @@ -82,8 +92,8 @@ private String runClient(String method) throws IOException, InterruptedException
result.append(line).append("\n");
}
int exit = client.waitFor();
if(exit != 0)
throw new AssertionFailedError("Exit value from external process was " + exit +
if (exit != 0)
throw new AssertionFailedError("Exit value from external process was " + exit +
" (with stdout/stderr: " + result + ")");
return result.toString();
}
Expand Down

0 comments on commit 58b36d5

Please sign in to comment.