/******************************************************************************* * 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(); } } */ }