ameba.container.grizzly.server.http.websocket.WebSocketServerContainer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ameba-container-grizzly Show documentation
Show all versions of ameba-container-grizzly Show documentation
A useful Java framework grizzly container!
package ameba.container.grizzly.server.http.websocket;
import ameba.core.Application;
import ameba.util.ClassUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.glassfish.tyrus.core.DebugContext;
import org.glassfish.tyrus.core.TyrusWebSocketEngine;
import org.glassfish.tyrus.core.Utils;
import org.glassfish.tyrus.core.cluster.ClusterContext;
import org.glassfish.tyrus.core.frame.TyrusFrame;
import org.glassfish.tyrus.core.monitoring.ApplicationEventListener;
import org.glassfish.tyrus.core.monitoring.EndpointEventListener;
import org.glassfish.tyrus.core.monitoring.MessageEventListener;
import org.glassfish.tyrus.ext.monitoring.jmx.SessionAwareApplicationMonitor;
import org.glassfish.tyrus.server.TyrusServerContainer;
import org.glassfish.tyrus.spi.WebSocketEngine;
import javax.inject.Inject;
import javax.websocket.DeploymentException;
import javax.websocket.server.ServerEndpointConfig;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @author icode
*/
public class WebSocketServerContainer extends TyrusServerContainer {
/**
* Maximum size of incoming buffer in bytes.
*
* The value must be {@link java.lang.Integer} or its primitive alternative.
*
* Default value is 4194315, which means that TyrusWebSocketEngine is by default
* capable of processing messages up to 4 MB.
*/
public static final String WEBSOCKET_INCOMING_BUFFER_SIZE = "websocket.incomingBufferSize";
/**
* Maximum number of open sessions per server application.
*
* The value must be positive {@link java.lang.Integer} or its primitive alternative. Negative values
* and zero are ignored.
*
* The number of open sessions per application is not limited by default.
*/
public static final String WEBSOCKET_MAX_SESSIONS_PER_APP = "websocket.maxSessionsPerApp";
/**
* Maximum number of open sessions per unique remote address.
*
* The value must be positive {@link java.lang.Integer} or its primitive alternative. Negative values
* and zero are ignored.
*
* The number of open sessions per remote address is not limited by default.
*/
public static final String WEBSOCKET_MAX_SESSIONS_PER_REMOTE_ADDR = "websocket.maxSessionsPerRemoteAddr";
/**
* Property used for configuring the type of tracing supported by the server.
*
* The value is expected to be string value of {@link org.glassfish.tyrus.core.DebugContext.TracingType}.
*
* The default value is {@link org.glassfish.tyrus.core.DebugContext.TracingType#OFF}.
*/
public static final String WEBSOCKET_TRACING_TYPE = "websocket.tracingType";
/**
* Property used for configuring tracing threshold.
*
* The value is expected to be string value of {@link org.glassfish.tyrus.core.DebugContext.TracingThreshold}.
*
* The default value is {@link org.glassfish.tyrus.core.DebugContext.TracingThreshold#SUMMARY}.
*/
public static final String WEBSOCKET_TRACING_THRESHOLD = "websocket.tracingThreshold";
/**
* Parallel broadcast support.
*
* {@link org.glassfish.tyrus.core.TyrusSession#broadcast(String)} and {@link org.glassfish.tyrus.core.TyrusSession#broadcast(java.nio.ByteBuffer)}
* operations are by default executed in parallel. The parallel execution of broadcast can be disabled by setting
* this server property to {@code false}.
*
* Expected value is {@code true} or {@code false} and the default value is {@code true}.
*
* @see org.glassfish.tyrus.core.TyrusSession#broadcast(String) .
* @see org.glassfish.tyrus.core.TyrusSession#broadcast(java.nio.ByteBuffer) .
*/
public static final String WEBSOCKET_PARALLEL_BROADCAST_ENABLED = "websocket.parallelBroadcastEnabled";
/**
* ClusterContext registration property.
*
* ClusterContext is registered to the Server container via properties passed to {@link org.glassfish.tyrus.spi.ServerContainerFactory#createServerContainer(java.util.Map)}.
*/
public static final String WEBSOCKET_CLUSTER_CONTEXT = "websocket.cluster.ClusterContext";
/**
* A key used for registering a application event listener implementation.
*
* For monitoring in Grizzly server an instance should be passed to the server in server properties:
*
* serverProperties.put(ApplicationEventListener.APPLICATION_EVENT_LISTENER, new MyApplicationEventListener());
*
* For use in servlet container the class name should be passed as a context parameter in web.xml:
* {@code
*
* org.glassfish.tyrus.core.monitoring.ApplicationEventListener
* com.acme.MyApplicationEventListener
* }
*/
public static final String WEBSOCKET_APPLICATION_EVENT_LISTENER = "websocket.monitoring.ApplicationEventListener";
private Integer incomingBufferSize;
private Integer maxSessionsPerApp;
private Integer maxSessionsPerRemoteAddr;
private Boolean parallelBroadcastEnabled;
private DebugContext.TracingType tracingType;
private DebugContext.TracingThreshold tracingThreshold;
private ClusterContext clusterContext;
private ApplicationEventListener applicationEventListener;
private WebSocketEngine engine;
private int port;
private String contextPath;
@Inject
public WebSocketServerContainer(Application application) {
super((Set>) null);
Map properties = application.getProperties();
final Map localProperties;
// defensive copy
if (properties == null) {
localProperties = Collections.emptyMap();
} else {
localProperties = new HashMap<>(properties);
}
incomingBufferSize = Utils.getProperty(localProperties, WEBSOCKET_INCOMING_BUFFER_SIZE, Integer.class);
maxSessionsPerApp = Utils.getProperty(localProperties, WEBSOCKET_MAX_SESSIONS_PER_APP, Integer.class);
maxSessionsPerRemoteAddr = Utils.getProperty(localProperties, WEBSOCKET_MAX_SESSIONS_PER_REMOTE_ADDR, Integer.class);
parallelBroadcastEnabled = Utils.getProperty(localProperties, WEBSOCKET_PARALLEL_BROADCAST_ENABLED, Boolean.class);
String clusterContextClass = Utils.getProperty(localProperties, WEBSOCKET_CLUSTER_CONTEXT, String.class);
if (StringUtils.isNotBlank(clusterContextClass)) {
clusterContext = ClassUtils.newInstance(clusterContextClass);
}
final String applicationEventListenerClass = Utils.getProperty(localProperties, WEBSOCKET_APPLICATION_EVENT_LISTENER, String.class);
if (StringUtils.isNotBlank(applicationEventListenerClass)) {
applicationEventListener = ClassUtils.newInstance(applicationEventListenerClass);
}
if ("true".equals(localProperties.get("jmx.enabled"))) {
if (applicationEventListener == null) {
applicationEventListener = new SessionAwareApplicationMonitor();
} else {
applicationEventListener = new ApplicationEventListener() {
private ApplicationEventListener jmx = new SessionAwareApplicationMonitor();
private ApplicationEventListener src = ClassUtils.newInstance(applicationEventListenerClass);
@Override
public void onApplicationInitialized(String applicationName) {
try {
src.onApplicationInitialized(applicationName);
} finally {
jmx.onApplicationInitialized(applicationName);
}
}
@Override
public void onApplicationDestroyed() {
try {
src.onApplicationDestroyed();
} finally {
jmx.onApplicationDestroyed();
}
}
@Override
public EndpointEventListener onEndpointRegistered(String endpointPath, Class> endpointClass) {
final EndpointEventListener srcL;
final EndpointEventListener jmxL;
try {
srcL = src.onEndpointRegistered(endpointPath, endpointClass);
} finally {
jmxL = jmx.onEndpointRegistered(endpointPath, endpointClass);
}
return new EndpointEventListener() {
@Override
public MessageEventListener onSessionOpened(final String sessionId) {
final MessageEventListener srcM;
final MessageEventListener jmxM;
try {
srcM = srcL.onSessionOpened(sessionId);
} finally {
jmxM = jmxL.onSessionOpened(sessionId);
}
return new MessageEventListener() {
@Override
public void onFrameSent(TyrusFrame.FrameType frameType, long payloadLength) {
try {
srcM.onFrameSent(frameType, payloadLength);
} finally {
jmxM.onFrameSent(frameType, payloadLength);
}
}
@Override
public void onFrameReceived(TyrusFrame.FrameType frameType, long payloadLength) {
try {
srcM.onFrameReceived(frameType, payloadLength);
} finally {
jmxM.onFrameReceived(frameType, payloadLength);
}
}
};
}
@Override
public void onSessionClosed(String sessionId) {
try {
srcL.onSessionClosed(sessionId);
} finally {
jmxL.onSessionClosed(sessionId);
}
}
@Override
public void onError(String sessionId, Throwable t) {
try {
srcL.onError(sessionId, t);
} finally {
jmxL.onError(sessionId, t);
}
}
};
}
@Override
public void onEndpointUnregistered(String endpointPath) {
try {
src.onEndpointUnregistered(endpointPath);
} finally {
jmx.onEndpointUnregistered(endpointPath);
}
}
};
}
}
tracingType = Utils.getProperty(localProperties, WEBSOCKET_TRACING_TYPE, DebugContext.TracingType.class, DebugContext.TracingType.OFF);
tracingThreshold = Utils.getProperty(localProperties, WEBSOCKET_TRACING_THRESHOLD, DebugContext.TracingThreshold.class, DebugContext.TracingThreshold.TRACE);
buildEngine();
}
private void buildEngine() {
engine = TyrusWebSocketEngine.builder(this)
.incomingBufferSize(incomingBufferSize)
.clusterContext(clusterContext)
.applicationEventListener(applicationEventListener)
.maxSessionsPerApp(maxSessionsPerApp)
.maxSessionsPerRemoteAddr(maxSessionsPerRemoteAddr)
.parallelBroadcastEnabled(BooleanUtils.isTrue(parallelBroadcastEnabled))
.tracingType(tracingType)
.tracingThreshold(tracingThreshold)
.build();
}
@Override
public void register(Class> endpointClass) throws DeploymentException {
engine.register(endpointClass, contextPath);
}
@Override
public void register(ServerEndpointConfig serverEndpointConfig) throws DeploymentException {
engine.register(serverEndpointConfig, contextPath);
}
@Override
public WebSocketEngine getWebSocketEngine() {
return engine;
}
public Integer getIncomingBufferSize() {
return incomingBufferSize;
}
@Override
public void start(final String rootPath, int port) throws IOException, DeploymentException {
contextPath = rootPath;
this.port = port;
super.start(rootPath, port);
}
public int getPort() {
return port;
}
public String getContextPath() {
return contextPath;
}
@Override
public void stop() {
super.stop();
if (applicationEventListener != null) {
applicationEventListener.onApplicationDestroyed();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy