/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ameba.websocket.adapter.standard;
import ameba.websocket.BinaryMessage;
import ameba.websocket.PingMessage;
import ameba.websocket.PongMessage;
import ameba.websocket.TextMessage;
import ameba.websocket.adapter.AbstractWebSocketSession;
import com.google.common.util.concurrent.Futures;
import org.glassfish.jersey.internal.util.collection.MultivaluedStringMap;
import javax.websocket.CloseReason;
import javax.websocket.Extension;
import javax.websocket.Session;
import javax.ws.rs.core.MultivaluedMap;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.Principal;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
/**
* A {@link ameba.websocket.WebSocketSession} for use with the standard WebSocket for Java API.
*
* @author Rossen Stoyanchev
* @author icode
*
*/
public class StandardWebSocketSession extends AbstractWebSocketSession<Session> {
private final MultivaluedMap<String, String> handshakeHeaders;
private final InetSocketAddress localAddress;
private final InetSocketAddress remoteAddress;
private String id;
private URI uri;
private String negotiatedProtocol;
private List<Extension> extensions;
private Principal user;
/**
* Class constructor.
*
* @param headers the headers of the handshake request
* @param attributes attributes from the HTTP handshake to associate with the WebSocket
* session; the provided attributes are copied, the original map is not used.
* @param localAddress the address on which the request was received
* @param remoteAddress the address of the remote client
*/
public StandardWebSocketSession(MultivaluedMap<String, String> headers, Map<String, Object> attributes,
InetSocketAddress localAddress, InetSocketAddress remoteAddress) {
this(headers, attributes, localAddress, remoteAddress, null);
}
/**
* Class constructor that associates a user with the WebSocket session.
*
* @param headers the headers of the handshake request
* @param attributes attributes from the HTTP handshake to associate with the WebSocket session
* @param localAddress the address on which the request was received
* @param remoteAddress the address of the remote client
* @param user the user associated with the session; if {@code null} we'll
* fallback on the user available in the underlying WebSocket session
*/
public StandardWebSocketSession(MultivaluedMap<String, String> headers, Map<String, Object> attributes,
InetSocketAddress localAddress, InetSocketAddress remoteAddress, Principal user) {
super(attributes);
this.handshakeHeaders = (headers != null) ? headers : new MultivaluedStringMap();
this.user = user;
this.localAddress = localAddress;
this.remoteAddress = remoteAddress;
}
/**
* {@inheritDoc}
*/
@Override
public String getId() {
checkNativeSessionInitialized();
return this.id;
}
/** {@inheritDoc} */
@Override
public URI getUri() {
checkNativeSessionInitialized();
return this.uri;
}
/** {@inheritDoc} */
@Override
public MultivaluedMap<String, String> getHandshakeHeaders() {
return this.handshakeHeaders;
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("unchecked")
public <T> T getAttribute(String key) {
return (T) getAttributes().get(key);
}
/** {@inheritDoc} */
@Override
public void setAttribute(String key, Object value) {
getAttributes().put(key, value);
}
/** {@inheritDoc} */
@Override
public List<Extension> getExtensions() {
checkNativeSessionInitialized();
return this.extensions;
}
/**
* <p>getPrincipal.</p>
*
* @return a {@link java.security.Principal} object.
*/
public Principal getPrincipal() {
return this.user;
}
/** {@inheritDoc} */
@Override
public InetSocketAddress getLocalAddress() {
return this.localAddress;
}
/** {@inheritDoc} */
@Override
public InetSocketAddress getRemoteAddress() {
return this.remoteAddress;
}
/** {@inheritDoc} */
@Override
public String getNegotiatedProtocol() {
checkNativeSessionInitialized();
return this.negotiatedProtocol;
}
/** {@inheritDoc} */
@Override
public int getTextMessageSizeLimit() {
checkNativeSessionInitialized();
return getNativeSession().getMaxTextMessageBufferSize();
}
/** {@inheritDoc} */
@Override
public void setTextMessageSizeLimit(int messageSizeLimit) {
checkNativeSessionInitialized();
getNativeSession().setMaxTextMessageBufferSize(messageSizeLimit);
}
/** {@inheritDoc} */
@Override
public int getBinaryMessageSizeLimit() {
checkNativeSessionInitialized();
return getNativeSession().getMaxBinaryMessageBufferSize();
}
/** {@inheritDoc} */
@Override
public void setBinaryMessageSizeLimit(int messageSizeLimit) {
checkNativeSessionInitialized();
getNativeSession().setMaxBinaryMessageBufferSize(messageSizeLimit);
}
/** {@inheritDoc} */
@Override
public boolean isOpen() {
return (getNativeSession() != null && getNativeSession().isOpen());
}
/** {@inheritDoc} */
@Override
public Set<Session> getOpenSessions() {
checkNativeSessionInitialized();
return getNativeSession().getOpenSessions();
}
/** {@inheritDoc} */
@Override
public void initializeNativeSession(Session session) {
super.initializeNativeSession(session);
this.id = session.getId();
this.uri = session.getRequestURI();
this.negotiatedProtocol = session.getNegotiatedSubprotocol();
this.extensions = session.getNegotiatedExtensions();
if (this.user == null) {
this.user = session.getUserPrincipal();
}
}
/** {@inheritDoc} */
@Override
protected Future<Void> sendTextMessage(TextMessage message) {
return getNativeSession().getAsyncRemote().sendText(message.getPayload());
}
/** {@inheritDoc} */
@Override
protected Future<Void> sendBinaryMessage(BinaryMessage message) {
return getNativeSession().getAsyncRemote().sendBinary(message.getPayload());
}
/** {@inheritDoc} */
@Override
protected Future<Void> sendPingMessage(PingMessage message) throws IOException {
getNativeSession().getAsyncRemote().sendPing(message.getPayload());
return Futures.immediateFuture(null);
}
/** {@inheritDoc} */
@Override
protected Future<Void> sendPongMessage(PongMessage message) throws IOException {
getNativeSession().getAsyncRemote().sendPong(message.getPayload());
return Futures.immediateFuture(null);
}
/** {@inheritDoc} */
@Override
protected Future<Void> sendObjectMessage(Object message) {
return getNativeSession().getAsyncRemote().sendObject(message);
}
/** {@inheritDoc} */
@Override
protected void closeInternal(CloseReason status) throws IOException {
checkNativeSessionInitialized();
getNativeSession().close(status);
}
}