001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.impl.client;
029
030import java.util.concurrent.ThreadFactory;
031import java.util.concurrent.TimeUnit;
032
033import org.apache.http.conn.HttpClientConnectionManager;
034import org.apache.http.util.Args;
035
036/**
037 * This class maintains a background thread to enforce an eviction policy for expired / idle
038 * persistent connections kept alive in the connection pool.
039 *
040 * @since 4.4
041 */
042public final class IdleConnectionEvictor {
043
044    private final HttpClientConnectionManager connectionManager;
045    private final ThreadFactory threadFactory;
046    private final Thread thread;
047    private final long sleepTimeMs;
048    private final long maxIdleTimeMs;
049
050    private volatile Exception exception;
051
052    public IdleConnectionEvictor(
053            final HttpClientConnectionManager connectionManager,
054            final ThreadFactory threadFactory,
055            final long sleepTime, final TimeUnit sleepTimeUnit,
056            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
057        this.connectionManager = Args.notNull(connectionManager, "Connection manager");
058        this.threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory();
059        this.sleepTimeMs = sleepTimeUnit != null ? sleepTimeUnit.toMillis(sleepTime) : sleepTime;
060        this.maxIdleTimeMs = maxIdleTimeUnit != null ? maxIdleTimeUnit.toMillis(maxIdleTime) : maxIdleTime;
061        this.thread = this.threadFactory.newThread(new Runnable() {
062            @Override
063            public void run() {
064                try {
065                    while (!Thread.currentThread().isInterrupted()) {
066                        Thread.sleep(sleepTimeMs);
067                        connectionManager.closeExpiredConnections();
068                        if (maxIdleTimeMs > 0) {
069                            connectionManager.closeIdleConnections(maxIdleTimeMs, TimeUnit.MILLISECONDS);
070                        }
071                    }
072                } catch (final Exception ex) {
073                    exception = ex;
074                }
075
076            }
077        });
078    }
079
080    public IdleConnectionEvictor(
081            final HttpClientConnectionManager connectionManager,
082            final long sleepTime, final TimeUnit sleepTimeUnit,
083            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
084        this(connectionManager, null, sleepTime, sleepTimeUnit, maxIdleTime, maxIdleTimeUnit);
085    }
086
087    public IdleConnectionEvictor(
088            final HttpClientConnectionManager connectionManager,
089            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
090        this(connectionManager, null,
091                maxIdleTime > 0 ? maxIdleTime : 5, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS,
092                maxIdleTime, maxIdleTimeUnit);
093    }
094
095    public void start() {
096        thread.start();
097    }
098
099    public void shutdown() {
100        thread.interrupt();
101    }
102
103    public boolean isRunning() {
104        return thread.isAlive();
105    }
106
107    public void awaitTermination(final long time, final TimeUnit tunit) throws InterruptedException {
108        thread.join((tunit != null ? tunit : TimeUnit.MILLISECONDS).toMillis(time));
109    }
110
111    static class DefaultThreadFactory implements ThreadFactory {
112
113        @Override
114        public Thread newThread(final Runnable r) {
115            final Thread t = new Thread(r, "Connection evictor");
116            t.setDaemon(true);
117            return t;
118        }
119
120    };
121
122
123}