001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.uml.core.eventframework;
043:
044: import org.netbeans.modules.uml.common.ETSystem;
045:
046: import java.lang.ref.WeakReference;
047: import java.util.Iterator;
048: import java.util.Vector;
049: import java.util.WeakHashMap;
050: import org.openide.ErrorManager;
051:
052: /**
053: * EventManager is a simple base class used to manage
054: * the collection of lister interfaces. The type used to instanciate
055: * this class should be the event listener interface, such as IWorkspaceEventsSink.
056: */
057: public class EventManager<Element> {
058: private Vector<WeakReference<Object>> m_listeners = new Vector<WeakReference<Object>>();
059: private WeakHashMap<Object, Object> hashedListeners = new WeakHashMap<Object, Object>();
060: private IEventDispatcher m_dispatcher = null;
061: private IValidationSink m_Validator = null;
062:
063: public void addListener(Element obj, IValidationSink<Element> sink) {
064: // conover - duplicate listeners were being registered, and this
065: // will prevent that from happening
066: //if (!m_listeners.contains(obj))
067: if (!contains(obj)) {
068: m_listeners.addElement(new WeakReference(obj));
069: hashedListeners.put(obj, new Object());
070:
071: if (sink != null)
072: setValidator(sink);
073: }
074:
075: // log instances when there is an attempt to register
076: // a duplicate listener
077: else
078: ErrorManager.getDefault().log(
079: ErrorManager.INFORMATIONAL,
080: "Duplicate listener registration was attempted with "
081: + obj.toString()); // NOI18N
082: }
083:
084: public void removeListener(Element sink) {
085: if (sink != null) {
086: Iterator<WeakReference<Object>> iter = m_listeners
087: .iterator();
088: if (iter != null) {
089: while (iter.hasNext()) {
090: WeakReference<Object> ref = iter.next();
091: if (ref != null) {
092: Object elem = ref.get();
093: if (elem != null && elem.equals(sink)) {
094: iter.remove();
095: }
096: }
097: }
098: }
099: hashedListeners.remove(sink);
100: }
101: }
102:
103: private boolean contains(Element obj) {
104: if (obj != null) {
105: if (hashedListeners.get(obj) != null) {
106: return true;
107: }
108: }
109: return false;
110: }
111:
112: private void cleanUp() {
113: Iterator<WeakReference<Object>> iter = m_listeners.iterator();
114: if (iter != null) {
115: while (iter.hasNext()) {
116: WeakReference<Object> ref = iter.next();
117: if (ref == null) {
118: iter.remove();
119: } else {
120: Object elem = ref.get();
121: if (elem == null) {
122: iter.remove();
123: }
124: }
125: }
126: }
127: }
128:
129: public void setDispatcher(IEventDispatcher disp) {
130: m_dispatcher = disp;
131: }
132:
133: public boolean anyListeners() {
134: return m_listeners.size() > 0;
135: }
136:
137: public int getNumListeners() {
138: return m_listeners.size();
139: }
140:
141: public void notifyListeners(EventFunctor func) {
142: if (func == null)
143: return;
144:
145: cleanUp();
146: //
147: // Switched the loop to go backwards because in onCoreProductPreQuit
148: // the listeners could be removed in the execute and that was causing
149: // the array to be messed up.
150: // In c++, this function takes a boolean as a parameter, but it is only
151: // set to true in WorkspaceEventDispatcherImpl::FireWSProjectPreSave
152: // so I am not sure how this isn't causing problems in c++ as well
153: //
154: //for (int i = 0; i < m_listeners.size(); i++)
155: for (int i = m_listeners.size() - 1; i >= 0; i--) {
156: try {
157: //if (validateSink(obj);
158: //System.out.println("--EventManager.notifyListeners() m_listeners.elementAt(i).get() = "+m_listeners.elementAt(i).get());
159: func.execute(m_listeners.elementAt(i).get());
160: }
161:
162: catch (Exception e) {
163: ETSystem.out.println("Error in notifyListeners");
164: }
165: }
166: }
167:
168: public void notifyListeners(EventFunctor func, Object[] params) {
169: if (func == null)
170: return;
171:
172: cleanUp();
173: // See above for comment
174: //for (int i = 0; i < m_listeners.size(); i++)
175: for (int i = m_listeners.size() - 1; i >= 0; i--) {
176: try {
177: //validateSink(obj);
178: func.execute(params, m_listeners.elementAt(i).get());
179: }
180:
181: catch (Exception e) {
182: ETSystem.out.println("Error in notifyListeners");
183: }
184: }
185: }
186:
187: public void notifyListenersWithQualifiedProceed(EventFunctor func) {
188: cleanUp();
189: // cvc - 6269224
190: // loop in reverse because an element might get removed outside of
191: // this instance and cause some listeners to be skipped
192: // see other notifier methods in this class for exact same comments
193: // as this was a problem in the past but this loop wasn't touched
194: // for (int i = 0; i < m_listeners.size(); i++)
195: for (int i = m_listeners.size() - 1; i > -1; i--) {
196: try {
197: //validateSink(obj);
198: func.execute(m_listeners.elementAt(i).get());
199: //check the result and if required call dispatchCancelEvent
200:
201: if (!func.isResultOK()) {
202: //DispatchCancelledEvent( i, event );
203: break;
204: }
205: }
206:
207: catch (Exception e) {
208: ETSystem.out
209: .println("Exception in notifyListenersWithQualifiedProceed"); // NOI18N
210: }
211: }
212: }
213:
214: /**
215: * @return
216: */
217: public IValidationSink getValidator() {
218: return m_Validator;
219: }
220:
221: /**
222: * @param sink
223: */
224: public void setValidator(IValidationSink sink) {
225: m_Validator = sink;
226: }
227: }
|