/**
* 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.behavior.handler;
import static org.kaazing.k3po.driver.internal.channel.Channels.prepare;
import static org.kaazing.k3po.driver.internal.netty.channel.ChannelFutures.describeFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.DefaultChannelFuture;
import org.jboss.netty.channel.LifeCycleAwareChannelHandler;
import org.kaazing.k3po.driver.internal.behavior.ScriptProgressException;
import org.kaazing.k3po.driver.internal.behavior.handler.prepare.PreparationEvent;
import org.kaazing.k3po.driver.internal.behavior.handler.prepare.SimplePrepareUpstreamHandler;
import org.kaazing.k3po.lang.internal.RegionInfo;
public class ExecutionHandler extends SimplePrepareUpstreamHandler implements LifeCycleAwareChannelHandler {
private ChannelFuture handlerFuture;
private ChannelFuture pipelineFuture;
private RegionInfo regionInfo;
private final AtomicBoolean preparationLatch = new AtomicBoolean();
private Channel channel;
public RegionInfo getRegionInfo() {
return regionInfo;
}
public void setRegionInfo(RegionInfo regionInfo) {
this.regionInfo = regionInfo;
}
public Channel getChannel() {
return channel;
}
@Override
public void prepareRequested(ChannelHandlerContext ctx, PreparationEvent evt) {
// Ideally one could extract the future from the handlerFuture. But we are
// creating them before the channel is set up :(
channel = ctx.getChannel();
// set latch in case prepare triggered by handler earlier in pipeline
preparationLatch.set(true);
pipelineFuture = evt.checkpoint(handlerFuture);
super.prepareRequested(ctx, evt);
}
@Override
public void beforeAdd(final ChannelHandlerContext ctx) throws Exception {
assert handlerFuture == null;
// note: the context channel is null if handler added to pipeline before channel has been created
handlerFuture = new DefaultChannelFuture(null, false) {
@Override
public Channel getChannel() {
return ctx.getChannel();
}
@Override
public String toString() {
return ExecutionHandler.this.toString();
}
};
}
@Override
public void afterAdd(ChannelHandlerContext ctx) throws Exception {
assert handlerFuture != null;
}
@Override
public void beforeRemove(ChannelHandlerContext ctx) throws Exception {
assert handlerFuture != null;
}
@Override
public void afterRemove(ChannelHandlerContext ctx) throws Exception {
assert handlerFuture != null;
if (!handlerFuture.isDone()) {
ScriptProgressException exception = new ScriptProgressException(getRegionInfo(), "");
exception.fillInStackTrace();
handlerFuture.setFailure(exception);
}
handlerFuture = null;
}
public ChannelFuture getHandlerFuture() {
if (handlerFuture == null) {
throw new IllegalStateException("ChannelHandler not added to pipeline yet");
}
return handlerFuture;
}
public ChannelFuture getPipelineFuture() {
if (pipelineFuture == null) {
throw new IllegalStateException("ChannelHandler not prepared yet");
}
return pipelineFuture;
}
@Override
protected final void handleUpstream0(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
// prepare on receiving first channel open event
if (preparationLatch.compareAndSet(false, true)) {
prepare(ctx.getChannel());
}
handleUpstream1(ctx, e);
}
protected void handleUpstream1(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
super.handleUpstream0(ctx, e);
}
@Override
public final String toString() {
return describe(new StringBuilder())
.append(" (")
.append(describeFuture(getHandlerFuture()))
.append(')')
.toString();
}
protected StringBuilder describe(StringBuilder sb) {
return sb.append("execution");
}
}