1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.awt;
19
20import java.io.IOException;
21import java.io.ObjectInputStream;
22import java.io.ObjectOutputStream;
23import java.io.Serializable;
24import java.util.ArrayList;
25import java.util.Collections;
26import java.util.EventListener;
27import java.util.Iterator;
28import java.util.List;
29
30/**
31 * List of AWT listeners. It is for 3 purposes.
32 * 1. To support list modification from listeners
33 * 2. To ensure call for all listeners as atomic operation
34 * 3. To support system listeners that are needed for built-in AWT components
35 */
36public class ListenerList<T extends EventListener> implements Serializable {
37    private static final long serialVersionUID = 9180703263299648154L;
38
39    private transient ArrayList<T> systemList;
40    private transient ArrayList<T> userList;
41
42    public ListenerList() {
43        super();
44    }
45
46    /**
47     * Adds system listener to this list.
48     *
49     * @param listener - listener to be added.
50     */
51    public void addSystemListener(T listener) {
52        if (systemList == null) {
53            systemList = new ArrayList<T>();
54        }
55        systemList.add(listener);
56    }
57
58    /**
59     * Adds user (public) listener to this list.
60     *
61     * @param listener - listener to be added.
62     */
63    public void addUserListener(T listener) {
64        if (listener == null) {
65            return;
66        }
67        // transactionally replace old list
68        synchronized (this) {
69            if (userList == null) {
70                userList = new ArrayList<T>();
71                userList.add(listener);
72                return;
73            }
74            ArrayList<T> newList = new ArrayList<T>(userList);
75            newList.add(listener);
76            userList = newList;
77        }
78    }
79
80    /**
81     * Removes user (public) listener to this list.
82     *
83     * @param listener - listener to be removed.
84     */
85    public void removeUserListener(Object listener) {
86        if (listener == null) {
87            return;
88        }
89        // transactionally replace old list
90        synchronized (this) {
91            if (userList == null || !userList.contains(listener)) {
92                return;
93            }
94            ArrayList<T> newList = new ArrayList<T>(userList);
95            newList.remove(listener);
96            userList = (newList.size() > 0 ? newList : null);
97        }
98    }
99
100    /**
101     * Gets all user (public) listeners in one array.
102     *
103     * @param emptyArray - empty array, it's for deriving particular listeners class.
104     * @return array of all user listeners.
105     */
106    public <AT> AT[] getUserListeners(AT[] emptyArray){
107        synchronized (this) {
108            return (userList != null ? userList.toArray(emptyArray) : emptyArray);
109
110        }
111    }
112
113    /**
114     * Gets all user (public) listeners in one list.
115     *
116     * @return list of all user listeners.
117     */
118    public List<T> getUserListeners() {
119        synchronized (this) {
120            if (userList == null || userList.isEmpty()) {
121                return Collections.emptyList();
122            }
123            return new ArrayList<T>(userList);
124        }
125    }
126
127    public List<T> getSystemListeners() {
128        synchronized (this) {
129            if (systemList == null || systemList.isEmpty()) {
130                return Collections.emptyList();
131            }
132            return new ArrayList<T>(systemList);
133        }
134    }
135
136    /**
137     * Gets iterator for user listeners.
138     *
139     * @return iterator for user listeners.
140     */
141    public Iterator<T> getUserIterator() {
142        synchronized (this) {
143            if (userList == null) {
144                List<T> emptyList = Collections.emptyList();
145                return emptyList.iterator();
146            }
147            return new ReadOnlyIterator<T>(userList.iterator());
148        }
149    }
150
151    /**
152     * Gets iterator for system listeners.
153     *
154     * @return iterator for system listeners.
155     */
156    public Iterator<T> getSystemIterator() {
157        return systemList.iterator();
158    }
159
160    private static ArrayList<?> getOnlySerializable(ArrayList<?> list) {
161        if (list == null) {
162            return null;
163        }
164
165        ArrayList<Object> result = new ArrayList<Object>();
166        for (Iterator<?> it = list.iterator(); it.hasNext();) {
167            Object obj = it.next();
168            if (obj instanceof Serializable) {
169                result.add(obj);
170            }
171        }
172
173        return (result.size() != 0) ? result : null;
174    }
175
176    private void writeObject(ObjectOutputStream stream) throws IOException {
177
178        stream.defaultWriteObject();
179
180        stream.writeObject(getOnlySerializable(systemList));
181        stream.writeObject(getOnlySerializable(userList));
182    }
183
184    @SuppressWarnings("unchecked")
185    private void readObject(ObjectInputStream stream)
186            throws IOException, ClassNotFoundException {
187
188        stream.defaultReadObject();
189
190        systemList = (ArrayList<T>)stream.readObject();
191        userList = (ArrayList<T>)stream.readObject();
192    }
193
194}
195