]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/SyncListenerList.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.utils.thread / src / org / simantics / utils / threads / SyncListenerList.java
index 17a158e2bf803f96078291aa22dce5d3175ae1bb..2b643ee32643b149fbb36a46982d0f3831d6e58d 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
- *\r
- * @author Toni Kalajainen\r
- */\r
-package org.simantics.utils.threads;\r
-\r
-import java.lang.reflect.InvocationTargetException;\r
-import java.lang.reflect.Method;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Map.Entry;\r
-\r
-import org.simantics.utils.threads.internal.ListenerList;\r
-\r
-/**\r
- * \r
- * @author Toni Kalajainen\r
- *\r
- * @see ListenerList Simple listener list\r
- *\r
- * @param <T>\r
- */\r
-public class SyncListenerList<T> {\r
-\r
-       /** internal use */\r
-       Map<IThreadWorkQueue, ListenerList<T>> lists =\r
-               new HashMap<IThreadWorkQueue, ListenerList<T>>(2);\r
-               \r
-       /** Snapshot version */\r
-       Map<IThreadWorkQueue, T[]> snapshot;\r
-       \r
-       Boolean requiresThreadSwitching = Boolean.FALSE;\r
-               \r
-    /** \r
-     * The class of T\r
-     */\r
-    private final Class<T> componentType;      \r
-       \r
-       @SuppressWarnings("unchecked")\r
-       public SyncListenerList(Class<?> componentType)\r
-       {\r
-        this.componentType = (Class<T>) componentType;         \r
-       }\r
-       \r
-       /**\r
-        * Add listener to the list\r
-        * @param thread thread to use to handle the event\r
-        * @param listener\r
-        */\r
-    public synchronized void add(IThreadWorkQueue thread, T listener)\r
-    {\r
-       if (listener==null)\r
-               throw new IllegalArgumentException("null");\r
-       \r
-       snapshot = null;\r
-       ListenerList<T> list = lists.get(thread);\r
-       if (list==null) {\r
-               list = new ListenerList<T>(componentType);\r
-               lists.put(thread, list);\r
-       }\r
-       list.add(listener);\r
-       if (thread!=CurrentThread.getThreadAccess())\r
-               requiresThreadSwitching = Boolean.TRUE;\r
-    }\r
-    \r
-    /**\r
-     * Contains elements that require thread switching.\r
-     * @return true if contains elements with thread access other than current thread\r
-     */\r
-    public synchronized Boolean containsContextSwitchingListeners() {\r
-       if (requiresThreadSwitching==null)\r
-               requiresThreadSwitching = _HasContextSwitching();\r
-       return requiresThreadSwitching;\r
-    }\r
-        \r
-    /**\r
-     * \r
-     * @return true if contains listeners that require context switching\r
-     */\r
-    private boolean _HasContextSwitching()\r
-    {\r
-       if (lists.size()!=0) return false;\r
-       if (lists.size()>1) return false;\r
-       Entry<IThreadWorkQueue, ListenerList<T>> e = lists.entrySet().iterator().next();\r
-       if (e.getKey()!=CurrentThread.getThreadAccess()) return false;\r
-       return !e.getValue().isEmpty();\r
-    }\r
-\r
-    /**\r
-     * Add listener to the list. Listener will be invoked in the thread that\r
-     * happens to be running at the time of events.\r
-     * \r
-     * @param listener\r
-     */\r
-    public void add(T listener)\r
-    {\r
-       if (listener==null)\r
-               throw new IllegalArgumentException("null");\r
-       add(CurrentThread.getThreadAccess(), listener);\r
-    }\r
-\r
-       /**\r
-        * Remove listener from the list\r
-        * @param thread thread to use to handle the event\r
-        * @param listener\r
-        */\r
-    public synchronized void remove(IThreadWorkQueue thread, T listener)\r
-    {\r
-       snapshot = null;\r
-       ListenerList<T> list = lists.get(thread);\r
-       if (list==null) return;\r
-       list.remove(listener);\r
-       if (list.isEmpty())\r
-               lists.remove(thread);\r
-       if (isEmpty()) {\r
-               requiresThreadSwitching = Boolean.FALSE;\r
-               return;\r
-       }\r
-       if (requiresThreadSwitching==null) return;      \r
-       if (!requiresThreadSwitching) return;\r
-       if (thread==CurrentThread.getThreadAccess()) return;\r
-       requiresThreadSwitching = null;\r
-    }\r
-\r
-    public void remove(T listener)\r
-    {\r
-       remove(CurrentThread.getThreadAccess(), listener);\r
-    }\r
-    \r
-    public synchronized boolean isEmpty()\r
-    {\r
-        return lists.size()==0;\r
-    }\r
-    \r
-    public synchronized void clear()\r
-    {\r
-       requiresThreadSwitching = Boolean.FALSE;\r
-        lists.clear();\r
-        snapshot = null;\r
-    }\r
-        \r
-    \r
-    public synchronized Map<IThreadWorkQueue, T[]> getSnapshot()\r
-    {\r
-       if (snapshot==null) {\r
-               snapshot = new HashMap<IThreadWorkQueue, T[]>(lists.size());\r
-               for (Entry<IThreadWorkQueue, ListenerList<T>> e : lists.entrySet())\r
-               {\r
-                       T[] list = e.getValue().getListeners();\r
-                       snapshot.put(e.getKey(), list);\r
-               }\r
-       }\r
-       return snapshot;\r
-    }\r
-\r
-    public void fireEventAsync(final Method m, final Object ... args)\r
-    {\r
-       if (m==null)\r
-               throw new IllegalArgumentException("null");\r
-       if (isEmpty()) return;          \r
-       Map<IThreadWorkQueue, T[]> snapshot = getSnapshot();            \r
-       for (Entry<IThreadWorkQueue, T[]> e : snapshot.entrySet())\r
-       {\r
-               final IThreadWorkQueue thread = e.getKey();\r
-               final T[] list = e.getValue();                  \r
-                       Runnable r = new Runnable() {\r
-                               @Override\r
-                               public void run() {\r
-                                       for (T t : list)\r
-                                               try {\r
-                                                       m.invoke(t, args);\r
-                                               } catch (RuntimeException e) {\r
-                                                       e.printStackTrace();\r
-                                               } catch (IllegalAccessException e) {\r
-                                                       e.printStackTrace();\r
-                                               } catch (InvocationTargetException e) {\r
-                                                       e.getCause().printStackTrace();\r
-                                               }\r
-                               }\r
-                       };\r
-                       ThreadUtils.asyncExec(thread, r);                       \r
-       }\r
-    }\r
-/*        \r
- * Version that does not use ThreadUtils\r
-    public void fireEventSync(final Method m, final Object ... args)\r
-    {\r
-       Map<IThreadAccess, T[]> snapshot = getSnapshot();       \r
-       final Semaphore s = new Semaphore(0);\r
-       \r
-       int countAsyncThreads = 0;\r
-       \r
-       // todo use snapshot version of lists\r
-       for (Entry<IThreadAccess, T[]> e : snapshot.entrySet())\r
-       {\r
-               final IThreadAccess thread = e.getKey();\r
-               if (!thread.currentThreadAccess()) {\r
-                       countAsyncThreads++;\r
-                       continue;\r
-               }\r
-       }\r
-       // Start async prosessing\r
-       for (Entry<IThreadAccess, T[]> e : snapshot.entrySet())\r
-       {\r
-               final IThreadAccess thread = e.getKey();\r
-               if (thread.currentThreadAccess()) {\r
-                       countAsyncThreads++;\r
-                       continue;\r
-               }\r
-               final T[] list = e.getValue();                  \r
-                       Runnable r = new Runnable() {\r
-                               @Override\r
-                               public void run() {\r
-                                       try {\r
-                                               for (T t : list)\r
-                                               {\r
-                                                       try {\r
-                                                               m.invoke(t, args);\r
-                                                       } catch (RuntimeException e) {\r
-                                                               e.printStackTrace();\r
-                                                       } catch (IllegalAccessException e) {\r
-                                                               e.printStackTrace();\r
-                                                       } catch (InvocationTargetException e) {\r
-                                                               e.printStackTrace();\r
-                                                       }\r
-                                               }\r
-                                       } finally {\r
-                                               // Signal ready\r
-                                               s.release();\r
-                                       }\r
-                               }\r
-                       };\r
-                       ThreadUtils.asyncExec(thread, r);\r
-       }\r
-       // Start local thread processing\r
-       for (Entry<IThreadAccess, T[]> e : snapshot.entrySet())\r
-       {\r
-               final T[] list = e.getValue();                  \r
-                       for (T t : list)\r
-                       {\r
-                               try {\r
-                                       m.invoke(t, args);\r
-                               } catch (RuntimeException e1) {\r
-                                       e1.printStackTrace();\r
-                               } catch (IllegalAccessException e2) {\r
-                                       e2.printStackTrace();\r
-                               } catch (InvocationTargetException e3) {\r
-                                       e3.printStackTrace();\r
-                               }\r
-                       }\r
-       }       \r
-       \r
-       // wait until all threads are ready\r
-       try {\r
-                       s.acquire(countAsyncThreads);\r
-               } catch (InterruptedException e) {\r
-               }\r
-    }\r
-       */\r
-    \r
-    public void addExecutables(Collection<Executable> container, final Method m, final Object ... args)\r
-    {\r
-       Map<IThreadWorkQueue, T[]> snapshot = getSnapshot();            \r
-       \r
-       for (Entry<IThreadWorkQueue, T[]> e : snapshot.entrySet())\r
-       {\r
-               IThreadWorkQueue thread = e.getKey();\r
-               final T[] list = e.getValue();\r
-                       Runnable r = new Runnable() {\r
-                               @Override\r
-                               public void run() {\r
-                                       for (T t : list)\r
-                                       {\r
-                                               try {\r
-                                                       m.invoke(t, args);\r
-                                               } catch (RuntimeException e) {\r
-                                                       e.printStackTrace();\r
-                                               } catch (IllegalAccessException e) {\r
-                                                       e.printStackTrace();\r
-                                               } catch (InvocationTargetException e) {\r
-                                                       e.getCause().printStackTrace();\r
-                                               }\r
-                                       }\r
-                               }\r
-                       };\r
-                       \r
-               container.add( new Executable(thread, r) );\r
-       }\r
-    }\r
-    \r
-    public Executable[] getExecutables(final Method m, final Object ... args)\r
-    {\r
-       Map<IThreadWorkQueue, T[]> snapshot = getSnapshot();\r
-       List<Executable> container =\r
-               new ArrayList<Executable>(snapshot.size());\r
-       addExecutables(container, m, args);\r
-       return container.toArray(new Executable[container.size()]);\r
-    }\r
-    \r
-    // Version that uses thread utils\r
-    public void fireEventSync(final Method m, final Object ... args)\r
-    {\r
-       if (m==null)\r
-               throw new IllegalArgumentException("null");\r
-       if (isEmpty()) return;\r
-       ThreadUtils.multiSyncExec(getExecutables(m, args));\r
-    }\r
-    \r
-    public static Method getMethod(Class<?> clazz, String name)\r
-    {\r
-       int count = 0;\r
-       Method result = null;\r
-       for (Method m : clazz.getMethods())\r
-       {\r
-               if (!m.getName().equals(name)) continue;\r
-               count++;\r
-               result = m;\r
-       }\r
-       if (count!=1) throw new Error("Unexpected method \""+name+"\" count in class "+clazz.getName());\r
-       return result;\r
-    }\r
-    \r
-    public synchronized T[] getListenersByThread(IThreadWorkQueue ta) \r
-    {\r
-       ListenerList<T> l = lists.get(ta);\r
-       if (l==null) return null;\r
-       return l.getListeners();\r
-    }\r
-    \r
-    /**\r
-     * Is the list executable in current thread. \r
-     *  \r
-     * @return <code>true</code> if executable\r
-     */\r
-    public synchronized boolean executableInCurrentThread() {\r
-       for (IThreadWorkQueue ta : lists.keySet())\r
-               if (!ta.currentThreadAccess())\r
-                       return false;\r
-       return true;\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
+ *******************************************************************************/
+/*
+ *
+ * @author Toni Kalajainen
+ */
+package org.simantics.utils.threads;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.simantics.utils.threads.internal.ListenerList;
+
+/**
+ * 
+ * @author Toni Kalajainen
+ *
+ * @see ListenerList Simple listener list
+ *
+ * @param <T>
+ */
+public class SyncListenerList<T> {
+
+       /** internal use */
+       Map<IThreadWorkQueue, ListenerList<T>> lists =
+               new HashMap<IThreadWorkQueue, ListenerList<T>>(2);
+               
+       /** Snapshot version */
+       Map<IThreadWorkQueue, T[]> snapshot;
+       
+       Boolean requiresThreadSwitching = Boolean.FALSE;
+               
+    /** 
+     * The class of T
+     */
+    private final Class<T> componentType;      
+       
+       @SuppressWarnings("unchecked")
+       public SyncListenerList(Class<?> componentType)
+       {
+        this.componentType = (Class<T>) componentType;         
+       }
+       
+       /**
+        * Add listener to the list
+        * @param thread thread to use to handle the event
+        * @param listener
+        */
+    public synchronized void add(IThreadWorkQueue thread, T listener)
+    {
+       if (listener==null)
+               throw new IllegalArgumentException("null");
+       
+       snapshot = null;
+       ListenerList<T> list = lists.get(thread);
+       if (list==null) {
+               list = new ListenerList<T>(componentType);
+               lists.put(thread, list);
+       }
+       list.add(listener);
+       if (thread!=CurrentThread.getThreadAccess())
+               requiresThreadSwitching = Boolean.TRUE;
+    }
+    
+    /**
+     * Contains elements that require thread switching.
+     * @return true if contains elements with thread access other than current thread
+     */
+    public synchronized Boolean containsContextSwitchingListeners() {
+       if (requiresThreadSwitching==null)
+               requiresThreadSwitching = _HasContextSwitching();
+       return requiresThreadSwitching;
+    }
+        
+    /**
+     * 
+     * @return true if contains listeners that require context switching
+     */
+    private boolean _HasContextSwitching()
+    {
+       if (lists.size()!=0) return false;
+       if (lists.size()>1) return false;
+       Entry<IThreadWorkQueue, ListenerList<T>> e = lists.entrySet().iterator().next();
+       if (e.getKey()!=CurrentThread.getThreadAccess()) return false;
+       return !e.getValue().isEmpty();
+    }
+
+    /**
+     * Add listener to the list. Listener will be invoked in the thread that
+     * happens to be running at the time of events.
+     * 
+     * @param listener
+     */
+    public void add(T listener)
+    {
+       if (listener==null)
+               throw new IllegalArgumentException("null");
+       add(CurrentThread.getThreadAccess(), listener);
+    }
+
+       /**
+        * Remove listener from the list
+        * @param thread thread to use to handle the event
+        * @param listener
+        */
+    public synchronized void remove(IThreadWorkQueue thread, T listener)
+    {
+       snapshot = null;
+       ListenerList<T> list = lists.get(thread);
+       if (list==null) return;
+       list.remove(listener);
+       if (list.isEmpty())
+               lists.remove(thread);
+       if (isEmpty()) {
+               requiresThreadSwitching = Boolean.FALSE;
+               return;
+       }
+       if (requiresThreadSwitching==null) return;      
+       if (!requiresThreadSwitching) return;
+       if (thread==CurrentThread.getThreadAccess()) return;
+       requiresThreadSwitching = null;
+    }
+
+    public void remove(T listener)
+    {
+       remove(CurrentThread.getThreadAccess(), listener);
+    }
+    
+    public synchronized boolean isEmpty()
+    {
+        return lists.size()==0;
+    }
+    
+    public synchronized void clear()
+    {
+       requiresThreadSwitching = Boolean.FALSE;
+        lists.clear();
+        snapshot = null;
+    }
+        
+    
+    public synchronized Map<IThreadWorkQueue, T[]> getSnapshot()
+    {
+       if (snapshot==null) {
+               snapshot = new HashMap<IThreadWorkQueue, T[]>(lists.size());
+               for (Entry<IThreadWorkQueue, ListenerList<T>> e : lists.entrySet())
+               {
+                       T[] list = e.getValue().getListeners();
+                       snapshot.put(e.getKey(), list);
+               }
+       }
+       return snapshot;
+    }
+
+    public void fireEventAsync(final Method m, final Object ... args)
+    {
+       if (m==null)
+               throw new IllegalArgumentException("null");
+       if (isEmpty()) return;          
+       Map<IThreadWorkQueue, T[]> snapshot = getSnapshot();            
+       for (Entry<IThreadWorkQueue, T[]> e : snapshot.entrySet())
+       {
+               final IThreadWorkQueue thread = e.getKey();
+               final T[] list = e.getValue();                  
+                       Runnable r = new Runnable() {
+                               @Override
+                               public void run() {
+                                       for (T t : list)
+                                               try {
+                                                       m.invoke(t, args);
+                                               } catch (RuntimeException e) {
+                                                       e.printStackTrace();
+                                               } catch (IllegalAccessException e) {
+                                                       e.printStackTrace();
+                                               } catch (InvocationTargetException e) {
+                                                       e.getCause().printStackTrace();
+                                               }
+                               }
+                       };
+                       ThreadUtils.asyncExec(thread, r);                       
+       }
+    }
+/*        
+ * Version that does not use ThreadUtils
+    public void fireEventSync(final Method m, final Object ... args)
+    {
+       Map<IThreadAccess, T[]> snapshot = getSnapshot();       
+       final Semaphore s = new Semaphore(0);
+       
+       int countAsyncThreads = 0;
+       
+       // todo use snapshot version of lists
+       for (Entry<IThreadAccess, T[]> e : snapshot.entrySet())
+       {
+               final IThreadAccess thread = e.getKey();
+               if (!thread.currentThreadAccess()) {
+                       countAsyncThreads++;
+                       continue;
+               }
+       }
+       // Start async prosessing
+       for (Entry<IThreadAccess, T[]> e : snapshot.entrySet())
+       {
+               final IThreadAccess thread = e.getKey();
+               if (thread.currentThreadAccess()) {
+                       countAsyncThreads++;
+                       continue;
+               }
+               final T[] list = e.getValue();                  
+                       Runnable r = new Runnable() {
+                               @Override
+                               public void run() {
+                                       try {
+                                               for (T t : list)
+                                               {
+                                                       try {
+                                                               m.invoke(t, args);
+                                                       } catch (RuntimeException e) {
+                                                               e.printStackTrace();
+                                                       } catch (IllegalAccessException e) {
+                                                               e.printStackTrace();
+                                                       } catch (InvocationTargetException e) {
+                                                               e.printStackTrace();
+                                                       }
+                                               }
+                                       } finally {
+                                               // Signal ready
+                                               s.release();
+                                       }
+                               }
+                       };
+                       ThreadUtils.asyncExec(thread, r);
+       }
+       // Start local thread processing
+       for (Entry<IThreadAccess, T[]> e : snapshot.entrySet())
+       {
+               final T[] list = e.getValue();                  
+                       for (T t : list)
+                       {
+                               try {
+                                       m.invoke(t, args);
+                               } catch (RuntimeException e1) {
+                                       e1.printStackTrace();
+                               } catch (IllegalAccessException e2) {
+                                       e2.printStackTrace();
+                               } catch (InvocationTargetException e3) {
+                                       e3.printStackTrace();
+                               }
+                       }
+       }       
+       
+       // wait until all threads are ready
+       try {
+                       s.acquire(countAsyncThreads);
+               } catch (InterruptedException e) {
+               }
+    }
+       */
+    
+    public void addExecutables(Collection<Executable> container, final Method m, final Object ... args)
+    {
+       Map<IThreadWorkQueue, T[]> snapshot = getSnapshot();            
+       
+       for (Entry<IThreadWorkQueue, T[]> e : snapshot.entrySet())
+       {
+               IThreadWorkQueue thread = e.getKey();
+               final T[] list = e.getValue();
+                       Runnable r = new Runnable() {
+                               @Override
+                               public void run() {
+                                       for (T t : list)
+                                       {
+                                               try {
+                                                       m.invoke(t, args);
+                                               } catch (RuntimeException e) {
+                                                       e.printStackTrace();
+                                               } catch (IllegalAccessException e) {
+                                                       e.printStackTrace();
+                                               } catch (InvocationTargetException e) {
+                                                       e.getCause().printStackTrace();
+                                               }
+                                       }
+                               }
+                       };
+                       
+               container.add( new Executable(thread, r) );
+       }
+    }
+    
+    public Executable[] getExecutables(final Method m, final Object ... args)
+    {
+       Map<IThreadWorkQueue, T[]> snapshot = getSnapshot();
+       List<Executable> container =
+               new ArrayList<Executable>(snapshot.size());
+       addExecutables(container, m, args);
+       return container.toArray(new Executable[container.size()]);
+    }
+    
+    // Version that uses thread utils
+    public void fireEventSync(final Method m, final Object ... args)
+    {
+       if (m==null)
+               throw new IllegalArgumentException("null");
+       if (isEmpty()) return;
+       ThreadUtils.multiSyncExec(getExecutables(m, args));
+    }
+    
+    public static Method getMethod(Class<?> clazz, String name)
+    {
+       int count = 0;
+       Method result = null;
+       for (Method m : clazz.getMethods())
+       {
+               if (!m.getName().equals(name)) continue;
+               count++;
+               result = m;
+       }
+       if (count!=1) throw new Error("Unexpected method \""+name+"\" count in class "+clazz.getName());
+       return result;
+    }
+    
+    public synchronized T[] getListenersByThread(IThreadWorkQueue ta) 
+    {
+       ListenerList<T> l = lists.get(ta);
+       if (l==null) return null;
+       return l.getListeners();
+    }
+    
+    /**
+     * Is the list executable in current thread. 
+     *  
+     * @return <code>true</code> if executable
+     */
+    public synchronized boolean executableInCurrentThread() {
+       for (IThreadWorkQueue ta : lists.keySet())
+               if (!ta.currentThreadAccess())
+                       return false;
+       return true;
+    }
+    
+}