/*
* @(#)ETSLADisposalStrategy.java
*
* Project: JHotdraw - a GUI framework for technical drawings
* http://www.jhotdraw.org
* http://jhotdraw.sourceforge.net
* Copyright: (c) by the original author(s) and all contributors
* License: Lesser GNU Public License (LGPL)
* http://www.opensource.org/licenses/lgpl-license.html
*/
package org.jhotdraw.contrib.html;
import java.util.Iterator;
/**
* ETSLADisposalStrategy implements an Ellapsed Time Since Last Access disposal
* strategy.<bt>
* It checks the last time a resource was accessed and if greater than
* the resource's disposalDelay it disposes of the resource so that it can
* be GCed.<br>
* Disposal activity must be explicitely started using the startDisposing method
*
* @author Eduardo Francos - InContext
* @created 2 mai 2002
* @version 1.0
*/
public class ETSLADisposalStrategy implements ResourceDisposabilityStrategy {
/** The associated resource manager */
private DisposableResourceManager manager;
/** The periodicity at wich disposal is checked */
private long gcPeriodicity = 60000;
/** the thread that calls this periodically */
private DisposalThread disposalThread = null;
/** True if disposal is active and running */
private boolean disposingActive = false;
/**
* Constructor for the ETSLADisposalStrategy object
*/
public ETSLADisposalStrategy() { }
/**
*Constructor for the ETSLADisposalStrategy object
*
* @param periodicity the periodicity at which to check for disposable resources
*/
public ETSLADisposalStrategy(long periodicity) {
this(null, periodicity);
}
/**
*Constructor for the ETSLADisposalStrategy object
*
* @param manager the manager
* @param periodicity the periodicity at which to check for disposable resources
*/
public ETSLADisposalStrategy(DisposableResourceManager newManager, long newPeriodicity) {
setManager(newManager);
setPeriodicity(newPeriodicity);
initDisposalThread();
}
/**
* Sets the manager holding the resources for this strategy
*
* @param manager The new manager value
*/
public synchronized void setManager(DisposableResourceManager newManager) {
// if new manager is null the stop disposing
if (getManager() == null) {
stopDisposing(Long.MAX_VALUE);
}
manager = newManager;
}
/**
* Gets the manager holding the resources for this strategy
*
* @return The manager value
*/
public DisposableResourceManager getManager() {
return manager;
}
/**
* Activates the strategy which starts disposing of resources as fitted
*
* @exception ResourceManagerNotSetException thrown if the manager has not
* been set, so impossible to run
*/
public void startDisposing() throws ResourceManagerNotSetException {
if (getManager() == null) {
throw new ResourceManagerNotSetException();
}
// do nothing if already active
if (disposingActive) {
return;
}
disposingActive = true;
disposalThread.start();
}
/**
* Deactivates the strategy that stops automatic disposal of resources.<br>
* The millis parameters specifies in milliseconds the time to wait for
* the disposal to stop. After this time the method returns, but the
* deactivation request remains active.
*
* @param millis time to wait for disposal to stop
*/
public void stopDisposing(long millis) {
// do nothing if not disposing
if (!disposingActive) {
return;
}
// request the thread to stop and wait for it
try {
disposalThread.interruptDisposalPending = true;
disposalThread.join(millis);
}
catch (InterruptedException ex) {
// ignore
}
finally {
disposingActive = false;
}
}
/**
* Initializes the disposal thread if not alrady done.
*/
protected void initDisposalThread() {
if (disposalThread != null) {
return;
}
disposalThread = new DisposalThread(this, getPeriodicity());
}
/**
* Dispose of all the resources whose dispose delay has expired and
* are not locked
*/
protected synchronized void dispose() {
synchronized (getManager()) {
long currentTime = System.currentTimeMillis();
Iterator resourceIter = getManager().getResources();
DisposableResourceHolder resource;
while (resourceIter.hasNext()) {
resource = (DisposableResourceHolder)resourceIter.next();
synchronized (resource) {
if (!resource.isLocked() && (resource.getLastTimeAccessed() + resource.getDisposableDelay()) < currentTime) {
resource.dispose();
}
}
}
}
}
/**
* Gets the periodicity attribute of the ETSLADisposalStrategy object
*
* @return The periodicity value
*/
public long getPeriodicity() {
return gcPeriodicity;
}
/**
* Sets the periodicity attribute of the ETSLADisposalStrategy object
*
* @param newPeriodicity The new periodicity value
*/
public void setPeriodicity(long newPeriodicity) {
gcPeriodicity = newPeriodicity;
if (disposalThread != null) {
disposalThread.setPeriodicity(newPeriodicity);
}
}
}
/**
* Description of the Class
*
* @author Eduardo Francos - InContext
* @created 2 mai 2002
*/
class DisposalThread extends Thread {
private ETSLADisposalStrategy strategy;
/** The periodicity at wich disposal is checked */
private long periodicity = 60000;
/** Description of the Field */
boolean interruptDisposalPending = false;
/**
*Constructor for the DisposalThread object
*
* @param strategy the strategy
* @param periodicity the periodicity at which the strategy should be called
*/
DisposalThread(ETSLADisposalStrategy newStrategy, long newPeriodicity) {
strategy = newStrategy;
periodicity = newPeriodicity;
}
/**
* Main processing method for the DisposalThread object
*/
public void run() {
interruptDisposalPending = false;
while (!interruptDisposalPending) {
try {
sleep(periodicity);
}
catch (Exception ex) {
// just exit
break;
}
strategy.dispose();
}
interruptDisposalPending = false;
}
/**
* Gets the periodicity attribute of the ETSLADisposalStrategy object
*
* @return The periodicity value
*/
public long getPeriodicity() {
return periodicity;
}
/**
* Sets the periodicity attribute of the ETSLADisposalStrategy object
*
* @param newPeriodicity The new periodicity value
*/
public void setPeriodicity(long newPeriodicity) {
periodicity = newPeriodicity;
}
/** Description of the Method */
public void interruptDisposal() {
interruptDisposalPending = true;
}
}