/*
 * Copyright (c) 2009, 2017 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.grizzly.utils;

import org.glassfish.grizzly.Connection;
import org.glassfish.grizzly.Grizzly;
import org.glassfish.grizzly.attributes.Attribute;
import org.glassfish.grizzly.filterchain.BaseFilter;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

Filter, which determines silent connections and closes them. The silent connection is a connection, which didn't send/receive any byte since it was accepted during specified period of time.
Author:Alexey Stashok
/** * Filter, which determines silent connections and closes them. * The silent connection is a connection, which didn't send/receive any byte * since it was accepted during specified period of time. * * @author Alexey Stashok */
public final class SilentConnectionFilter extends BaseFilter { private static final Logger LOGGER = Grizzly.logger(SilentConnectionFilter.class); public static final long UNLIMITED_TIMEOUT = -1; public static final long UNSET_TIMEOUT = 0; private static final String ATTR_NAME = SilentConnectionFilter.class.getName() + ".silent-connection-attr"; private static final Attribute<Long> silentConnectionAttr = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(ATTR_NAME); private final long timeoutMillis; private final DelayedExecutor.DelayQueue<Connection> queue; public SilentConnectionFilter(DelayedExecutor executor, long timeout, TimeUnit timeunit) { this.timeoutMillis = TimeUnit.MILLISECONDS.convert(timeout, timeunit); queue = executor.createDelayQueue( new DelayedExecutor.Worker<Connection>() { @Override public boolean doWork(Connection connection) { connection.closeSilently(); return true; } }, new Resolver()); } public long getTimeout(TimeUnit timeunit) { return timeunit.convert(timeoutMillis, TimeUnit.MILLISECONDS); } @Override public NextAction handleAccept(FilterChainContext ctx) throws IOException { final Connection connection = ctx.getConnection(); queue.add(connection, timeoutMillis, TimeUnit.MILLISECONDS); return ctx.getInvokeAction(); } @Override public NextAction handleRead(FilterChainContext ctx) throws IOException { final Connection connection = ctx.getConnection(); queue.remove(connection); return ctx.getInvokeAction(); } @Override public NextAction handleWrite(FilterChainContext ctx) throws IOException { final Connection connection = ctx.getConnection(); queue.remove(connection); return ctx.getInvokeAction(); } @Override public NextAction handleClose(FilterChainContext ctx) throws IOException { queue.remove(ctx.getConnection()); return ctx.getInvokeAction(); } private static final class Resolver implements DelayedExecutor.Resolver<Connection> { @Override public boolean removeTimeout(Connection connection) { return silentConnectionAttr.remove(connection) != null; } @Override public long getTimeoutMillis(Connection connection) { final Long timeout = silentConnectionAttr.get(connection); return timeout != null ? timeout : DelayedExecutor.UNSET_TIMEOUT; } @Override public void setTimeoutMillis(Connection connection, long timeoutMillis) { silentConnectionAttr.set(connection, timeoutMillis); } } }