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 * http://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.util.concurrent.atomic.AtomicInteger;
21
22 /**
23 * <p>Object created by {@link WaiterFactory}. Maintains active / valid state,
24 * last passivated and idle times. Waits with configurable latency when
25 * {@link #doWait()} method is called.</p>
26 *
27 * <p>This class is *not* threadsafe.</p>
28 */
29 public class Waiter {
30 private static final AtomicInteger instanceCount = new AtomicInteger();
31 /** TODO Reuse Apache Commons Lang ThreadUtils */
32 public static void sleepQuietly(final long millis) {
33 try {
34 Thread.sleep(millis);
35 } catch (final InterruptedException e) {
36 // be quiet
37 }
38 }
39 private boolean active;
40 private boolean valid;
41 private long latency;
42 private long lastPassivatedMillis;
43 private long lastIdleTimeMillis;
44 private long passivationCount;
45 private long validationCount;
46
47 private final int id = instanceCount.getAndIncrement();
48
49 public Waiter(final boolean active, final boolean valid, final long latency) {
50 this.active = active;
51 this.valid = valid;
52 this.latency = latency;
53 this.lastPassivatedMillis = System.currentTimeMillis();
54 }
55
56 /**
57 * Wait for {@link #getLatency()} milliseconds.
58 */
59 public void doWait() {
60 sleepQuietly(latency);
61 }
62
63 @Override
64 public boolean equals(final Object obj) {
65 if (!(obj instanceof Waiter)) {
66 return false;
67 }
68 return obj.hashCode() == id;
69 }
70
71 /**
72 * <p>Returns the last idle time for this instance in ms.</p>
73 *
74 * <p>When an instance is created, and each subsequent time it is passivated,
75 * the {@link #getLastPassivatedMillis() lastPassivated} property is updated with the
76 * current time. When the next activation occurs, {@code lastIdleTime} is
77 * updated with the elapsed time since passivation.<p>
78 *
79 * @return last idle time
80 */
81 public long getLastIdleTimeMillis() {
82 return lastIdleTimeMillis;
83 }
84
85 /**
86 * <p>Returns the system time of this instance's last passivation.</p>
87 *
88 * <p>When an instance is created, this field is initialized to the system time.</p>
89 *
90 * @return time of last passivation
91 */
92 public long getLastPassivatedMillis() {
93 return lastPassivatedMillis;
94 }
95
96 public long getLatency() {
97 return latency;
98 }
99
100 /**
101 * @return how many times this instance has been passivated
102 */
103 public long getPassivationCount() {
104 return passivationCount;
105 }
106
107 /**
108 * @return how many times this instance has been validated
109 */
110 public long getValidationCount() {
111 return validationCount;
112 }
113
114 @Override
115 public int hashCode() {
116 return id;
117 }
118
119 /**
120 * Whether or not the instance is active.
121 *
122 * @return true if the last lifecycle event for this instance was activation.
123 */
124 public boolean isActive() {
125 return active;
126 }
127
128 public boolean isValid() {
129 validationCount++;
130 return valid;
131 }
132
133 /**
134 * <p>Sets the active state and updates {@link #getLastIdleTimeMillis() lastIdleTime}
135 * or {@link #getLastPassivatedMillis() lastPassivated} as appropriate.</p>
136 *
137 * <p>If the active state is changing from inactive to active, lastIdleTime
138 * is updated with the current time minus lastPassivated. If the state is
139 * changing from active to inactive, lastPassivated is updated with the
140 * current time.</p>
141 *
142 * <p>{@link WaiterFactory#activateObject(PooledObject)} and
143 * {@link WaiterFactory#passivateObject(PooledObject)} invoke this method on
144 * their actual parameter, passing {@code true} and {@code false},
145 * respectively.</p>
146 *
147 * @param active new active state
148 */
149 public void setActive(final boolean active) {
150 final boolean activeState = this.active;
151 if (activeState == active) {
152 return;
153 }
154 this.active = active;
155 final long currentTimeMillis = System.currentTimeMillis();
156 if (active) { // activating
157 lastIdleTimeMillis = currentTimeMillis - lastPassivatedMillis;
158 } else { // passivating
159 lastPassivatedMillis = currentTimeMillis;
160 passivationCount++;
161 }
162 }
163
164 public void setLatency(final long latency) {
165 this.latency = latency;
166 }
167
168 public void setValid(final boolean valid) {
169 this.valid = valid;
170 }
171
172 @Override
173 public String toString() {
174 final StringBuilder buff = new StringBuilder();
175 buff.append("ID = " + id + '\n');
176 buff.append("valid = " + valid + '\n');
177 buff.append("active = " + active + '\n');
178 buff.append("lastPassivated = " + lastPassivatedMillis + '\n');
179 buff.append("lastIdleTimeMs = " + lastIdleTimeMillis + '\n');
180 buff.append("latency = " + latency + '\n');
181 return buff.toString();
182 }
183 }