/**
*
*/
package com.trendrr.oss.concurrent;
import java.util.Date;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* An object that will be lazily initialized, and reinitialize every X millis
*
*
* @author Dustin Norlander
* @created Dec 6, 2010
*
*/
public abstract class ReinitObject<T> implements Initializer<T>{
protected static Log log = LogFactory.getLog(ReinitObject.class);
private PeriodicLock lock = null;
private AtomicReference<T> ref = new AtomicReference<T>();
private boolean usePreviousIfNull = false;
public ReinitObject(long millisBetweenInit) {
lock = new PeriodicLock(0, millisBetweenInit);
}
/**
*
* @param millisBetweenInit
* @param usePreviousIfNull if init returns null should we use the old result?
*/
public ReinitObject(long millisBetweenInit, boolean usePreviousIfNull) {
lock = new PeriodicLock(0, millisBetweenInit);
this.usePreviousIfNull = usePreviousIfNull;
}
public T get() {
if (ref.get() == null) {
//we block if the object is unitialized. otherwise we skip while initia
if (lock.lockOrWait()) {
try {
if (ref.get() == null) { //check again
ref.set(this.init());
}
} finally {
lock.unlock();
}
}
} else {
// else we return the old results while the new ones are being initialized
if (lock.lockOrSkip()) {
T old = null;
try {
T val = this.init();
if (val != null || !this.usePreviousIfNull) {
old = this.ref.get();
ref.set(val);
} else {
// log.info("Skipping cause this init is null");
}
} finally {
lock.unlock();
}
//cleanup outside the lock.
if (old != null) {
this.cleanup(old);
}
}
}
return ref.get();
}
/**
* This is called when the object is reinitialized. allows to cleanup any resources.
* @param object
*/
public void cleanup(T object) {
}
/**
* passively looks to see if this object needs to be re-initialized
* @return
*/
public boolean isExpired() {
return lock.getNextUnlock().getTime() < new Date().getTime();
}
/**
* clears the initialized object if it is expired.
*/
public void clearIfExpired() {
if (lock.lockOrWait()) {
try {
ref.set(null);
} finally {
lock.unlock();
}
}
lock.lockUntil(new Date());
}
}