org.jboss.netty.handler.timeout.WriteTimeoutHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of netty Show documentation
Show all versions of netty Show documentation
The Netty project is an effort to provide an asynchronous event-driven
network application framework and tools for rapid development of
maintainable high performance and high scalability protocol servers and
clients. In other words, Netty is a NIO client server framework which
enables quick and easy development of network applications such as protocol
servers and clients. It greatly simplifies and streamlines network
programming such as TCP and UDP socket server.
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you 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.jboss.netty.handler.timeout;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandler.Sharable;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelDownstreamHandler;
import org.jboss.netty.util.ExternalResourceReleasable;
import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timeout;
import org.jboss.netty.util.Timer;
import org.jboss.netty.util.TimerTask;
import java.util.concurrent.TimeUnit;
import static org.jboss.netty.channel.Channels.*;
/**
* Raises a {@link WriteTimeoutException} when no data was written within a
* certain period of time.
*
*
* public class MyPipelineFactory implements {@link ChannelPipelineFactory} {
*
* private final {@link Timer} timer;
*
* public MyPipelineFactory({@link Timer} timer) {
* this.timer = timer;
* }
*
* public {@link ChannelPipeline} getPipeline() {
* // An example configuration that implements 30-second write timeout:
* return {@link Channels}.pipeline(
* new {@link WriteTimeoutHandler}(timer, 30), // timer must be shared.
* new MyHandler());
* }
* }
*
* {@link ServerBootstrap} bootstrap = ...;
* {@link Timer} timer = new {@link HashedWheelTimer}();
* ...
* bootstrap.setPipelineFactory(new MyPipelineFactory(timer));
*
*
* The {@link Timer} which was specified when the {@link ReadTimeoutHandler} is
* created should be stopped manually by calling {@link #releaseExternalResources()}
* or {@link Timer#stop()} when your application shuts down.
* @see ReadTimeoutHandler
* @see IdleStateHandler
*
* @apiviz.landmark
* @apiviz.uses org.jboss.netty.util.HashedWheelTimer
* @apiviz.has org.jboss.netty.handler.timeout.TimeoutException oneway - - raises
*/
@Sharable
public class WriteTimeoutHandler extends SimpleChannelDownstreamHandler
implements ExternalResourceReleasable {
static final WriteTimeoutException EXCEPTION = new WriteTimeoutException();
private final Timer timer;
private final long timeoutMillis;
/**
* Creates a new instance.
*
* @param timer
* the {@link Timer} that is used to trigger the scheduled event.
* The recommended {@link Timer} implementation is {@link HashedWheelTimer}.
* @param timeoutSeconds
* write timeout in seconds
*/
public WriteTimeoutHandler(Timer timer, int timeoutSeconds) {
this(timer, timeoutSeconds, TimeUnit.SECONDS);
}
/**
* Creates a new instance.
*
* @param timer
* the {@link Timer} that is used to trigger the scheduled event.
* The recommended {@link Timer} implementation is {@link HashedWheelTimer}.
* @param timeout
* write timeout
* @param unit
* the {@link TimeUnit} of {@code timeout}
*/
public WriteTimeoutHandler(Timer timer, long timeout, TimeUnit unit) {
if (timer == null) {
throw new NullPointerException("timer");
}
if (unit == null) {
throw new NullPointerException("unit");
}
this.timer = timer;
if (timeout <= 0) {
timeoutMillis = 0;
} else {
timeoutMillis = Math.max(unit.toMillis(timeout), 1);
}
}
/**
* Stops the {@link Timer} which was specified in the constructor of this
* handler. You should not call this method if the {@link Timer} is in use
* by other objects.
*/
public void releaseExternalResources() {
timer.stop();
}
/**
* Returns the write timeout of the specified event. By default, this method returns the
* timeout value you specified in the constructor. Override this method to determine the
* timeout value depending on the message being written.
*
* @param e the message being written
*/
protected long getTimeoutMillis(MessageEvent e) {
return timeoutMillis;
}
@Override
public void writeRequested(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
long timeoutMillis = getTimeoutMillis(e);
if (timeoutMillis > 0) {
// Set timeout only when getTimeoutMillis() returns a positive value.
ChannelFuture future = e.getFuture();
final Timeout timeout = timer.newTimeout(
new WriteTimeoutTask(ctx, future),
timeoutMillis, TimeUnit.MILLISECONDS);
future.addListener(new TimeoutCanceller(timeout));
}
super.writeRequested(ctx, e);
}
protected void writeTimedOut(ChannelHandlerContext ctx) throws Exception {
fireExceptionCaught(ctx, EXCEPTION);
}
private final class WriteTimeoutTask implements TimerTask {
private final ChannelHandlerContext ctx;
private final ChannelFuture future;
WriteTimeoutTask(ChannelHandlerContext ctx, ChannelFuture future) {
this.ctx = ctx;
this.future = future;
}
public void run(Timeout timeout) throws Exception {
if (timeout.isCancelled()) {
return;
}
if (!ctx.getChannel().isOpen()) {
return;
}
// Mark the future as failure
if (future.setFailure(EXCEPTION)) {
// If succeeded to mark as failure, notify the pipeline, too.
fireWriteTimeOut(ctx);
}
}
private void fireWriteTimeOut(final ChannelHandlerContext ctx) {
ctx.getPipeline().execute(new Runnable() {
public void run() {
try {
writeTimedOut(ctx);
} catch (Throwable t) {
fireExceptionCaught(ctx, t);
}
}
});
}
}
private static final class TimeoutCanceller implements ChannelFutureListener {
private final Timeout timeout;
TimeoutCanceller(Timeout timeout) {
this.timeout = timeout;
}
public void operationComplete(ChannelFuture future) throws Exception {
timeout.cancel();
}
}
}