alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  
* </tr> * <tr> * <td>{@code readerIdleTime} * <td>an {@link IdleStateEvent} whose state is {@link IdleState#READER_IDLE} * will be triggered when no read was performed for the specified period of * time. Specify {@code 0} to disable.</td> * </tr> * <tr> * <td>{@code writerIdleTime} * <td>an {@link IdleStateEvent} whose state is {@link IdleState#WRITER_IDLE} * will be triggered when no write was performed for the specified period of * time. Specify {@code 0} to disable.</td> * </tr> * <tr> * <td>{@code allIdleTime} * <td>an {@link IdleStateEvent} whose state is {@link IdleState#ALL_IDLE} * will be triggered when neither read nor write was performed for the * specified period of time. Specify {@code 0} to disable.</td> * </tr> * </table> * * <pre> * // An example that sends a ping message when there is no outbound traffic * // for 30 seconds. The connection is closed when there is no inbound traffic * // for 60 seconds. * * public class MyChannelInitializer extends {@link ChannelInitializer}<{@link Channel}> { * {@code @Override} * public void initChannel({@link Channel} channel) { * channel.pipeline().addLast("idleStateHandler", new {@link IdleStateHandler}(60, 30, 0)); * channel.pipeline().addLast("myHandler", new MyHandler()); * } * } * * // Handler should handle the {@link IdleStateEvent} triggered by {@link IdleStateHandler}. * public class MyHandler extends {@link ChannelDuplexHandler} { * {@code @Override} * public void userEventTriggered({@link ChannelHandlerContext} ctx, {@link Object} evt) throws {@link Exception} { * if (evt instanceof {@link IdleStateEvent}) { * {@link IdleStateEvent} e = ({@link IdleStateEvent}) evt; * if (e.state() == {@link IdleState}.READER_IDLE) { * ctx.close(); * } else if (e.state() == {@link IdleState}.WRITER_IDLE) { * ctx.writeAndFlush(new PingMessage()); * } * } * } * } * * {@link ServerBootstrap} bootstrap = ...; * ... * bootstrap.childHandler(new MyChannelInitializer()); * ... * </pre> * * @see ReadTimeoutHandler * @see WriteTimeoutHandler */ public class IdleStateHandler extends ChannelDuplexHandler { private static final long MIN_TIMEOUT_NANOS = TimeUnit.MILLISECONDS.toNanos(1); // Not create a new ChannelFutureListener per write operation to reduce GC pressure. private final ChannelFutureListener writeListener = new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { lastWriteTime = System.nanoTime(); firstWriterIdleEvent = firstAllIdleEvent = true; } }; private final long readerIdleTimeNanos; private final long writerIdleTimeNanos; private final long allIdleTimeNanos; volatile ScheduledFuture<?> readerIdleTimeout; volatile long lastReadTime; private boolean firstReaderIdleEvent = true; volatile ScheduledFuture<?> writerIdleTimeout; volatile long lastWriteTime; private boolean firstWriterIdleEvent = true; volatile ScheduledFuture<?> allIdleTimeout; private boolean firstAllIdleEvent = true; private volatile int state; // 0 - none, 1 - initialized, 2 - destroyed private volatile boolean reading; /** * Creates a new instance firing {@link IdleStateEvent}s. * * @param readerIdleTimeSeconds * an {@link IdleStateEvent} whose state is {@link IdleState#READER_IDLE} * will be triggered when no read was performed for the specified * period of time. Specify {@code 0} to disable. * @param writerIdleTimeSeconds * an {@link IdleStateEvent} whose state is {@link IdleState#WRITER_IDLE} * will be triggered when no write was performed for the specified * period of time. Specify {@code 0} to disable. * @param allIdleTimeSeconds * an {@link IdleStateEvent} whose state is {@link IdleState#ALL_IDLE} * will be triggered when neither read nor write was performed for * the specified period of time. Specify {@code 0} to disable. */ public IdleStateHandler( int readerIdleTimeSeconds, int writerIdleTimeSeconds, int allIdleTimeSeconds) { this(readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds, TimeUnit.SECONDS); } /** * Creates a new instance firing {@link IdleStateEvent}s. * * @param readerIdleTime * an {@link IdleStateEvent} whose state is {@link IdleState#READER_IDLE} * will be triggered when no read was performed for the specified * period of time. Specify {@code 0} to disable. * @param writerIdleTime * an {@link IdleStateEvent} whose state is {@link IdleState#WRITER_IDLE} * will be triggered when no write was performed for the specified * period of time. Specify {@code 0} to disable. * @param allIdleTime * an {@link IdleStateEvent} whose state is {@link IdleState#ALL_IDLE} * will be triggered when neither read nor write was performed for * the specified period of time. Specify {@code 0} to disable. * @param unit * the {@link TimeUnit} of {@code readerIdleTime}, * {@code writeIdleTime}, and {@code allIdleTime} */ public IdleStateHandler( long readerIdleTime, long writerIdleTime, long allIdleTime, TimeUnit unit) { if (unit == null) { throw new NullPointerException("unit"); } if (readerIdleTime <= 0) { readerIdleTimeNanos = 0; } else { readerIdleTimeNanos = Math.max(unit.toNanos(readerIdleTime), MIN_TIMEOUT_NANOS); } if (writerIdleTime <= 0) { writerIdleTimeNanos = 0; } else { writerIdleTimeNanos = Math.max(unit.toNanos(writerIdleTime), MIN_TIMEOUT_NANOS); } if (allIdleTime <= 0) { allIdleTimeNanos = 0; } else { allIdleTimeNanos = Math.max(unit.toNanos(allIdleTime), MIN_TIMEOUT_NANOS); } } /** * Return the readerIdleTime that was given when instance this class in milliseconds. * */ public long getReaderIdleTimeInMillis() { return TimeUnit.NANOSECONDS.toMillis(readerIdleTimeNanos); } /** * Return the writerIdleTime that was given when instance this class in milliseconds. * */ public long getWriterIdleTimeInMillis() { return TimeUnit.NANOSECONDS.toMillis(writerIdleTimeNanos); } /** * Return the allIdleTime that was given when instance this class in milliseconds. * */ public long getAllIdleTimeInMillis() { return TimeUnit.NANOSECONDS.toMillis(allIdleTimeNanos); } @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { if (ctx.channel().isActive() && ctx.channel().isRegistered()) { // channelActvie() event has been fired already, which means this.channelActive() will // not be invoked. We have to initialize here instead. initialize(ctx); } else { // channelActive() event has not been fired yet. this.channelActive() will be invoked // and initialization will occur there. } } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { destroy(); } @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { // Initialize early if channel is active already. if (ctx.channel().isActive()) { initialize(ctx); } super.channelRegistered(ctx); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // This method will be invoked only if this handler was added // before channelActive() event is fired. If a user adds this handler // after the channelActive() event, initialize() will be called by beforeAdd(). initialize(ctx); super.channelActive(ctx); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { destroy(); super.channelInactive(ctx); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (readerIdleTimeNanos > 0 || allIdleTimeNanos > 0) { reading = true; firstReaderIdleEvent = firstAllIdleEvent = true; } ctx.fireChannelRead(msg); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { if (readerIdleTimeNanos > 0 || allIdleTimeNanos > 0) { lastReadTime = System.nanoTime(); reading = false; } ctx.fireChannelReadComplete(); } @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { // Allow writing with void promise if handler is only configured for read timeout events. if (writerIdleTimeNanos > 0 || allIdleTimeNanos > 0) { ChannelPromise unvoid = promise.unvoid(); unvoid.addListener(writeListener); ctx.write(msg, unvoid); } else { ctx.write(msg, promise); } } private void initialize(ChannelHandlerContext ctx) { // Avoid the case where destroy() is called before scheduling timeouts. // See: https://github.com/netty/netty/issues/143 switch (state) { case 1: case 2: return; } state = 1; EventExecutor loop = ctx.executor(); lastReadTime = lastWriteTime = System.nanoTime(); if (readerIdleTimeNanos > 0) { readerIdleTimeout = loop.schedule( new ReaderIdleTimeoutTask(ctx), readerIdleTimeNanos, TimeUnit.NANOSECONDS); } if (writerIdleTimeNanos > 0) { writerIdleTimeout = loop.schedule( new WriterIdleTimeoutTask(ctx), writerIdleTimeNanos, TimeUnit.NANOSECONDS); } if (allIdleTimeNanos > 0) { allIdleTimeout = loop.schedule( new AllIdleTimeoutTask(ctx), allIdleTimeNanos, TimeUnit.NANOSECONDS); } } private void destroy() { state = 2; if (readerIdleTimeout != null) { readerIdleTimeout.cancel(false); readerIdleTimeout = null; } if (writerIdleTimeout != null) { writerIdleTimeout.cancel(false); writerIdleTimeout = null; } if (allIdleTimeout != null) { allIdleTimeout.cancel(false); allIdleTimeout = null; } } /** * Is called when an {@link IdleStateEvent} should be fired. This implementation calls * {@link ChannelHandlerContext#fireUserEventTriggered(Object)}. */ protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception { ctx.fireUserEventTriggered(evt); } /** * Returns a {@link IdleStateEvent}. */ protected IdleStateEvent newIdleStateEvent(IdleState state, boolean first) { switch (state) { case ALL_IDLE: return first ? IdleStateEvent.FIRST_ALL_IDLE_STATE_EVENT : IdleStateEvent.ALL_IDLE_STATE_EVENT; case READER_IDLE: return first ? IdleStateEvent.FIRST_READER_IDLE_STATE_EVENT : IdleStateEvent.READER_IDLE_STATE_EVENT; case WRITER_IDLE: return first ? IdleStateEvent.FIRST_WRITER_IDLE_STATE_EVENT : IdleStateEvent.WRITER_IDLE_STATE_EVENT; default: throw new Error(); } } private final class ReaderIdleTimeoutTask implements Runnable { private final ChannelHandlerContext ctx; ReaderIdleTimeoutTask(ChannelHandlerContext ctx) { this.ctx = ctx; } @Override public void run() { if (!ctx.channel().isOpen()) { return; } long nextDelay = readerIdleTimeNanos; if (!reading) { nextDelay -= System.nanoTime() - lastReadTime; } if (nextDelay <= 0) { // Reader is idle - set a new timeout and notify the callback. readerIdleTimeout = ctx.executor().schedule(this, readerIdleTimeNanos, TimeUnit.NANOSECONDS); try { IdleStateEvent event = newIdleStateEvent(IdleState.READER_IDLE, firstReaderIdleEvent); if (firstReaderIdleEvent) { firstReaderIdleEvent = false; } channelIdle(ctx, event); } catch (Throwable t) { ctx.fireExceptionCaught(t); } } else { // Read occurred before the timeout - set a new timeout with shorter delay. readerIdleTimeout = ctx.executor().schedule(this, nextDelay, TimeUnit.NANOSECONDS); } } } private final class WriterIdleTimeoutTask implements Runnable { private final ChannelHandlerContext ctx; WriterIdleTimeoutTask(ChannelHandlerContext ctx) { this.ctx = ctx; } @Override public void run() { if (!ctx.channel().isOpen()) { return; } long lastWriteTime = IdleStateHandler.this.lastWriteTime; long nextDelay = writerIdleTimeNanos - (System.nanoTime() - lastWriteTime); if (nextDelay <= 0) { // Writer is idle - set a new timeout and notify the callback. writerIdleTimeout = ctx.executor().schedule( this, writerIdleTimeNanos, TimeUnit.NANOSECONDS); try { IdleStateEvent event = newIdleStateEvent(IdleState.WRITER_IDLE, firstWriterIdleEvent); if (firstWriterIdleEvent) { firstWriterIdleEvent = false; } channelIdle(ctx, event); } catch (Throwable t) { ctx.fireExceptionCaught(t); } } else { // Write occurred before the timeout - set a new timeout with shorter delay. writerIdleTimeout = ctx.executor().schedule(this, nextDelay, TimeUnit.NANOSECONDS); } } } private final class AllIdleTimeoutTask implements Runnable { private final ChannelHandlerContext ctx; AllIdleTimeoutTask(ChannelHandlerContext ctx) { this.ctx = ctx; } @Override public void run() { if (!ctx.channel().isOpen()) { return; } long nextDelay = allIdleTimeNanos; if (!reading) { nextDelay -= System.nanoTime() - Math.max(lastReadTime, lastWriteTime); } if (nextDelay <= 0) { // Both reader and writer are idle - set a new timeout and // notify the callback. allIdleTimeout = ctx.executor().schedule( this, allIdleTimeNanos, TimeUnit.NANOSECONDS); try { IdleStateEvent event = newIdleStateEvent(IdleState.ALL_IDLE, firstAllIdleEvent); if (firstAllIdleEvent) { firstAllIdleEvent = false; } channelIdle(ctx, event); } catch (Throwable t) { ctx.fireExceptionCaught(t); } } else { // Either read or write occurred before the timeout - set a new // timeout with shorter delay. allIdleTimeout = ctx.executor().schedule(this, nextDelay, TimeUnit.NANOSECONDS); } } } }

Other Java examples (source code examples)

Here is a short list of links related to this Java IdleStateHandler.java source code file:

Java example source code file (IdleStateHandler.java)

This example Java source code file (IdleStateHandler.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

allidletimeouttask, channelhandlercontext, channelpromise, exception, idlestateevent, idlestatehandler, min_timeout_nanos, object, override, readeridletimeouttask, runnable, scheduledfuture, threading, threads, throwable, writeridletimeouttask

The IdleStateHandler.java Java example source code

/*
 * 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 io.netty.handler.timeout;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.EventExecutor;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * Triggers an {@link IdleStateEvent} when a {@link Channel} has not performed
 * read, write, or both operation for a while.
 *
 * <h3>Supported idle states
 * <table border="1">
 * <tr>
 * <th>Property
Meaning
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.