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