package com.xoom.oss.feathercon;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.server.ServerEndpointConfig;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
public class WebSocketEndpointConfiguration {
public final Collection<Class> endpointClasses;
public final Collection<ServerEndpointConfig> serverEndpointConfigs;
private WebSocketEndpointConfiguration(Collection<Class> endpointClasses, Collection<ServerEndpointConfig> serverEndpointConfigs) {
this.endpointClasses = Collections.unmodifiableCollection(endpointClasses);
this.serverEndpointConfigs = Collections.unmodifiableCollection(serverEndpointConfigs);
}
public static class Builder {
private boolean built;
Collection<Class> endpointClasses = new ArrayList<Class>();
Collection<ServerEndpointConfig> serverEndpointConfigs = new ArrayList<ServerEndpointConfig>();
public Builder withEndpointClass(Class endpointClass) {
requireServerEndPointAnnotation(endpointClass);
requireHandlerMethods(endpointClass);
endpointClasses.add(endpointClass);
return this;
}
public Builder withServerEndpointConfig(ServerEndpointConfig serverEndpointConfig) {
serverEndpointConfigs.add(serverEndpointConfig);
return this;
}
public WebSocketEndpointConfiguration build() {
if (built) {
throw new IllegalStateException("This builder can be used to produce one configuration instance. Please create a new builder.");
}
built = true;
return new WebSocketEndpointConfiguration(endpointClasses, serverEndpointConfigs);
}
// file bug: Option-return at EOL should offer to Iterate, like it does for Colelctions
private void requireHandlerMethods(Class endpointClass) {
boolean hasOnOpenAnnotation = false;
boolean hasOnMessageAnnotation = false;
boolean hasOnCloseAnnotation = false;
boolean hasOnErrorAnnotation = false;
Method[] methods = endpointClass.getMethods();
for (Method method : methods) {
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof OnOpen) {
hasOnOpenAnnotation = true;
continue;
}
if (annotation instanceof OnClose) {
hasOnCloseAnnotation = true;
continue;
}
if (annotation instanceof OnMessage) {
hasOnMessageAnnotation = true;
continue;
}
if (annotation instanceof OnError) {
hasOnErrorAnnotation = true;
continue;
}
}
}
if (!(hasOnOpenAnnotation && hasOnMessageAnnotation && hasOnCloseAnnotation && hasOnErrorAnnotation)) {
throw new IllegalArgumentException(String.format("Class %s must have methods annotated with OnOpen, OnClose, OnMessage, and OnError javax.websocket annotations", endpointClass));
}
}
private void requireServerEndPointAnnotation(Class c) {
Annotation annotation = c.getAnnotation(ServerEndpoint.class);
if (annotation == null) {
throw new IllegalArgumentException(String.format("Endpoint class must be annotated with javax.websocket.server.ServerEndpoint"));
}
}
}
}
/*
@ServerEndpoint(value = "/events/")
public class EventSocket {
@OnOpen
public void onWebSocketConnect(Session sess) {
System.out.println("Socket Connected: " + sess);
}
@OnMessage
public void onWebSocketText(String message) {
System.out.println("Received TEXT message: " + message);
}
@OnClose
public void onWebSocketClose(CloseReason reason) {
System.out.println("Socket Closed: " + reason);
}
@OnError
public void onWebSocketError(Throwable cause) {
cause.printStackTrace(System.err);
}
}
*/