/*
* Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/
package com.ning.http.client.websocket;
import com.ning.http.client.AsyncHandler;
import com.ning.http.client.HttpResponseBodyPart;
import com.ning.http.client.HttpResponseHeaders;
import com.ning.http.client.HttpResponseStatus;
import com.ning.http.client.UpgradeHandler;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* An {@link AsyncHandler} which is able to execute WebSocket upgrade. Use the Builder for configuring WebSocket options.
*/
public class WebSocketUpgradeHandler implements UpgradeHandler<WebSocket>, AsyncHandler<WebSocket> {
private WebSocket webSocket;
private final ConcurrentLinkedQueue<WebSocketListener> l;
private final String protocol;
private final long maxByteSize;
private final long maxTextSize;
private final AtomicBoolean ok = new AtomicBoolean(false);
private WebSocketUpgradeHandler(Builder b) {
l = b.l;
protocol = b.protocol;
maxByteSize = b.maxByteSize;
maxTextSize = b.maxTextSize;
}
/**
* {@inheritDoc}
*/
@Override
public final void onThrowable(Throwable t) {
onFailure(t);
}
/**
* {@inheritDoc}
*/
@Override
public final STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
return STATE.CONTINUE;
}
/**
* {@inheritDoc}
*/
@Override
public final STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception {
if (responseStatus.getStatusCode() == 101) {
return STATE.UPGRADE;
} else {
throw new IllegalStateException("Invalid upgrade protocol, status should be 101 but was " + responseStatus.getStatusCode());
}
}
/**
* {@inheritDoc}
*/
@Override
public final STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception {
return STATE.CONTINUE;
}
/**
* {@inheritDoc}
*/
@Override
public final WebSocket onCompleted() throws Exception {
if (webSocket == null) {
throw new IllegalStateException("WebSocket is null");
}
return webSocket;
}
/**
* {@inheritDoc}
*/
@Override
public final void onSuccess(WebSocket webSocket) {
this.webSocket = webSocket;
for (WebSocketListener w : l) {
webSocket.addWebSocketListener(w);
w.onOpen(webSocket);
}
ok.set(true);
}
/**
* {@inheritDoc}
*/
@Override
public final void onFailure(Throwable t) {
for (WebSocketListener w : l) {
if (!ok.get() && webSocket != null) {
webSocket.addWebSocketListener(w);
}
w.onError(t);
}
}
/**
* Build a {@link WebSocketUpgradeHandler}
*/
public final static class Builder {
private ConcurrentLinkedQueue<WebSocketListener> l = new ConcurrentLinkedQueue<WebSocketListener>();
private String protocol = "";
private long maxByteSize = 8192;
private long maxTextSize = 8192;
/**
* Add a {@link WebSocketListener} that will be added to the {@link WebSocket}
*
* @param listener a {@link WebSocketListener}
* @return this
*/
public Builder addWebSocketListener(WebSocketListener listener) {
l.add(listener);
return this;
}
/**
* Remove a {@link WebSocketListener}
*
* @param listener a {@link WebSocketListener}
* @return this
*/
public Builder removeWebSocketListener(WebSocketListener listener) {
l.remove(listener);
return this;
}
/**
* Set the WebSocket protocol.
*
* @param protocol the WebSocket protocol.
* @return this
*/
public Builder setProtocol(String protocol) {
this.protocol = protocol;
return this;
}
/**
* Set the max size of the WebSocket byte message that will be sent.
*
* @param maxByteSize max size of the WebSocket byte message
* @return this
*/
public Builder setMaxByteSize(long maxByteSize) {
this.maxByteSize = maxByteSize;
return this;
}
/**
* Set the max size of the WebSocket text message that will be sent.
*
* @param maxTextSize max size of the WebSocket byte message
* @return this
*/
public Builder setMaxTextSize(long maxTextSize) {
this.maxTextSize = maxTextSize;
return this;
}
/**
* Build a {@link WebSocketUpgradeHandler}
* @return a {@link WebSocketUpgradeHandler}
*/
public WebSocketUpgradeHandler build() {
return new WebSocketUpgradeHandler(this);
}
}
}