All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.tyrus.core.TyrusEndpoint Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2012-2014 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * http://glassfish.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package org.glassfish.tyrus.core;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.Extension;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

import org.glassfish.tyrus.spi.UpgradeRequest;
import org.glassfish.tyrus.spi.UpgradeResponse;

/**
 * Tyrus endpoint representation.
 * 

* Please note that for one connection to TyrusEndpoint it is guaranteed that the methods: * isApplicationRequest, createSocket, getSupportedProtocols, getSupportedExtensions are called in this order. * Handshakes * * @author Danny Coward (danny.coward at oracle.com) * @author Stepan Kopriva (stepan.kopriva at oracle.com) * @author Pavel Bucek (pavel.bucek at oracle.com) */ public class TyrusEndpoint { private static final Logger LOGGER = Logger.getLogger(TyrusEndpoint.class.getName()); private final TyrusEndpointWrapper endpoint; /** * Used to store negotiated extensions between the call of isApplicationRequest method and getSupportedExtensions. */ private List temporaryNegotiatedExtensions = Collections.emptyList(); /** * Used to store negotiated protocol between the call of isApplicationRequest method and getSupportedProtocols. */ private String temporaryNegotiatedProtocol; /** * Create {@link TyrusEndpoint} which represents given {@link TyrusEndpointWrapper}. * * @param endpoint endpoint to be wrapped. */ public TyrusEndpoint(TyrusEndpointWrapper endpoint) { this.endpoint = endpoint; } /** * Checks application specific criteria to determine if this application can * process the request as a WebSocket connection. * * @param request the incoming HTTP request. * @return true if this application can service this request */ protected boolean isApplicationRequest(UpgradeRequest request) { final List protocols = request.getHeaders().get(UpgradeRequest.SEC_WEBSOCKET_PROTOCOL); temporaryNegotiatedProtocol = endpoint.getNegotiatedProtocol(protocols); final List extensions = TyrusExtension.fromString(request.getHeaders().get(UpgradeRequest.SEC_WEBSOCKET_EXTENSIONS)); temporaryNegotiatedExtensions = endpoint.getNegotiatedExtensions(extensions); return endpoint.checkHandshake(request); } /** * 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, {@link #isApplicationRequest(org.glassfish.tyrus.spi.UpgradeRequest)} * will be invoked to determine if the request is a valid websocket request. * * @param request TODO * @return true if the request should be upgraded to a * WebSocket connection */ public final boolean upgrade(UpgradeRequest request) { final String upgradeHeader = request.getHeader(UpgradeRequest.UPGRADE); return request.getHeaders().get(UpgradeRequest.UPGRADE) != null && // RFC 6455, paragraph 4.2.1.3 UpgradeRequest.WEBSOCKET.equalsIgnoreCase(upgradeHeader) && isApplicationRequest(request); } /** * Return path for which is current {@link TyrusEndpoint} registered. * * @return path. {@code null} will be returned when called on client. */ public String getPath() { return endpoint.getEndpointPath(); } /** * Factory method to create new {@link TyrusWebSocket} instances. Developers may * wish to override this to return customized {@link TyrusWebSocket} implementations. * * @param handler the {@link ProtocolHandler} to use with the newly created * {@link TyrusWebSocket}. * @return TODO */ public TyrusWebSocket createSocket(final ProtocolHandler handler) { return new TyrusWebSocket(handler, this); } /** *

* Invoked when the opening handshake has been completed for a specific * {@link WebSocket} instance. *

* * @param socket the newly connected {@link WebSocket} * @param upgradeRequest request associated with accepted connection. */ /** * When a new {@link TyrusWebSocket} connection is made to this application, the * {@link TyrusWebSocket} will be associated with this application. * * @param socket the new {@link TyrusWebSocket} connection. * @param upgradeRequest request associated with connection. */ public void onConnect(TyrusWebSocket socket, UpgradeRequest upgradeRequest) { this.endpoint.onConnect(new TyrusRemoteEndpoint(socket), temporaryNegotiatedProtocol, temporaryNegotiatedExtensions, upgradeRequest); } /** *

* Invoked when {@link TyrusWebSocket#onFragment(boolean, org.glassfish.tyrus.core.frame.TextFrame)} has been called * on a particular {@link TyrusWebSocket} instance. *

* * @param socket the {@link TyrusWebSocket} received the message fragment. * @param fragment the message fragment. * @param last flag indicating if this was the last fragment. */ public void onFragment(TyrusWebSocket socket, String fragment, boolean last) { try { this.endpoint.onPartialMessage(new TyrusRemoteEndpoint(socket), fragment, last); } catch (Throwable t) { LOGGER.log(Level.FINE, t.getMessage(), t); } } /** *

* Invoked when {@link TyrusWebSocket#onFragment(boolean, org.glassfish.tyrus.core.frame.BinaryFrame)} has been called * on a particular {@link TyrusWebSocket} instance. *

* * @param socket the {@link TyrusWebSocket} received the message fragment. * @param fragment the message fragment. * @param last flag indicating if this was the last fragment. */ public void onFragment(TyrusWebSocket socket, byte[] fragment, boolean last) { try { this.endpoint.onPartialMessage(new TyrusRemoteEndpoint(socket), ByteBuffer.wrap(fragment), last); } catch (Throwable t) { LOGGER.log(Level.FINE, t.getMessage(), t); } } /** *

* Invoked when {@link TyrusWebSocket#onMessage(org.glassfish.tyrus.core.frame.TextFrame)} has been called on a * particular {@link TyrusWebSocket} instance. *

* * @param socket the {@link TyrusWebSocket} that received a message. * @param text the message received. */ public void onMessage(TyrusWebSocket socket, String text) { this.endpoint.onMessage(new TyrusRemoteEndpoint(socket), text); } /** *

* Invoked when {@link TyrusWebSocket#onMessage(org.glassfish.tyrus.core.frame.BinaryFrame)} has been called on a * particular {@link TyrusWebSocket} instance. *

* * @param socket the {@link TyrusWebSocket} that received a message. * @param bytes the message received. */ public void onMessage(TyrusWebSocket socket, byte[] bytes) { this.endpoint.onMessage(new TyrusRemoteEndpoint(socket), ByteBuffer.wrap(bytes)); } /** * When a {@link WebSocket#onClose(org.glassfish.tyrus.core.frame.CloseFrame)} is invoked, the {@link WebSocket} * will be unassociated with this application and closed. * * @param socket the {@link WebSocket} being closed. * @param closeReason the {@link CloseReason}. */ /** *

* Invoked when {@link TyrusWebSocket#onClose(org.glassfish.tyrus.core.frame.CloseFrame)} has been called on a * particular {@link TyrusWebSocket} instance. *

* * @param socket the {@link TyrusWebSocket} being closed. * @param closeReason the {@link CloseReason} sent by the remote end-point. */ public void onClose(TyrusWebSocket socket, CloseReason closeReason) { this.endpoint.onClose(new TyrusRemoteEndpoint(socket), closeReason); } /** *

* Invoked when {@link TyrusWebSocket#onPing(org.glassfish.tyrus.core.frame.PingFrame)} has been called on a * particular {@link TyrusWebSocket} instance. *

* * @param socket the {@link TyrusWebSocket} that received the ping. * @param bytes the payload of the ping frame, if any. */ public void onPing(TyrusWebSocket socket, byte[] bytes) { this.endpoint.onPing(new TyrusRemoteEndpoint(socket), ByteBuffer.wrap(bytes)); } /** *

* Invoked when {@link TyrusWebSocket#onPong(org.glassfish.tyrus.core.frame.PongFrame)} has been called on a * particular {@link TyrusWebSocket} instance. *

* * @param socket the {@link TyrusWebSocket} that received the pong. * @param bytes the payload of the pong frame, if any. */ public void onPong(TyrusWebSocket socket, byte[] bytes) { this.endpoint.onPong(new TyrusRemoteEndpoint(socket), ByteBuffer.wrap(bytes)); } /** * Return the websocket extensions supported by this {@link TyrusEndpoint} * 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 {@link TyrusEndpoint}. */ public List getSupportedExtensions() { return new ArrayList(temporaryNegotiatedExtensions); } /** * 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} if the WebSocket should be closed otherwise * {@code false}. */ public boolean onError(TyrusWebSocket webSocket, Throwable t) { Logger.getLogger(TyrusEndpoint.class.getName()).log(Level.WARNING, "Unexpected error, closing connection.", t); return true; } /** * @param subProtocol TODO * @return TODO */ public List getSupportedProtocols(List subProtocol) { List result; if (temporaryNegotiatedProtocol == null || temporaryNegotiatedProtocol.isEmpty()) { result = Collections.emptyList(); } else { result = new ArrayList(); result.add(temporaryNegotiatedProtocol); } return result; } /** * Invoked when server side handshake is ready to send response. *

* Changes in response parameter will be reflected in data sent back to client. * * @param request original request which caused this handshake. * @param response response to be send. */ public void onHandShakeResponse(UpgradeRequest request, UpgradeResponse response) { final EndpointConfig configuration = this.endpoint.getEndpointConfig(); if (configuration instanceof ServerEndpointConfig) { // http://java.net/jira/browse/TYRUS-62 final ServerEndpointConfig serverEndpointConfig = (ServerEndpointConfig) configuration; serverEndpointConfig.getConfigurator().modifyHandshake(serverEndpointConfig, createHandshakeRequest(request), response); } } private HandshakeRequest createHandshakeRequest(final UpgradeRequest webSocketRequest) { if (webSocketRequest instanceof RequestContext) { final RequestContext requestContext = (RequestContext) webSocketRequest; // TYRUS-208; spec requests headers to be read only when passed to ServerEndpointConfig.Configurator#modifyHandshake. // TYRUS-211; spec requests parameterMap to be read only when passed to ServerEndpointConfig.Configurator#modifyHandshake. requestContext.lock(); return requestContext; } return null; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TyrusEndpoint that = (TyrusEndpoint) o; if (endpoint == null) { return super.equals(o); } else { return endpoint.equals(that.endpoint); } } @Override public int hashCode() { if (endpoint == null) { return super.hashCode(); } else { return endpoint.hashCode(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy