KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > event > DispatchQueue


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56
57 package org.objectstyle.cayenne.event;
58
59 import java.util.Collection JavaDoc;
60 import java.util.HashSet JavaDoc;
61 import java.util.Iterator JavaDoc;
62 import java.util.Map JavaDoc;
63 import java.util.Set JavaDoc;
64 import java.util.WeakHashMap JavaDoc;
65
66 import org.apache.log4j.Logger;
67 import org.objectstyle.cayenne.event.EventManager.Dispatch;
68 import org.objectstyle.cayenne.util.Invocation;
69
70 /**
71  * Stores a set of Invocation objects, organizing them by sender.
72  * Listeners have an option to receive events for a particular sender
73  * or to receive all events. EventManager creates one DispatchQueue per
74  * EventSubject. DispatchQueue is thread-safe - all methods that read/modify
75  * internal collections are synchronized.
76  *
77  * @author Andrei Adamchik
78  * @since 1.1
79  */

80 class DispatchQueue {
81     private static Logger logObj = Logger.getLogger(DispatchQueue.class);
82
83     // TODO: implement a maintenance thread to cleanup dead invocations with deallocated targets
84

85     private Set JavaDoc subjectInvocations = new HashSet JavaDoc();
86     private Map JavaDoc invocationsBySender = new WeakHashMap JavaDoc();
87
88     /**
89      * Dispatches event to all listeners in the queue that are
90      * registered for this event and sender.
91      */

92     synchronized void dispatchEvent(Dispatch dispatch) {
93         // dispatch to "any sender" listeners
94
dispatchEvent(subjectInvocations, dispatch);
95
96         // dispatch to the given sender listeners
97
Object JavaDoc sender = dispatch.getSender();
98         dispatchEvent(invocationsForSender(sender, false), dispatch);
99     }
100
101     synchronized void addInvocation(Invocation invocation, Object JavaDoc sender) {
102         if (sender == null) {
103             subjectInvocations.add(invocation);
104         }
105         else {
106             invocationsForSender(sender, true).add(invocation);
107         }
108     }
109
110     synchronized boolean removeInvocations(Object JavaDoc listener, Object JavaDoc sender) {
111
112         // remove only for specific sender
113
if (sender != null) {
114             return removeInvocations(invocationsForSender(sender, false), listener);
115         }
116
117         boolean didRemove = false;
118
119         // remove listener from all collections
120
didRemove = removeInvocations(subjectInvocations, listener);
121
122         Iterator JavaDoc sets = invocationsBySender.values().iterator();
123         while (sets.hasNext()) {
124             Collection JavaDoc senderInvocations = (Collection JavaDoc) sets.next();
125             if (senderInvocations == null) {
126                 continue;
127             }
128
129             Iterator JavaDoc it = senderInvocations.iterator();
130             while (it.hasNext()) {
131                 Invocation invocation = (Invocation) it.next();
132                 if (invocation.getTarget() == listener) {
133                     it.remove();
134                     didRemove = true;
135                 }
136             }
137         }
138
139         return didRemove;
140     }
141
142     private Collection JavaDoc invocationsForSender(Object JavaDoc sender, boolean create) {
143         Collection JavaDoc senderInvocations = (Collection JavaDoc) invocationsBySender.get(sender);
144         if (create && senderInvocations == null) {
145             senderInvocations = new HashSet JavaDoc();
146             invocationsBySender.put(sender, senderInvocations);
147         }
148
149         return senderInvocations;
150     }
151
152     // removes all invocations for a given listener
153
private boolean removeInvocations(Collection JavaDoc invocations, Object JavaDoc listener) {
154         if (invocations == null || invocations.isEmpty()) {
155             return false;
156         }
157
158         boolean didRemove = false;
159
160         Iterator JavaDoc invocationsIt = invocations.iterator();
161         while (invocationsIt.hasNext()) {
162             Invocation invocation = (Invocation) invocationsIt.next();
163             if (invocation.getTarget() == listener) {
164                 invocationsIt.remove();
165                 didRemove = true;
166             }
167         }
168
169         return didRemove;
170     }
171
172     // dispatches event to a list of listeners
173
private void dispatchEvent(Collection JavaDoc invocations, Dispatch dispatch) {
174         if (invocations == null || invocations.isEmpty()) {
175             return;
176         }
177
178         Iterator JavaDoc it = invocations.iterator();
179         while (it.hasNext()) {
180             Invocation invocation = (Invocation) it.next();
181
182             // fire invocation, detect if anything went wrong (e.g. GC'ed invocation targets)
183
if (!dispatch.fire(invocation)) {
184                 it.remove();
185                 logObj.debug(
186                     "Failed invocation, removing: " + invocation.getMethod().getName());
187             }
188         }
189     }
190 }
191
Popular Tags