/*
* Copyright 2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.rioproject.test.monitor;
import org.rioproject.test.TimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The class represents an object that can be used to wait for a condition to
* become true and stable.
*/
public class Waiter {
/**
* The logger used by this class.
*/
private static Logger logger = LoggerFactory.getLogger("org.rioproject.test");
/**
* The maximum timeout.
*/
private long maxTimeout = 180000;
/**
* The stability timeout.
*/
private long stabilityTimeout = 2000;
/**
* Constructs a <code>Waiter</code>.
*/
public Waiter() {
}
/**
* Waits for a given condition to become true and stable.
*
* @param condition the condition to wait for.
* @throws org.rioproject.test.TimeoutException if the wait times out (i.e. the maximum timeout
* has elapsed).
*/
public void waitFor(Condition condition) throws TimeoutException {
logger.info("Waiting for [" + condition.toString() + "] ...");
// This method is implemented as a state machine invoked once
// a second. An alternative is a fully event-driven state machine
// controlled by simultaneous timers and events
// (which seems unreasonably complex for now)
final long TIME_STEP = 1000;
final int WAIT = 0;
final int STABILITY_WAIT = 1;
int state = WAIT;
long maxTime = System.currentTimeMillis() + getMaxTimeout();
long stabilityTime = 0;
// State machine
while (true) {
long time = System.currentTimeMillis();
if (state == WAIT) {
if (condition.test()) { // -> STABILITY_WAIT
state = STABILITY_WAIT;
stabilityTime = time + getStabilityTimeout();
logger.info("Ensuring stable state ...");
} else if (time > maxTime) { // ERROR
throw new TimeoutException();
}
} else {
if (!condition.test()) { // -> WAIT
state = WAIT;
logger.info("Waiting again ...");
} else if (time > stabilityTime) { // SUCCESS
break;
} else if (time > maxTime) { // ERROR
throw new TimeoutException();
}
}
try {
Thread.sleep(TIME_STEP);
} catch (InterruptedException e) {
}
}
logger.info("Waiting for [" + condition.toString() + "] - OK");
}
/**
* Retrieves the maximum timeout. The default maximum timeout is 180000 (3
* minutes).
*
* @return the maximum timeout, in milliseconds.
*/
public long getMaxTimeout() {
return maxTimeout;
}
/**
* Sets the maximum timeout. The default maximum timeout is 180000 (3
* minutes).
*
* @param timeout the new maximum timeout, in milliseconds.
*/
public void setMaxTimeout(long timeout) {
maxTimeout = timeout;
}
/**
* Retrieves the stability timeout. The default stability timeout is 2000 (2
* seconds).
*
* @return the stability timeout, in milliseconds.
*/
public long getStabilityTimeout() {
return stabilityTimeout;
}
/**
* Sets the stability timeout. The default stability timeout is 2000 (2
* seconds).
*
* @param timeout the new stability timeout, in milliseconds.
*/
public void setStabilityTimeout(long timeout) {
stabilityTimeout = timeout;
}
}