package com.github.aesteve.vertx.nubes.reflections.visitors; import com.github.aesteve.vertx.nubes.Config; import com.github.aesteve.vertx.nubes.annotations.sockjs.OnClose; import com.github.aesteve.vertx.nubes.annotations.sockjs.OnMessage; import com.github.aesteve.vertx.nubes.annotations.sockjs.OnOpen; import com.github.aesteve.vertx.nubes.annotations.sockjs.SockJS; import io.vertx.core.Vertx; import io.vertx.core.VertxException; import io.vertx.core.buffer.Buffer; import io.vertx.core.eventbus.EventBus; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.sockjs.SockJSHandler; import io.vertx.ext.web.handler.sockjs.SockJSSocket; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; public class SockJSVisitor<T> extends BaseVisitor<T> { private static final Logger LOG = LoggerFactory.getLogger(SockJSVisitor.class); private SockJSHandler sockJSHandler; private SockJS annot; private final List<Method> openHandlers; private final List<Method> messageHandlers; private final List<Method> closeHandlers; public SockJSVisitor(Class<T> clazz, Config config, Router router) { super(clazz, config, router); annot = clazz.getAnnotation(SockJS.class); path = annot.value(); openHandlers = new ArrayList<>(); messageHandlers = new ArrayList<>(); closeHandlers = new ArrayList<>(); } public void visit() { sockJSHandler = SockJSHandler.create(config.getVertx(), config.getSockJSOptions()); try { instance = clazz.newInstance(); injectServices(); } catch (Exception e) { throw new VertxException("Could not instanciate socket controller : " + clazz.getName(), e); } createHandlers(); sockJSHandler.socketHandler(ws -> { openHandlers.forEach(handler -> tryToInvoke(instance, handler, ws, null)); ws.handler(buff -> messageHandlers.forEach(messageHandler -> tryToInvoke(instance, messageHandler, ws, buff))); ws.endHandler(voidz -> closeHandlers.forEach(closeHandler -> tryToInvoke(instance, closeHandler, ws, null))); }); normalizePath(); router.route(path).handler(sockJSHandler); } private void createHandlers() { for (Method method : clazz.getMethods()) { OnOpen openAnnot = method.getAnnotation(OnOpen.class); OnClose closeAnnot = method.getAnnotation(OnClose.class); OnMessage messageAnnot = method.getAnnotation(OnMessage.class); if (openAnnot != null) { openHandlers.add(method); } if (closeAnnot != null) { closeHandlers.add(method); } if (messageAnnot != null) { messageHandlers.add(method); } } } private void tryToInvoke(Object instance, Method method, SockJSSocket socket, Buffer msg) { try { method.invoke(instance, getParamValues(method, socket, msg)); } catch (Exception e) { LOG.error("Error while handling websocket", e); socket.close(); } } private Object[] getParamValues(Method method, SockJSSocket socket, Buffer msg) { final Vertx vertx = config.getVertx(); List<Object> paramInstances = new ArrayList<>(); for (Class<?> parameterClass : method.getParameterTypes()) { if (parameterClass.equals(SockJSSocket.class)) { paramInstances.add(socket); } else if (Buffer.class.isAssignableFrom(parameterClass)) { paramInstances.add(msg); } else if (parameterClass.equals(EventBus.class)) { paramInstances.add(vertx.eventBus()); } else if (parameterClass.equals(Vertx.class)) { paramInstances.add(vertx); } } return paramInstances.toArray(); } }