/*
* Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package org.glassfish.grizzly.websockets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.glassfish.grizzly.http.HttpRequestPacket;
import org.glassfish.grizzly.http.util.Header;
Author: Alexey Stashok
/**
* Abstract server-side {@link WebSocket} application, which will handle
* application {@link WebSocket}s events.
*
* @author Alexey Stashok
*/
public abstract class WebSocketApplication extends WebSocketAdapter {
/*
* WebSockets registered with this application.
*/
private final ConcurrentMap<WebSocket, Boolean> sockets = new ConcurrentHashMap<>();
private final List<Extension> supportedExtensions = new ArrayList<Extension>(2);
private final List<String> supportedProtocols = new ArrayList<String>(2);
// ---------------------------------------------------------- Public Methods
Factory method to create new WebSocket
instances. Developers may wish to override this to return customized WebSocket
implementations. Params: - handler – the
ProtocolHandler
to use with the newly created WebSocket
. - listeners – the
WebSocketListener
s to associate with the new WebSocket
.
Returns: a new WebSocket
instance. Deprecated: Use createSocket(ProtocolHandler, HttpRequestPacket, WebSocketListener...)
/**
* Factory method to create new {@link WebSocket} instances. Developers may
* wish to override this to return customized {@link WebSocket} implementations.
*
* @param handler the {@link ProtocolHandler} to use with the newly created
* {@link WebSocket}.
*
* @param listeners the {@link WebSocketListener}s to associate with the new
* {@link WebSocket}.
*
* @return a new {@link WebSocket} instance.
*
* @deprecated Use {@link WebSocketApplication#createSocket(ProtocolHandler, org.glassfish.grizzly.http.HttpRequestPacket, WebSocketListener...)}
*/
@Deprecated
public WebSocket createSocket(ProtocolHandler handler, WebSocketListener... listeners) {
return createSocket(handler, null, listeners);
}
Factory method to create new WebSocket
instances. Developers may wish to override this to return customized WebSocket
implementations. Params: - handler – the
ProtocolHandler
to use with the newly created WebSocket
. - requestPacket – the
HttpRequestPacket
that triggered the creation of the WebSocket
connection. - listeners – the
WebSocketListener
s to associate with the new WebSocket
.
Returns:
/**
* Factory method to create new {@link WebSocket} instances. Developers may
* wish to override this to return customized {@link WebSocket} implementations.
* @param handler the {@link ProtocolHandler} to use with the newly created
* {@link WebSocket}.
* @param requestPacket the {@link HttpRequestPacket} that triggered the
* creation of the {@link WebSocket} connection.
* @param listeners the {@link WebSocketListener}s to associate with the new
* {@link WebSocket}.
* @return
*/
public WebSocket createSocket(final ProtocolHandler handler,
final HttpRequestPacket requestPacket,
final WebSocketListener... listeners) {
return new DefaultWebSocket(handler, requestPacket, listeners);
}
When a WebSocket.onClose(DataFrame)
is invoked, the WebSocket
will be unassociated with this application and closed. If this method is overridden, the overriding method must call remove(WebSocket)
. This is necessary to ensure WebSocket instances are not leaked nor are message operations against closed sockets are performed. Params: - socket – the
WebSocket
being closed. - frame – the closing frame.
/**
* When a {@link WebSocket#onClose(DataFrame)} is invoked, the {@link WebSocket}
* will be unassociated with this application and closed.
*
* If this method is overridden, the overriding method <em>must</em>
* call {@link #remove(WebSocket)}. This is necessary to ensure WebSocket
* instances are not leaked nor are message operations against closed sockets
* are performed.
*
* @param socket the {@link WebSocket} being closed.
* @param frame the closing frame.
*/
@Override
public void onClose(WebSocket socket, DataFrame frame) {
remove(socket);
socket.close();
}
When a new WebSocket
connection is made to this application, the WebSocket
will be associated with this application. If this method is overridden, the overriding method must call add(WebSocket)
. This is necessary to ensure bulk message sending via facilities such as Broadcaster
function properly. Params: - socket – the new
WebSocket
connection.
/**
* When a new {@link WebSocket} connection is made to this application, the
* {@link WebSocket} will be associated with this application.
*
* If this method is overridden, the overriding method <em>must</em>
* call {@link #add(WebSocket)}. This is necessary to ensure bulk message
* sending via facilities such as {@link Broadcaster} function properly.
*
* @param socket the new {@link WebSocket} connection.
*/
@Override
public void onConnect(WebSocket socket) {
add(socket);
}
Invoked during the handshake if the client has advertised extensions it may use and one or more extensions intersect with those returned by getSupportedExtensions()
. The Extension
s passed to this method will include any extension parameters included by the client. It's up to this method to re-order and or adjust any parameter values within the list. This method must not add any extensions that weren't originally in the list, but it is acceptable to remove one or all extensions if for some reason they can't be supported. If not overridden, the List will be sent as-is back to the client. Params: - extensions – the intersection of extensions between client and
application.
Since: 2.3
/**
* Invoked during the handshake if the client has advertised extensions
* it may use and one or more extensions intersect with those returned
* by {@link #getSupportedExtensions()}.
*
* The {@link Extension}s passed to this method will include any extension
* parameters included by the client. It's up to this method to re-order
* and or adjust any parameter values within the list. This method must not
* add any extensions that weren't originally in the list, but it is acceptable
* to remove one or all extensions if for some reason they can't be supported.
*
* If not overridden, the List will be sent as-is back to the client.
*
* @param extensions the intersection of extensions between client and
* application.
*
* @since 2.3
*/
public void onExtensionNegotiation(List<Extension> extensions) {
}
Checks protocol specific information can and should be upgraded.
The default implementation will check for the presence of the
Upgrade
header with a value of WebSocket
. If present, isApplicationRequest(HttpRequestPacket)
will be invoked to determine if the request is a valid websocket request. Returns: true
if the request should be upgraded to a
WebSocket connection
/**
* Checks protocol specific information can and should be upgraded.
*
* The default implementation will check for the presence of the
* <code>Upgrade</code> header with a value of <code>WebSocket</code>.
* If present, {@link #isApplicationRequest(org.glassfish.grizzly.http.HttpRequestPacket)}
* will be invoked to determine if the request is a valid websocket request.
*
* @return <code>true</code> if the request should be upgraded to a
* WebSocket connection
*/
public final boolean upgrade(HttpRequestPacket request) {
return "WebSocket".equalsIgnoreCase(request.getHeader(Header.Upgrade)) && isApplicationRequest(request);
}
Checks application specific criteria to determine if this application can
process the request as a WebSocket connection.
Params: - request – the incoming HTTP request.
Returns: true
if this application can service this request
Deprecated: URI mapping shouldn't be intrinsic to the application. WebSocketApplications should be registered using WebSocketEngine.register(String, String, WebSocketApplication)
using standard Servlet url-pattern rules.
/**
* Checks application specific criteria to determine if this application can
* process the request as a WebSocket connection.
*
* @param request the incoming HTTP request.
* @return <code>true</code> if this application can service this request
* <p/>
* @deprecated URI mapping shouldn't be intrinsic to the application.
* WebSocketApplications should be registered using {@link WebSocketEngine#register(String, String, WebSocketApplication)}
* using standard Servlet url-pattern rules.
*/
public boolean isApplicationRequest(HttpRequestPacket request) {
return false;
}
Return the websocket extensions supported by this WebSocketApplication
. The Extension
s added to this List
should not include any Parameter
s as they will be ignored. This is used exclusively for matching the requested extensions. Returns: the websocket extensions supported by this
WebSocketApplication
.
/**
* Return the websocket extensions supported by this <code>WebSocketApplication</code>.
* The {@link Extension}s added to this {@link List} should not include
* any {@link Extension.Parameter}s as they will be ignored. This is used
* exclusively for matching the requested extensions.
*
* @return the websocket extensions supported by this
* <code>WebSocketApplication</code>.
*/
public List<Extension> getSupportedExtensions() {
return supportedExtensions;
}
Params: - subProtocol –
Returns:
/**
*
*
* @param subProtocol
* @return
*/
public List<String> getSupportedProtocols(List<String> subProtocol) {
return supportedProtocols;
}
// ------------------------------------------------------- Protected Methods
Returns a set of WebSocket
s, registered with the application. The returned set is unmodifiable, the possible modifications may cause exceptions. Returns: a set of WebSocket
s, registered with the application.
/**
* Returns a set of {@link WebSocket}s, registered with the application.
* The returned set is unmodifiable, the possible modifications may cause exceptions.
*
* @return a set of {@link WebSocket}s, registered with the application.
*/
protected Set<WebSocket> getWebSockets() {
return sockets.keySet();
}
Associates the specified WebSocket
with this application. Params: - socket – the
WebSocket
to associate with this application.
Returns: true
if the socket was successfully associated,
otherwise returns false
.
/**
* Associates the specified {@link WebSocket} with this application.
*
* @param socket the {@link WebSocket} to associate with this application.
*
* @return <code>true</code> if the socket was successfully associated,
* otherwise returns <code>false</code>.
*/
protected boolean add(WebSocket socket) {
return sockets.put(socket, Boolean.TRUE) == null;
}
Unassociates the specified WebSocket
with this application. Params: - socket – the
WebSocket
to unassociate with this application.
Returns: true
if the socket was successfully unassociated,
otherwise returns false
.
/**
* Unassociates the specified {@link WebSocket} with this application.
*
* @param socket the {@link WebSocket} to unassociate with this application.
*
* @return <code>true</code> if the socket was successfully unassociated,
* otherwise returns <code>false</code>.
*/
public boolean remove(WebSocket socket) {
return sockets.remove(socket) != null;
}
This method will be called, when initial WebSocket
handshake process has been completed, but allows the application to perform further negotiation/validation. Throws: - HandshakeException – error occurred during the handshake.
/**
* This method will be called, when initial {@link WebSocket} handshake
* process has been completed, but allows the application to perform further
* negotiation/validation.
*
* @throws HandshakeException error occurred during the handshake.
*/
protected void handshake(HandShake handshake) throws HandshakeException {
}
This method will be invoked if an unexpected exception is caught by
the WebSocket runtime.
Params: - webSocket – the websocket being processed at the time the
exception occurred.
- t – the unexpected exception.
Returns: true
if the WebSocket should be closed otherwise
false
.
/**
* This method will be invoked if an unexpected exception is caught by
* the WebSocket runtime.
*
* @param webSocket the websocket being processed at the time the
* exception occurred.
* @param t the unexpected exception.
*
* @return <code>true</code> if the WebSocket should be closed otherwise
* <code>false</code>.
*/
protected boolean onError(final WebSocket webSocket,
final Throwable t) {
return true;
}
}