
com.github.gkutiel.flip.web.Remote Maven / Gradle / Ivy
package com.github.gkutiel.flip.web;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketServlet;
import ch.lambdaj.Lambda;
import com.github.gkutiel.flip.AFlip;
import com.github.gkutiel.flip.AFlip.Hook;
import com.github.gkutiel.flip.utils.Utils;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.gson.Gson;
public class Remote extends ServletHolder {
public interface Doorman {
boolean allow(Req req, String key);
void bye(Req req, String key);
void hi(Req req, String key, T remote);
}
@SuppressWarnings("unused")
private static class Cb {
final String name;
final Object[] args;
public Cb(final String name, final Object[] args) {
this.name = name;
this.args = args;
}
}
private class FlipSocket implements WebSocket {
private T remote;
private Connection con;
private String key;
private Req req;
private Doorman doorman;
@SuppressWarnings("unchecked")
public FlipSocket(final Req req, final String key, final Doorman doorman) {
this.req = req;
this.key = key;
this.doorman = doorman;
remote = (T) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class>[] { c }, new InvocationHandler() {
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
if (method.getDeclaringClass().equals(c)) {
con.sendMessage(GSON.toJson(new Cb(method.getName(), args)));
return null;
}
return method.invoke(FlipSocket.this, args);
}
});
}
@Override
public void onClose(final int closeCode, final String message) {
remotes.remove(key, remote);
doorman.bye(req, key);
}
@Override
public void onOpen(final Connection con) {
this.con = con;
remotes.put(key, remote);
doorman.hi(req, key, remote);
}
}
private static final String _JS = Utils.Resource.load("_.js");
static {
AFlip.hook(new Hook() {
@Override
public void hook(final AFlip flip) {
flip.bind(new ServletHolder(new HttpServlet() {
@Override
protected void doGet(final HttpServletRequest req, final HttpServletResponse res) throws ServletException, IOException {
final ServletOutputStream out = res.getOutputStream();
out.print(_JS);
out.close();
}
}), "/_.js");
}
});
}
private static final Gson GSON = new Gson();
public static Remote bind(final Class remote, final String path) {
final Remote r = new Remote<>(remote);
AFlip.hook(new Hook() {
@Override
public void hook(final AFlip flip) {
flip.bind(r, path);
}
});
return r;
}
public static Remote bind(final Class remote, final String path, final Doorman doorman) {
final Remote r = new Remote<>(remote, doorman);
AFlip.hook(new Hook() {
@Override
public void hook(final AFlip flip) {
flip.bind(r, path);
}
});
return r;
}
private final Multimap remotes = HashMultimap.create();
private Class c;
private Remote(final Class c) {
this(c, new Doorman() {
@Override
public boolean allow(final Req req, final String key) {
return true;
}
@Override
public void bye(final Req req, final String key) {}
@Override
public void hi(final Req req, final String key, final T remote) {}
});
}
private Remote(final Class remote, final Doorman doorman) {
this.c = remote;
setServlet(new WebSocketServlet() {
@Override
public WebSocket doWebSocketConnect(final HttpServletRequest req, final String key) {
final Req r = HttpUtils.req(req);
if (doorman.allow(r, key)) return new FlipSocket(r, key, doorman);
return null;
}
});
}
public T at() {
return at(".");
}
public T at(final String key) {
return Lambda.forEach(remotes.get(key), c);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy