]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ua/AbstractState.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.utils.thread / src / org / simantics / utils / threads / ua / AbstractState.java
index 5f9631ea01fc70ee28c9e44b4c50b5ec0abdad1c..8ab4c632d2e7ce301eb66f641ee279d0bb8eaa6d 100644 (file)
-/*******************************************************************************\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
-package org.simantics.utils.threads.ua;\r
-\r
-import java.util.Set;\r
-import java.util.concurrent.CopyOnWriteArrayList;\r
-import java.util.concurrent.Executor;\r
-import java.util.concurrent.TimeUnit;\r
-import java.util.concurrent.TimeoutException;\r
-\r
-/**\r
- * This is a default implementation to {@link IStatefulObject}.\r
- * This class can be subclassed or used as it. \r
- * The state type is parametrized (typically an enumeration). \r
- * \r
- * TODO Remove locks - use spin set and test\r
- *\r
- * @see IStatefulObject\r
- * @see StateListener Listener for state modifications\r
- * @author Toni Kalajainen (toni.kalajainen@vtt.fi)\r
- * @param <StateType> \r
- * @param <ErrorType> \r
- */\r
-public abstract class AbstractState<StateType, ErrorType extends Throwable> implements IStatefulObject<StateType, ErrorType> {\r
-\r
-       /** Current state */\r
-       private StateType state = null;\r
-       /** Optional error state */\r
-       private StateType errorState = null;\r
-       /** Error cause */\r
-       private ErrorType errorCause;\r
-       \r
-       // Optimization for 1 listener, ListenerList is heavy //\r
-       private StateListener<StateType> firstListener = null; \r
-       private CopyOnWriteArrayList<StateListener<StateType>> listenerList = null;\r
-       private Object lock = new Object();\r
-       \r
-       public AbstractState(StateType initialState)\r
-       {\r
-               state = initialState;\r
-       }\r
-       \r
-       /**\r
-        * Creates a state with a error state. The state object goes to errorState on setError(). \r
-        * \r
-        * @param initialState\r
-        * @param errorState\r
-        */\r
-       public AbstractState(StateType initialState, StateType errorState)\r
-       {\r
-               state = initialState;\r
-               this.errorState = errorState;\r
-       }\r
-       \r
-       @Override\r
-       public synchronized StateType getState() {\r
-               return state;\r
-       }\r
-       \r
-       /**\r
-        * Attempts to change the state. The state will be changed only if current\r
-        * state is one of the expected states. \r
-        * \r
-        * @param prerequisiteState expected current state\r
-        * @param newState\r
-        * @return state after attempt\r
-        */\r
-       protected StateType attemptSetState(Set<StateType> prerequisiteState, StateType newState)\r
-       {\r
-               if (prerequisiteState==null || newState==null)\r
-                       throw new IllegalArgumentException("null arg");\r
-               return setState(newState, null, prerequisiteState);\r
-       }\r
-       \r
-       @Override\r
-       public synchronized void addStateListener(StateListener<StateType> listener) {\r
-               if (listener==null) \r
-                       throw new IllegalArgumentException("null arg");\r
-               if (listenerList!=null)\r
-               {\r
-                       listenerList.add(listener);\r
-                       return;\r
-               }\r
-               if (firstListener==null) {\r
-                       firstListener = listener;\r
-                       return;\r
-               }\r
-               \r
-               listenerList = new CopyOnWriteArrayList<StateListener<StateType>>();\r
-               listenerList.add(listener);\r
-       }\r
-\r
-       @Override\r
-       public void removeStateListener(StateListener<StateType> listener) {\r
-               if (listener==null) \r
-                       throw new IllegalArgumentException("null arg");\r
-               if (listenerList!=null) {\r
-                       listenerList.remove(listener);\r
-                       if (listenerList.isEmpty()) listenerList = null;\r
-                       return;\r
-               }\r
-               if (listener == firstListener) {\r
-                       firstListener = null;\r
-               }\r
-       }\r
-\r
-       protected boolean setState(StateType state)\r
-       {\r
-               return setState(state, null, null) == state;\r
-       }\r
-       \r
-       protected void setError(ErrorType error)\r
-       {\r
-               this.errorCause = error;\r
-               if (errorState==null || !setState(errorState))\r
-               {\r
-                       // wake up sleepers\r
-                       synchronized(lock) \r
-                       {\r
-                               lock.notifyAll();\r
-                       }\r
-               }\r
-       }\r
-       \r
-       protected void clearError()\r
-       {\r
-               errorCause = null;               \r
-       }\r
-       \r
-       public ErrorType getError()\r
-       {\r
-               return errorCause;\r
-       }\r
-       \r
-       public boolean hasError()\r
-       {\r
-               return errorCause!=null;\r
-       }\r
-       \r
-       protected void assertNoError()\r
-       throws ErrorType\r
-       {\r
-               ErrorType e = errorCause;               \r
-               if (e!=null)\r
-                       throw e;\r
-       }\r
-       \r
-       /**\r
-        * Set state\r
-        * \r
-        * @param state\r
-        * @param listenerExecutor executor for post listener handling or null for immediate\r
-        * @param prerequisiteStates old state prerequisite or null \r
-        * @return state after attempt\r
-        */\r
-       protected StateType setState(StateType state, Executor listenerExecutor, Set<StateType> prerequisiteStates)\r
-       {               \r
-               boolean hasListeners;\r
-               StateListener<StateType> fl = null;\r
-               StateType oldState = null;\r
-               StateType newState = null;\r
-               synchronized (this) {\r
-                       oldState = this.state;\r
-                       newState = state;\r
-                       if (oldState==newState) return state;\r
-                       if (prerequisiteStates!=null && !prerequisiteStates.contains(this.state))\r
-                               return state;\r
-                       if (!isStateTransitionAllowed(oldState, newState))\r
-                               return state;\r
-\r
-                       this.state = newState;\r
-                       fl = firstListener;\r
-                       hasListeners = fl!=null || (listenerList!=null && !listenerList.isEmpty());\r
-               }\r
-               final StateListener<StateType> fl_ = fl;\r
-               synchronized(lock) \r
-               {\r
-                       lock.notifyAll();\r
-               }\r
-               // Threads wake up here...\r
-               \r
-               // Handle listeners\r
-               onStateTransition(oldState, newState);\r
-               \r
-               if (hasListeners) {\r
-                       final StateType os = oldState;\r
-                       final StateType ns = newState;\r
-                       if (fl!=null) {\r
-                               if (listenerExecutor==null) {\r
-                                       try {\r
-                                               fl.onStateTransition(this, oldState, newState);\r
-                                       } catch (RuntimeException e) {\r
-                                               onListenerException(e);\r
-                                       }\r
-                               } else {\r
-                                       listenerExecutor.execute(new Runnable() {\r
-                                               @Override\r
-                                               public void run() {\r
-                                                       try {\r
-                                                               fl_.onStateTransition(AbstractState.this, os, ns);\r
-                                                       } catch (RuntimeException e) {\r
-                                                               onListenerException(e);\r
-                                                       }\r
-                                               }});\r
-                               }\r
-                       }\r
-                       if (listenerList!=null && !listenerList.isEmpty())\r
-                       for (final StateListener<StateType> sl : listenerList) {\r
-                               if (listenerExecutor==null) {\r
-                                       try {\r
-                                               sl.onStateTransition(this, oldState, newState);\r
-                                       } catch (RuntimeException e) {\r
-                                               onListenerException(e);\r
-                                       }\r
-                               } else {\r
-                                       listenerExecutor.execute(new Runnable() {\r
-                                               @Override\r
-                                               public void run() {\r
-                                                       try {\r
-                                                               sl.onStateTransition(AbstractState.this, os, ns);                                                       \r
-                                                       } catch (RuntimeException e) {\r
-                                                               onListenerException(e);\r
-                                                       }\r
-                                               }});\r
-                               }\r
-                       }\r
-               }\r
-               return state;\r
-       }\r
-       \r
-       /**\r
-        * Checks whether state transition is allowed.\r
-        * Override this\r
-        * \r
-        * @param oldState\r
-        * @param newState\r
-        * @return true if state transition is allowed\r
-        */\r
-       protected boolean isStateTransitionAllowed(StateType oldState, StateType newState)\r
-       {\r
-               return true;\r
-       }\r
-       \r
-       /**\r
-        * Override this.\r
-        * \r
-        * @param oldState\r
-        * @param newState\r
-        */\r
-       protected void onStateTransition(StateType oldState, StateType newState)\r
-       {               \r
-       }\r
-\r
-       @Override\r
-       public StateType waitForState(Set<StateType> set) \r
-       throws InterruptedException, ErrorType\r
-       {\r
-               // This impl makes unnecessary wakeups but is memory conservative               \r
-               synchronized(lock) {\r
-                       while (!set.contains(state))\r
-                               lock.wait();\r
-                       ErrorType e = getError();\r
-                       if (e!=null)\r
-                               throw e;\r
-                       return state;\r
-               }\r
-       }\r
-\r
-       public StateType waitForStateUninterruptibly(Set<StateType> set) \r
-       throws ErrorType\r
-       {\r
-               // This impl makes unnecessary wakeups but is memory conservative               \r
-               synchronized(lock) {\r
-                       while (!set.contains(state))\r
-                               try {\r
-                                       lock.wait();\r
-                               } catch (InterruptedException qwer) {}\r
-                       ErrorType e = getError();\r
-                       if (e!=null)\r
-                               throw e;\r
-                       return state;\r
-               }\r
-       }\r
-\r
-       @Override\r
-       public StateType waitForState(\r
-                       Set<StateType> set, \r
-                       long timeout,\r
-                       TimeUnit unit) \r
-       throws InterruptedException, TimeoutException, ErrorType {\r
-               long abortTime = System.currentTimeMillis() + unit.toMillis(timeout);\r
-               synchronized(lock) {\r
-                       while (!set.contains(state)) {\r
-                               long waitTime = System.currentTimeMillis() - abortTime;\r
-                               if (waitTime<0)\r
-                                       throw new TimeoutException("timeout");\r
-                               lock.wait(waitTime);\r
-                               ErrorType e = getError();\r
-                               if (e!=null)\r
-                                       throw e;\r
-                       }\r
-                       return state;\r
-               }               \r
-       }\r
-       \r
-       /**\r
-        * Override this.\r
-        * @param rte\r
-        */\r
-       protected void onListenerException(RuntimeException rte)\r
-       {\r
-               rte.printStackTrace();\r
-       }\r
-\r
-}\r
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+
+package org.simantics.utils.threads.ua;
+
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This is a default implementation to {@link IStatefulObject}.
+ * This class can be subclassed or used as it. 
+ * The state type is parametrized (typically an enumeration). 
+ * 
+ * TODO Remove locks - use spin set and test
+ *
+ * @see IStatefulObject
+ * @see StateListener Listener for state modifications
+ * @author Toni Kalajainen (toni.kalajainen@vtt.fi)
+ * @param <StateType> 
+ * @param <ErrorType> 
+ */
+public abstract class AbstractState<StateType, ErrorType extends Throwable> implements IStatefulObject<StateType, ErrorType> {
+
+       /** Current state */
+       private StateType state = null;
+       /** Optional error state */
+       private StateType errorState = null;
+       /** Error cause */
+       private ErrorType errorCause;
+       
+       // Optimization for 1 listener, ListenerList is heavy //
+       private StateListener<StateType> firstListener = null; 
+       private CopyOnWriteArrayList<StateListener<StateType>> listenerList = null;
+       private Object lock = new Object();
+       
+       public AbstractState(StateType initialState)
+       {
+               state = initialState;
+       }
+       
+       /**
+        * Creates a state with a error state. The state object goes to errorState on setError(). 
+        * 
+        * @param initialState
+        * @param errorState
+        */
+       public AbstractState(StateType initialState, StateType errorState)
+       {
+               state = initialState;
+               this.errorState = errorState;
+       }
+       
+       @Override
+       public synchronized StateType getState() {
+               return state;
+       }
+       
+       /**
+        * Attempts to change the state. The state will be changed only if current
+        * state is one of the expected states. 
+        * 
+        * @param prerequisiteState expected current state
+        * @param newState
+        * @return state after attempt
+        */
+       protected StateType attemptSetState(Set<StateType> prerequisiteState, StateType newState)
+       {
+               if (prerequisiteState==null || newState==null)
+                       throw new IllegalArgumentException("null arg");
+               return setState(newState, null, prerequisiteState);
+       }
+       
+       @Override
+       public synchronized void addStateListener(StateListener<StateType> listener) {
+               if (listener==null) 
+                       throw new IllegalArgumentException("null arg");
+               if (listenerList!=null)
+               {
+                       listenerList.add(listener);
+                       return;
+               }
+               if (firstListener==null) {
+                       firstListener = listener;
+                       return;
+               }
+               
+               listenerList = new CopyOnWriteArrayList<StateListener<StateType>>();
+               listenerList.add(listener);
+       }
+
+       @Override
+       public void removeStateListener(StateListener<StateType> listener) {
+               if (listener==null) 
+                       throw new IllegalArgumentException("null arg");
+               if (listenerList!=null) {
+                       listenerList.remove(listener);
+                       if (listenerList.isEmpty()) listenerList = null;
+                       return;
+               }
+               if (listener == firstListener) {
+                       firstListener = null;
+               }
+       }
+
+       protected boolean setState(StateType state)
+       {
+               return setState(state, null, null) == state;
+       }
+       
+       protected void setError(ErrorType error)
+       {
+               this.errorCause = error;
+               if (errorState==null || !setState(errorState))
+               {
+                       // wake up sleepers
+                       synchronized(lock) 
+                       {
+                               lock.notifyAll();
+                       }
+               }
+       }
+       
+       protected void clearError()
+       {
+               errorCause = null;               
+       }
+       
+       public ErrorType getError()
+       {
+               return errorCause;
+       }
+       
+       public boolean hasError()
+       {
+               return errorCause!=null;
+       }
+       
+       protected void assertNoError()
+       throws ErrorType
+       {
+               ErrorType e = errorCause;               
+               if (e!=null)
+                       throw e;
+       }
+       
+       /**
+        * Set state
+        * 
+        * @param state
+        * @param listenerExecutor executor for post listener handling or null for immediate
+        * @param prerequisiteStates old state prerequisite or null 
+        * @return state after attempt
+        */
+       protected StateType setState(StateType state, Executor listenerExecutor, Set<StateType> prerequisiteStates)
+       {               
+               boolean hasListeners;
+               StateListener<StateType> fl = null;
+               StateType oldState = null;
+               StateType newState = null;
+               synchronized (this) {
+                       oldState = this.state;
+                       newState = state;
+                       if (oldState==newState) return state;
+                       if (prerequisiteStates!=null && !prerequisiteStates.contains(this.state))
+                               return state;
+                       if (!isStateTransitionAllowed(oldState, newState))
+                               return state;
+
+                       this.state = newState;
+                       fl = firstListener;
+                       hasListeners = fl!=null || (listenerList!=null && !listenerList.isEmpty());
+               }
+               final StateListener<StateType> fl_ = fl;
+               synchronized(lock) 
+               {
+                       lock.notifyAll();
+               }
+               // Threads wake up here...
+               
+               // Handle listeners
+               onStateTransition(oldState, newState);
+               
+               if (hasListeners) {
+                       final StateType os = oldState;
+                       final StateType ns = newState;
+                       if (fl!=null) {
+                               if (listenerExecutor==null) {
+                                       try {
+                                               fl.onStateTransition(this, oldState, newState);
+                                       } catch (RuntimeException e) {
+                                               onListenerException(e);
+                                       }
+                               } else {
+                                       listenerExecutor.execute(new Runnable() {
+                                               @Override
+                                               public void run() {
+                                                       try {
+                                                               fl_.onStateTransition(AbstractState.this, os, ns);
+                                                       } catch (RuntimeException e) {
+                                                               onListenerException(e);
+                                                       }
+                                               }});
+                               }
+                       }
+                       if (listenerList!=null && !listenerList.isEmpty())
+                       for (final StateListener<StateType> sl : listenerList) {
+                               if (listenerExecutor==null) {
+                                       try {
+                                               sl.onStateTransition(this, oldState, newState);
+                                       } catch (RuntimeException e) {
+                                               onListenerException(e);
+                                       }
+                               } else {
+                                       listenerExecutor.execute(new Runnable() {
+                                               @Override
+                                               public void run() {
+                                                       try {
+                                                               sl.onStateTransition(AbstractState.this, os, ns);                                                       
+                                                       } catch (RuntimeException e) {
+                                                               onListenerException(e);
+                                                       }
+                                               }});
+                               }
+                       }
+               }
+               return state;
+       }
+       
+       /**
+        * Checks whether state transition is allowed.
+        * Override this
+        * 
+        * @param oldState
+        * @param newState
+        * @return true if state transition is allowed
+        */
+       protected boolean isStateTransitionAllowed(StateType oldState, StateType newState)
+       {
+               return true;
+       }
+       
+       /**
+        * Override this.
+        * 
+        * @param oldState
+        * @param newState
+        */
+       protected void onStateTransition(StateType oldState, StateType newState)
+       {               
+       }
+
+       @Override
+       public StateType waitForState(Set<StateType> set) 
+       throws InterruptedException, ErrorType
+       {
+               // This impl makes unnecessary wakeups but is memory conservative               
+               synchronized(lock) {
+                       while (!set.contains(state))
+                               lock.wait();
+                       ErrorType e = getError();
+                       if (e!=null)
+                               throw e;
+                       return state;
+               }
+       }
+
+       public StateType waitForStateUninterruptibly(Set<StateType> set) 
+       throws ErrorType
+       {
+               // This impl makes unnecessary wakeups but is memory conservative               
+               synchronized(lock) {
+                       while (!set.contains(state))
+                               try {
+                                       lock.wait();
+                               } catch (InterruptedException qwer) {}
+                       ErrorType e = getError();
+                       if (e!=null)
+                               throw e;
+                       return state;
+               }
+       }
+
+       @Override
+       public StateType waitForState(
+                       Set<StateType> set, 
+                       long timeout,
+                       TimeUnit unit) 
+       throws InterruptedException, TimeoutException, ErrorType {
+               long abortTime = System.currentTimeMillis() + unit.toMillis(timeout);
+               synchronized(lock) {
+                       while (!set.contains(state)) {
+                               long waitTime = System.currentTimeMillis() - abortTime;
+                               if (waitTime<0)
+                                       throw new TimeoutException("timeout");
+                               lock.wait(waitTime);
+                               ErrorType e = getError();
+                               if (e!=null)
+                                       throw e;
+                       }
+                       return state;
+               }               
+       }
+       
+       /**
+        * Override this.
+        * @param rte
+        */
+       protected void onListenerException(RuntimeException rte)
+       {
+               rte.printStackTrace();
+       }
+
+}