/**
* Copyright 2007-2015, Kaazing Corporation. All rights reserved.
*
* 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 org.kaazing.k3po.driver.internal.netty.bootstrap.bbosh;
import static org.jboss.netty.channel.Channels.fireChannelClosed;
import static org.jboss.netty.channel.Channels.fireChannelDisconnected;
import static org.jboss.netty.channel.Channels.fireChannelUnbound;
import static org.jboss.netty.channel.Channels.fireMessageReceived;
import static org.kaazing.k3po.driver.internal.netty.bootstrap.bbosh.BBoshHttpHeaders.getIntHeader;
import static org.kaazing.k3po.driver.internal.netty.channel.Channels.shutdownOutput;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.kaazing.k3po.driver.internal.netty.bootstrap.bbosh.BBoshHttpHeaders.Names;
import org.kaazing.k3po.driver.internal.netty.bootstrap.http.HttpChannelConfig;
import org.kaazing.k3po.driver.internal.netty.bootstrap.http.HttpChildChannel;
import org.kaazing.k3po.driver.internal.netty.channel.ShutdownInputEvent;
import org.kaazing.k3po.driver.internal.netty.channel.SimpleChannelHandler;
public class BBoshPollingChildChannelSource extends SimpleChannelHandler {
private static final ChannelFutureListener READ_RESUMER = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Channel channel = future.getChannel();
channel.setReadable(true);
}
};
private final BBoshChildChannel bboshChannel;
private final BBoshPollingChildChannelSink bboshChannelSink;
public BBoshPollingChildChannelSource(BBoshChildChannel bboshChannel) {
this.bboshChannel = bboshChannel;
this.bboshChannelSink = (BBoshPollingChildChannelSink) bboshChannel.getPipeline().getSink();
}
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
HttpChildChannel httpChannel = (HttpChildChannel) ctx.getChannel();
HttpChannelConfig httpConfig = httpChannel.getConfig();
HttpHeaders httpHeaders = httpConfig.getReadHeaders();
int sequenceNo = getIntHeader(httpHeaders, Names.X_SEQUENCE_NO);
ChannelFuture attachFuture = bboshChannelSink.attach(sequenceNo, httpChannel);
if (!attachFuture.isDone()) {
httpChannel.setReadable(false);
attachFuture.addListener(READ_RESUMER);
}
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
Object message = e.getMessage();
fireMessageReceived(bboshChannel, message);
}
@Override
public void inputShutdown(ChannelHandlerContext ctx, ShutdownInputEvent e) {
HttpChildChannel httpChannel = (HttpChildChannel) ctx.getChannel();
HttpChannelConfig httpConfig = httpChannel.getConfig();
HttpMethod httpMethod = httpConfig.getMethod();
if (HttpMethod.DELETE.getName().equalsIgnoreCase(httpMethod.getName())) {
shutdownOutput(httpChannel);
}
}
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
HttpChildChannel httpChannel = (HttpChildChannel) ctx.getChannel();
HttpChannelConfig httpConfig = httpChannel.getConfig();
HttpMethod httpMethod = httpConfig.getMethod();
bboshChannelSink.detach(httpChannel);
if (HttpMethod.DELETE.getName().equalsIgnoreCase(httpMethod.getName())) {
if (bboshChannel.setClosed()) {
fireChannelDisconnected(bboshChannel);
fireChannelUnbound(bboshChannel);
fireChannelClosed(bboshChannel);
}
}
else {
// TODO: start timer for reconnect (close BBoshChannel on timeout, triggers cleanup of child channel handler)
}
}
}