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

Commit

Permalink
2 way communication working
Browse files Browse the repository at this point in the history
  • Loading branch information
aslakhellesoy committed Feb 13, 2011
1 parent fce149c commit 02d5da6
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 58 deletions.
5 changes: 5 additions & 0 deletions src/main/java/dnode/ClientHandler.java
@@ -0,0 +1,5 @@
package dnode;

public interface ClientHandler<T> {
void onConnect(T client);
}
1 change: 0 additions & 1 deletion src/main/java/dnode/Connection.java
Expand Up @@ -4,6 +4,5 @@

public interface Connection {
void close();

void write(JsonElement data);
}
64 changes: 56 additions & 8 deletions src/main/java/dnode/DNode.java
Expand Up @@ -3,15 +3,22 @@
import com.google.gson.*;

import java.io.IOException;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

public class DNode {
public class DNode<T> {
private final List<Connection> connections = new ArrayList<Connection>();
private final DNodeObject instance;
private List<Connection> connections = new ArrayList<Connection>();
private final ClientHandler<T> clientHandler;

public DNode(Object instance) {
this(instance, null);
}

public DNode(Object instance, ClientHandler<T> clientHandler) {
this.instance = new DNodeObject(instance);
this.clientHandler = clientHandler;
}

public void listen(Server server) throws IOException {
Expand All @@ -24,15 +31,15 @@ private JsonElement methods() {
return response("methods", arguments, instance.getCallbacks(), new JsonArray());
}

private JsonElement response(String method, JsonArray arguments, JsonElement callbacks, JsonArray links) {
private JsonElement response(String method, JsonArray arguments, JsonObject callbacks, JsonArray links) {
return response(new JsonPrimitive(method), arguments, callbacks, links);
}

public JsonElement response(int method, JsonArray arguments, JsonElement callbacks, JsonArray links) {
public JsonElement response(int method, JsonArray arguments, JsonObject callbacks, JsonArray links) {
return response(new JsonPrimitive(method), arguments, callbacks, links);
}

private JsonElement response(JsonElement method, JsonArray arguments, JsonElement callbacks, JsonArray links) {
private JsonElement response(JsonElement method, JsonArray arguments, JsonObject callbacks, JsonArray links) {
JsonObject response = new JsonObject();
response.add("method", method);
response.add("arguments", arguments);
Expand All @@ -44,20 +51,61 @@ private JsonElement response(JsonElement method, JsonArray arguments, JsonElemen
public void onOpen(Connection connection) {
connections.add(connection);
connection.write(methods());
if(clientHandler != null) {
T clientProxy = createClientProxy(connection);
clientHandler.onConnect(clientProxy);
}
}

private T createClientProxy(final Connection connection) {
ParameterizedType type = (ParameterizedType) clientHandler.getClass().getGenericInterfaces()[0];
Class clientType = (Class) type.getActualTypeArguments()[0];
T clientProxy = (T) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{clientType}, new InvocationHandler() {
@Override
public Object invoke(Object target, Method method, Object[] args) throws Throwable {
JsonArray arguments = transform(args);
JsonObject callbacks = new JsonObject();
JsonArray links = new JsonArray();
connection.write(response(method.getName(), arguments, callbacks, links));
return null;
}
});
return clientProxy;
}

public void onMessage(Connection connection, String msg) {
JsonObject json = new JsonParser().parse(msg).getAsJsonObject();
JsonPrimitive method = json.getAsJsonPrimitive("method");
if (method.isString() && method.getAsString().equals("methods")) {
handleMethods(json.getAsJsonArray("arguments").get(0).getAsJsonObject());
defineClientMethods(json.getAsJsonArray("arguments").get(0).getAsJsonObject());
} else {
instance.invoke(this, json, connection);
}
}

private void handleMethods(JsonObject methods) {
// System.out.println("methods = " + methods);
public JsonArray transform(Object[] args) {
JsonArray result = new JsonArray();
for (Object arg : args) {
result.add(toJson(arg));
}
return result;
}

private JsonElement toJson(Object o) {
JsonElement e;
if (o instanceof String) {
e = new JsonPrimitive((String) o);
} else if (o instanceof Number) {
e = new JsonPrimitive((Number) o);
} else {
throw new RuntimeException("Unsupported type: " + o.getClass());
}
return e;
}

private void defineClientMethods(JsonObject methods) {
// TODO: Verify that the client's reported methods have the same
// signatures as our client proxy, and fail fast if it doesn't.
}

public void closeAllConnections() {
Expand Down
23 changes: 2 additions & 21 deletions src/main/java/dnode/DNodeObject.java
Expand Up @@ -26,7 +26,7 @@ public JsonElement getSignature() {
return signature;
}

public JsonElement getCallbacks() {
public JsonObject getCallbacks() {
Class<?> klass = this.instance.getClass();
JsonObject callbacks = new JsonObject();
int index = 0;
Expand Down Expand Up @@ -54,7 +54,7 @@ public void invoke(final DNode dNode, JsonObject invocation, final Connection co
Callback cb = new Callback() {
@Override
public void call(Object... args) throws RuntimeException {
JsonArray jsonArgs = transform(args);
JsonArray jsonArgs = dNode.transform(args);
connection.write(dNode.response(callbackId, jsonArgs, new JsonObject(), new JsonArray()));
}
};
Expand All @@ -67,23 +67,4 @@ public void call(Object... args) throws RuntimeException {
}
}

private JsonArray transform(Object[] args) {
JsonArray result = new JsonArray();
for (Object arg : args) {
result.add(toJson(arg));
}
return result;
}

private JsonElement toJson(Object o) {
JsonElement e;
if (o instanceof String) {
e = new JsonPrimitive((String) o);
} else if (o instanceof Number) {
e = new JsonPrimitive((Number) o);
} else {
throw new RuntimeException("Unsupported type: " + o.getClass());
}
return e;
}
}
1 change: 0 additions & 1 deletion src/main/java/dnode/Server.java
Expand Up @@ -4,6 +4,5 @@

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

void shutdown() throws IOException;
}
4 changes: 3 additions & 1 deletion src/main/java/dnode/netty/NettyServer.java
Expand Up @@ -32,6 +32,8 @@ public void listen(DNode dnode) throws IOException {

@Override
public void shutdown() throws IOException {
channel.close();
if(channel != null) {
channel.close();
}
}
}
29 changes: 23 additions & 6 deletions src/test/java/dnode/DNodeTest.java
Expand Up @@ -55,19 +55,36 @@ public void shouldUseDataInInstance() throws IOException, InterruptedException {
assertEquals("200\n", runClient("moo"));
}

private void createDnode(int moo) {
Mooer instance = new Mooer(moo);
dNode = new DNode(instance);
instance.dNode = dNode;
}

@Test
public void shouldCallRightMethod() throws IOException, InterruptedException {
createDnode(300);
dNode.listen(server);
assertEquals("3000\n", runClient("boo"));
}

public static interface SomeClient {
void hello();
}

@Test
public void shouldBeAbleToCallClient() {
Mooer mooer = new Mooer(345);
dNode = new DNode<SomeClient>(mooer, new ClientHandler<SomeClient>() {
@Override
public void onConnect(SomeClient client) {
System.out.println("client = " + client);
client.hello();
}
});
}


private void createDnode(int moo) {
Mooer instance = new Mooer(moo);
dNode = new DNode(instance);
instance.dNode = dNode;
}

private String runClient(String method) throws IOException, InterruptedException {
String node = System.getProperty("node", "/usr/local/bin/node");
String clientScript = System.getProperty("client", "client.js");
Expand Down
16 changes: 13 additions & 3 deletions src/test/java/dnode/webbit/DNodeExample.java
@@ -1,6 +1,7 @@
package dnode.webbit;

import dnode.Callback;
import dnode.ClientHandler;
import dnode.DNode;
import webbit.WebServer;
import webbit.handler.EmbeddedResourceHandler;
Expand All @@ -12,14 +13,23 @@

public class DNodeExample {
public static class Cat {
public void cat(Callback cb) {
cb.call("GROWL");
public void howAreYou(Callback cb) {
cb.call("I am fine");
}
}

public interface MyClient {
void greet(String what);
}

public static void main(String[] args) throws IOException {
WebServer server = new NettyWebServer(6061);
new DNode(new Cat()).listen(new WebbitServer(server));
new DNode<MyClient>(new Cat(), new ClientHandler<MyClient>() {
@Override
public void onConnect(MyClient client) {
client.greet("How are you?");
}
}).listen(new WebbitServer(server));
server.add("/.*", new EmbeddedResourceHandler("dnode/js", newFixedThreadPool(4)));
server.start();
}
Expand Down
36 changes: 19 additions & 17 deletions src/test/resources/dnode/js/index.html
@@ -1,23 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<script src="/dnode.js"></script>
<script>
<head>
<style>span {font-weight: bold;}</style>
<script src="/dnode.js"></script>
<script>
window.onload = function () {
var Client = function() {
this.say = function(what) {
console.log("say", what);
};
}
DNode(Client).connect(function (remote) {
remote.cat(function (says) {
document.getElementById('says').innerHTML = says;
});
var Client = function() {
this.greet = function(greeting) {
document.getElementById('greeting').innerHTML = greeting;
};
}
DNode(Client).connect(function(cat) {
cat.howAreYou(function(catReply) {
document.getElementById('catReply').innerHTML = catReply;
});
});
};
</script>
</head>
<body>
The cat says <span id="says">?</span>.
</body>
</script>
</head>
<body>
<div>The cat says <span id="catReply">?</span></div>
<div>The server pushed <span id="greeting">?</span></div>
</body>
</html>

0 comments on commit 02d5da6

Please sign in to comment.