X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.utils.datastructures%2Fsrc%2Forg%2Fsimantics%2Futils%2Fdatastructures%2Fdisposable%2FAbstractDisposable.java;fp=bundles%2Forg.simantics.utils.datastructures%2Fsrc%2Forg%2Fsimantics%2Futils%2Fdatastructures%2Fdisposable%2FAbstractDisposable.java;h=745e8f0a79fd49739a9cb84f900f1ac5a5def861;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/disposable/AbstractDisposable.java b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/disposable/AbstractDisposable.java new file mode 100644 index 000000000..745e8f0a7 --- /dev/null +++ b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/disposable/AbstractDisposable.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * 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(); + } + } + */ + +}