/*******************************************************************************
* Copyright (c) 2007, 2010 Association for Decentralized Information Management
* in Industry THTH ry.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VTT Technical Research Centre of Finland - initial API and implementation
*******************************************************************************/
/*
*
* @author Toni Kalajainen
*/
package org.simantics.utils.datastructures.disposable;
import java.lang.reflect.Method;
import org.simantics.utils.threads.IThreadWorkQueue;
import org.simantics.utils.threads.SyncListenerList;
/**
* Base implementation of IDisposable. The subclass must implement doDispose()
* method. It invoked at once in first dispose call. Subsequent calls to dispose
* throws an AssertionError.
*
* assertNotDisposed() ensures that the object has not beed disposed. If so,
* AssertionError is thrown. assertNotDisposed() should be installed in all
* public methods of subclass.
*
* Object is disposed in finalize, if dispose has not been invoked explicitely.
*/
public abstract class AbstractDisposable implements IDisposable {
SyncListenerList disposeListeners = null;
private DisposeState disposeStatus = DisposeState.Alive;
protected void assertNotDisposed() {
if (isDisposed())
throw new AssertionError(this + " is disposed.");
}
@Override
public DisposeState getDisposeState() {
return disposeStatus;
}
public boolean isDisposed() {
return disposeStatus == DisposeState.Disposed;
}
public boolean isAlive() {
return disposeStatus == DisposeState.Alive;
}
@Override
public void dispose() {
try {
synchronized (this) {
if (disposeStatus == DisposeState.Disposing)
return;
assertNotDisposed();
disposeStatus = DisposeState.Disposing;
}
try {
fireDisposed();
} finally {
doDispose();
}
} finally {
synchronized(this) {
disposeStatus = DisposeState.Disposed;
}
}
}
/**
* Disposes if not disposed
*/
public void safeDispose() {
try {
synchronized (this) {
if (disposeStatus != DisposeState.Alive)
return;
disposeStatus = DisposeState.Disposing;
}
try {
fireDisposed();
} finally {
doDispose();
}
} finally {
synchronized(this) {
disposeStatus = DisposeState.Disposed;
}
}
}
/**
* Do dispose procedures. This method is invoked at most once.
*/
protected abstract void doDispose();
protected boolean hasDisposeListeners() {
return disposeListeners!=null && !disposeListeners.isEmpty();
}
private final static Method onDisposed = SyncListenerList.getMethod(IDisposeListener.class, "onDisposed");
private void fireDisposed() {
if (disposeListeners==null) return;
disposeListeners.fireEventSync(onDisposed, this);
}
@SuppressWarnings("unused")
private void fireDisposedAsync() {
if (disposeListeners==null) return;
disposeListeners.fireEventAsync(onDisposed, this);
}
@Override
public void addDisposeListener(IDisposeListener listener) {
lazyGetListenerList().add(listener);
}
@Override
public void addDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
lazyGetListenerList().add(thread, listener);
}
@Override
public void removeDisposeListener(IDisposeListener listener) {
if (disposeListeners==null) return;
disposeListeners.remove(listener);
}
@Override
public void removeDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
if (disposeListeners==null) return;
disposeListeners.remove(thread, listener);
}
private synchronized SyncListenerList lazyGetListenerList()
{
if (disposeListeners==null)
disposeListeners = new SyncListenerList(IDisposeListener.class);
return disposeListeners;
}
/*
@Override
protected void finalize() throws Throwable {
try {
safeDispose();
} finally {
super.finalize();
}
}
*/
}