/*
* $Id$
*
* Copyright 2009 Glencoe Software, Inc. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*
*/
package omero.util;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
/**
* Container class for storing resources which should be cleaned up on close and
* periodically checked.
*
* Note: this class uses java.util.logging (JUL) rather than commons-logging
* since it may be used on the client-side. Any use server-side will have logs
* forwarded to log4j via slf4j.
*/
public class Resources {
/**
* Interface to be implemented by any object which wants to be managed by
* the {@link Resources} class.
*/
public interface Entry {
/**
* Called during each cycle. If it returns false or throws an exception,
* {@link #cleanup()} will be called on the instance, and it will be
* removed.
*/
boolean check();
/**
* Gives an {@link Entry} a chance to cleanup resources before it is
* removed from checking.
*/
void cleanup();
}
private static Logger log = Logger.getLogger(Resources.class.getName());
private final int sleeptime;
private final ScheduledFuture<?> future;
private final ScheduledExecutorService service;
private final List<Entry> stuff = new CopyOnWriteArrayList<Entry>();
/**
* As {@link Resources#Resources(int)} but specifies a 60 second sleep
* period between task execution.
*/
public Resources() {
this(60);
}
/**
* As {@link Resources#Resources(int, ScheduledExecutorService)} but uses a
* {@link Executors#newSingleThreadExecutor()}.
*/
public Resources(int sleeptimeSeconds) {
this(sleeptimeSeconds, Executors.newSingleThreadScheduledExecutor());
}
public Resources(int sleeptimeSeconds, ScheduledExecutorService service) {
this.sleeptime = sleeptimeSeconds;
this.service = service;
log.finest("Starting");
this.future = this.service.scheduleAtFixedRate(task(), 1, sleeptime, TimeUnit.SECONDS);
}
private Runnable task() {
return new Runnable() {
public void run() {
log.finest("Running checks...");
for (Entry entry : stuff) {
log.finest("Checking " + entry);
boolean success = true;
try {
success = entry.check();
} catch (Exception e) {
log.warning("Exception thrown by entry: "
+ e.getMessage());
success = false;
}
if (!success) {
remove(entry);
}
}
log.finest("Finished checks.");
}
};
}
public void add(Entry entry) {
if (entry == null) {
log.warning("Entry null");
return;
}
log.finest("Adding object " + entry);
stuff.add(entry);
}
public int size() {
return stuff.size();
}
public void cleanup() {
log.finest("Cleaning called");
for (Entry entry : stuff) {
remove(entry);
}
log.finest("Stopping");
// Cancel thread; allows current task to finish
future.cancel(false);
log.finest("Stopped");
}
public void remove(Entry entry) {
if (entry == null) {
log.warning("Entry null");
return;
}
log.finest("Cleaning " + entry);
try {
entry.cleanup();
} catch (Exception e) {
log.warning("Cleaning entry threw an exception" + e);
}
log.finest("Removing " + entry);
stuff.remove(entry);
}
}