Permalink
Browse files

2 way communication working

  • Loading branch information...
1 parent fce149c commit 02d5da6378a0014b8f584917f6710542573dc916 @aslakhellesoy committed Feb 13, 2011
@@ -0,0 +1,5 @@
+package dnode;
+
+public interface ClientHandler<T> {
+ void onConnect(T client);
+}
@@ -4,6 +4,5 @@
public interface Connection {
void close();
-
void write(JsonElement data);
}
@@ -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 {
@@ -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);
@@ -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() {
@@ -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;
@@ -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()));
}
};
@@ -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;
- }
}
@@ -4,6 +4,5 @@
public interface Server {
void listen(DNode dnode) throws IOException;
-
void shutdown() throws IOException;
}
@@ -32,6 +32,8 @@ public void listen(DNode dnode) throws IOException {
@Override
public void shutdown() throws IOException {
- channel.close();
+ if(channel != null) {
+ channel.close();
+ }
}
}
@@ -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");
@@ -1,6 +1,7 @@
package dnode.webbit;
import dnode.Callback;
+import dnode.ClientHandler;
import dnode.DNode;
import webbit.WebServer;
import webbit.handler.EmbeddedResourceHandler;
@@ -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();
}
@@ -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.