View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.pool2;
19  
20  import java.time.Duration;
21  import java.util.concurrent.atomic.AtomicInteger;
22  
23  import org.apache.commons.lang3.ThreadUtils;
24  
25  /**
26   * <p>Object created by {@link WaiterFactory}. Maintains active / valid state,
27   * last passivated and idle times.  Waits with configurable latency when
28   * {@link #doWait()} method is called.</p>
29   *
30   * <p>This class is *not* threadsafe.</p>
31   */
32  public class Waiter {
33      private static final AtomicInteger instanceCount = new AtomicInteger();
34  
35      /**
36       * Sleeps for the given duration while ignoring {@link InterruptedException}.
37       * <p>
38       * The sleep duration may be shorter than duration if we catch a {@link InterruptedException}.
39       * </p>
40       *
41       * @param millis the length of time to sleep in milliseconds.
42       */
43      public static void sleepQuietly(final long millis) {
44          ThreadUtils.sleepQuietly(Duration.ofMillis(millis));
45      }
46  
47      private boolean active;
48      private boolean valid;
49      private long latency;
50      private long lastPassivatedMillis;
51      private long lastIdleTimeMillis;
52      private long passivationCount;
53      private long validationCount;
54  
55      private final int id = instanceCount.getAndIncrement();
56  
57      public Waiter(final boolean active, final boolean valid, final long latency) {
58          this.active = active;
59          this.valid = valid;
60          this.latency = latency;
61          this.lastPassivatedMillis = System.currentTimeMillis();
62      }
63  
64      /**
65       * Wait for {@link #getLatency()} milliseconds.
66       */
67      public void doWait() {
68          sleepQuietly(latency);
69      }
70  
71      @Override
72      public boolean equals(final Object obj) {
73          if (!(obj instanceof Waiter)) {
74              return false;
75          }
76          return obj.hashCode() == id;
77      }
78  
79      /**
80       * <p>Returns the last idle time for this instance in ms.</p>
81       *
82       * <p>When an instance is created, and each subsequent time it is passivated,
83       * the {@link #getLastPassivatedMillis() lastPassivated} property is updated with the
84       * current time.  When the next activation occurs, {@code lastIdleTime} is
85       * updated with the elapsed time since passivation.<p>
86       *
87       * @return last idle time
88       */
89      public long getLastIdleTimeMillis() {
90          return lastIdleTimeMillis;
91      }
92  
93      /**
94       * <p>Returns the system time of this instance's last passivation.</p>
95       *
96       * <p>When an instance is created, this field is initialized to the system time.</p>
97       *
98       * @return time of last passivation
99       */
100     public long getLastPassivatedMillis() {
101         return lastPassivatedMillis;
102     }
103 
104     public long getLatency() {
105         return latency;
106     }
107 
108     /**
109      * @return how many times this instance has been passivated
110      */
111     public long getPassivationCount() {
112         return passivationCount;
113     }
114 
115     /**
116      * @return how many times this instance has been validated
117      */
118     public long getValidationCount() {
119         return validationCount;
120     }
121 
122     @Override
123     public int hashCode() {
124         return id;
125     }
126 
127     /**
128      * Tests whether or not the instance is active.
129      *
130      * @return true if the last lifecycle event for this instance was activation.
131      */
132     public boolean isActive() {
133         return active;
134     }
135 
136     public boolean isValid() {
137         validationCount++;
138         return valid;
139     }
140 
141     /**
142      * <p>Sets the active state and updates {@link #getLastIdleTimeMillis() lastIdleTime}
143      * or {@link #getLastPassivatedMillis() lastPassivated} as appropriate.</p>
144      *
145      * <p>If the active state is changing from inactive to active, lastIdleTime
146      * is updated with the current time minus lastPassivated.  If the state is
147      * changing from active to inactive, lastPassivated is updated with the
148      * current time.</p>
149      *
150      * <p>{@link WaiterFactory#activateObject(PooledObject)} and
151      * {@link WaiterFactory#passivateObject(PooledObject)} invoke this method on
152      * their actual parameter, passing {@code true} and {@code false},
153      * respectively.</p>
154      *
155      * @param active new active state
156      */
157     public void setActive(final boolean active) {
158         final boolean activeState = this.active;
159         if (activeState == active) {
160             return;
161         }
162         this.active = active;
163         final long currentTimeMillis = System.currentTimeMillis();
164         if (active) {  // activating
165             lastIdleTimeMillis = currentTimeMillis - lastPassivatedMillis;
166         } else {       // passivating
167             lastPassivatedMillis = currentTimeMillis;
168             passivationCount++;
169         }
170     }
171 
172     public void setLatency(final long latency) {
173         this.latency = latency;
174     }
175 
176     public void setValid(final boolean valid) {
177         this.valid = valid;
178     }
179 
180     @Override
181     public String toString() {
182         final StringBuilder buff = new StringBuilder();
183         buff.append("ID = " + id + '\n');
184         buff.append("valid = " + valid + '\n');
185         buff.append("active = " + active + '\n');
186         buff.append("lastPassivated = " + lastPassivatedMillis + '\n');
187         buff.append("lastIdleTimeMs = " + lastIdleTimeMillis + '\n');
188         buff.append("latency = " + latency + '\n');
189         return buff.toString();
190     }
191 }