]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ListenerList.java
isImmutable can NPE
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / ListenerList.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package fi.vtt.simantics.procore.internal;
13
14 import java.lang.reflect.Array;
15
16 /**
17  * ListenerList is an efficient and synchronized list of listeners.
18  * The class is optimized for quick getListeners and slow add/remove.
19  * 
20  * @author Toni Kalajainen
21  */
22 public class ListenerList<T> {
23     
24     /**
25      * Array of listeners
26      */
27     private volatile T [] array;
28     
29     /** 
30      * The class of T
31      */
32     private final Class<T> componentType;
33            
34     /**
35      * Construct new Listener List
36      * @param componentType the class of the listener type
37      */
38     public ListenerList(Class<T> componentType)
39     {
40         this.componentType = componentType;
41         array = createArray(0);
42     }
43     
44     public T[] getListeners()
45     {
46         return array;
47     }
48     
49     public synchronized void add(T listener)
50     {
51         int oldLength = array.length;
52         int newLength = oldLength + 1;
53         T newArray[] = createArray(newLength);
54         System.arraycopy(array, 0, newArray, 0, oldLength);
55         newArray[oldLength] = listener;
56         array = newArray;
57     }
58     
59     /**
60      * Removes the first occurance of listener.
61      * If the listener is added multiple times, then it must be removed
62      * as many times.
63      * 
64      * @param listener a listener
65      * @return the listener that was removed from the list
66      */
67     public synchronized boolean remove(T listener)
68     {
69         int pos = getPos(listener);
70         if (pos<0) return false;
71         
72         int oldLength = array.length;
73         int newLength = oldLength -1;
74         T newArray[] = createArray(newLength);
75         
76         // Copy beginning
77         if (pos>0)
78             System.arraycopy(array, 0, newArray, 0, pos);
79         
80         // Copy ending
81         if (pos<newLength)
82             System.arraycopy(array, pos+1, newArray, pos, newLength-pos);
83         
84         array = newArray;
85         return true;
86     }        
87     
88     private synchronized int getPos(T listener)
89     {
90         for (int i=0; i<array.length; i++)
91             if (array[i] == listener)
92                 return i;
93         return -1;
94     }
95     
96     public int size()
97     {
98         return array.length;
99     }
100     
101     public boolean isEmpty()
102     {
103         return array.length == 0;
104     }
105     
106     public void clear()
107     {
108         array = createArray(0);
109     }
110     
111     @SuppressWarnings("unchecked")
112     private T[] createArray(int size)
113     {
114         return (T[]) Array.newInstance(componentType, size);
115     }
116     
117 }