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 */
027package org.apache.http.pool;
028
029import org.apache.http.annotation.Contract;
030import org.apache.http.annotation.ThreadingBehavior;
031import org.apache.http.util.Args;
032
033import java.util.concurrent.TimeUnit;
034
035/**
036 * Pool entry containing a pool connection object along with its route.
037 * <p>
038 * The connection contained by the pool entry may have an expiration time which
039 * can be either set upon construction time or updated with
040 * the {@link #updateExpiry(long, TimeUnit)}.
041 * <p>
042 * Pool entry may also have an object associated with it that represents
043 * a connection state (usually a security principal or a unique token identifying
044 * the user whose credentials have been used while establishing the connection).
045 *
046 * @param <T> the route type that represents the opposite endpoint of a pooled
047 *   connection.
048 * @param <C> the connection type.
049 * @since 4.2
050 */
051@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
052public abstract class PoolEntry<T, C> {
053
054    private final String id;
055    private final T route;
056    private final C conn;
057    private final long created;
058    private final long validityDeadline;
059
060    private long updated;
061
062    private long expiry;
063
064    private volatile Object state;
065
066    /**
067     * Creates new {@code PoolEntry} instance.
068     *
069     * @param id unique identifier of the pool entry. May be {@code null}.
070     * @param route route to the opposite endpoint.
071     * @param conn the connection.
072     * @param timeToLive maximum time to live. May be zero if the connection
073     *   does not have an expiry deadline.
074     * @param tunit time unit.
075     */
076    public PoolEntry(final String id, final T route, final C conn,
077            final long timeToLive, final TimeUnit tunit) {
078        super();
079        Args.notNull(route, "Route");
080        Args.notNull(conn, "Connection");
081        Args.notNull(tunit, "Time unit");
082        this.id = id;
083        this.route = route;
084        this.conn = conn;
085        this.created = System.currentTimeMillis();
086        this.updated = this.created;
087        if (timeToLive > 0) {
088            final long deadline = this.created + tunit.toMillis(timeToLive);
089            // If the above overflows then default to Long.MAX_VALUE
090            this.validityDeadline = deadline > 0 ? deadline : Long.MAX_VALUE;
091        } else {
092            this.validityDeadline = Long.MAX_VALUE;
093        }
094        this.expiry = this.validityDeadline;
095    }
096
097    /**
098     * Creates new {@code PoolEntry} instance without an expiry deadline.
099     *
100     * @param id unique identifier of the pool entry. May be {@code null}.
101     * @param route route to the opposite endpoint.
102     * @param conn the connection.
103     */
104    public PoolEntry(final String id, final T route, final C conn) {
105        this(id, route, conn, 0, TimeUnit.MILLISECONDS);
106    }
107
108    public String getId() {
109        return this.id;
110    }
111
112    public T getRoute() {
113        return this.route;
114    }
115
116    public C getConnection() {
117        return this.conn;
118    }
119
120    public long getCreated() {
121        return this.created;
122    }
123
124    /**
125     * @since 4.4
126     */
127    public long getValidityDeadline() {
128        return this.validityDeadline;
129    }
130
131    /**
132     * @deprecated use {@link #getValidityDeadline()}
133     */
134    @Deprecated
135    public long getValidUnit() {
136        return this.validityDeadline;
137    }
138
139    public Object getState() {
140        return this.state;
141    }
142
143    public void setState(final Object state) {
144        this.state = state;
145    }
146
147    public synchronized long getUpdated() {
148        return this.updated;
149    }
150
151    public synchronized long getExpiry() {
152        return this.expiry;
153    }
154
155    public synchronized void updateExpiry(final long time, final TimeUnit tunit) {
156        Args.notNull(tunit, "Time unit");
157        this.updated = System.currentTimeMillis();
158        final long newExpiry;
159        if (time > 0) {
160            newExpiry = this.updated + tunit.toMillis(time);
161        } else {
162            newExpiry = Long.MAX_VALUE;
163        }
164        this.expiry = Math.min(newExpiry, this.validityDeadline);
165    }
166
167    public synchronized boolean isExpired(final long now) {
168        return now >= this.expiry;
169    }
170
171    /**
172     * Invalidates the pool entry and closes the pooled connection associated
173     * with it.
174     */
175    public abstract void close();
176
177    /**
178     * Returns {@code true} if the pool entry has been invalidated.
179     */
180    public abstract boolean isClosed();
181
182    @Override
183    public String toString() {
184        final StringBuilder buffer = new StringBuilder();
185        buffer.append("[id:");
186        buffer.append(this.id);
187        buffer.append("][route:");
188        buffer.append(this.route);
189        buffer.append("][state:");
190        buffer.append(this.state);
191        buffer.append("]");
192        return buffer.toString();
193    }
194
195}