View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.core5.pool;
28  
29  import java.util.concurrent.atomic.AtomicReference;
30  
31  import org.apache.hc.core5.function.Supplier;
32  import org.apache.hc.core5.io.GracefullyCloseable;
33  import org.apache.hc.core5.io.ShutdownType;
34  import org.apache.hc.core5.util.Args;
35  import org.apache.hc.core5.util.TimeValue;
36  
37  /**
38   * Pool entry containing a pool connection object along with its route.
39   * <p>
40   * The connection assigned to this pool entry may have an expiration time and also have an object
41   * representing a connection state (usually a security principal or a unique token identifying
42   * the user whose credentials have been used while establishing the connection).
43   *
44   * @param <T> the route type that represents the opposite endpoint of a pooled
45   *   connection.
46   * @param <C> the connection type.
47   * @since 4.2
48   */
49  public final class PoolEntry<T, C extends GracefullyCloseable> {
50  
51      private final T route;
52      private final TimeValue timeToLive;
53      private final AtomicReference<C> connRef;
54  
55      private volatile Object state;
56      private volatile long created;
57      private volatile long updated;
58      private volatile long expiry;
59      private volatile long validityDeadline;
60      private Supplier<Long> currentTimeSupplier;
61  
62      PoolEntry(final T route, final TimeValue timeToLive, final Supplier<Long> currentTimeSupplier) {
63          super();
64          this.route = Args.notNull(route, "Route");
65          this.timeToLive = TimeValue.defaultsToNegativeOneMillisecond(timeToLive);
66          this.connRef = new AtomicReference<>(null);
67          this.currentTimeSupplier = currentTimeSupplier;
68      }
69  
70      long getCurrentTime() {
71          return currentTimeSupplier != null ? currentTimeSupplier.get() : System.currentTimeMillis();
72      }
73  
74      /**
75       * Creates new {@code PoolEntry} instance.
76       *
77       * @param route route to the opposite endpoint.
78       * @param timeToLive maximum time to live. May be zero if the connection
79       *   does not have an expiry deadline.
80       */
81      public PoolEntry(final T route, final TimeValue timeToLive) {
82          this(route, timeToLive, null);
83      }
84  
85      public PoolEntry(final T route) {
86          this(route, null);
87      }
88  
89      public T getRoute() {
90          return this.route;
91      }
92  
93      public C getConnection() {
94          return this.connRef.get();
95      }
96  
97      /**
98       * @since 4.4
99       */
100     public long getValidityDeadline() {
101         return this.validityDeadline;
102     }
103 
104     public Object getState() {
105         return this.state;
106     }
107 
108     public long getUpdated() {
109         return this.updated;
110     }
111 
112     public long getExpiry() {
113         return this.expiry;
114     }
115 
116     /**
117      * @since 5.0
118      */
119     public boolean hasConnection() {
120         return this.connRef.get() != null;
121     }
122 
123     /**
124      * @since 5.0
125      */
126     public void assignConnection(final C conn) {
127         Args.notNull(conn, "connection");
128         if (this.connRef.compareAndSet(null, conn)) {
129             this.created = getCurrentTime();
130             this.updated = this.created;
131             this.validityDeadline = TimeValue.calculateDeadline(this.created, this.timeToLive);
132             this.expiry = this.validityDeadline;
133             this.state = null;
134         } else {
135             throw new IllegalStateException("Connection already assigned");
136         }
137     }
138 
139     /**
140      * @since 5.0
141      */
142     public void discardConnection(final ShutdownType shutdownType) {
143         final C connection = this.connRef.getAndSet(null);
144         if (connection != null) {
145             this.state = null;
146             this.created = 0;
147             this.updated = 0;
148             this.expiry = 0;
149             this.validityDeadline = 0;
150             connection.shutdown(shutdownType);
151         }
152     }
153 
154     /**
155      * @since 5.0
156      */
157     public void updateExpiry(final TimeValue expiryTime) {
158         Args.notNull(expiryTime, "Expiry time");
159         final long currentTime = getCurrentTime();
160         final long newExpiry = TimeValue.calculateDeadline(currentTime, expiryTime);
161         this.expiry = Math.min(newExpiry, this.validityDeadline);
162         this.updated = currentTime;
163     }
164 
165     /**
166      * @since 5.0
167      */
168     public void updateState(final Object state) {
169         this.state = state;
170         this.updated = getCurrentTime();
171     }
172 
173     @Override
174     public String toString() {
175         final StringBuilder buffer = new StringBuilder();
176         buffer.append("[route:");
177         buffer.append(this.route);
178         buffer.append("][state:");
179         buffer.append(this.state);
180         buffer.append("]");
181         return buffer.toString();
182     }
183 
184 }