KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jegg > impl > Dispatcher


1 /*
2  * Copyright (c) 2004, Bruce Lowery
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * - Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * - Neither the name of JEGG nor the names of its contributors may be used
14  * to endorse or promote products derived from this software without
15  * specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */

29 package jegg.impl;
30
31 import java.util.HashMap JavaDoc;
32 import java.util.HashSet JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.Map JavaDoc;
35 import java.util.Set JavaDoc;
36
37 import jegg.Message;
38 import jegg.btree.BinaryTree;
39
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42
43 /**
44  * Used to dispatch messages to eggs. An instance of this
45  * class may be used to dispatch messages to multiple eggs, but it will
46  * always dispatch only a single message at a time.
47  * <p>
48  * When this class is loaded, a special dispatcher is created that is used
49  * to dispatch messages for eggs that were constructed without explicit
50  * specification of a dispatcher for the egg.
51  * <p>
52  * If a particular egg may take a long time to handle a message dispatched
53  * to it, then that egg should be constructed with its own dispatcher (see
54  * {@link jegg.Egg.Egg(Object,Dispatcher) Egg(Object,Dispatcher)}).
55  * <p>
56  * The Dispatcher class provides the fundamental mechanism that decouples
57  * an Egg implementation from its execution thread. The Dispatcher wraps
58  * the thread, not the Egg.
59  */

60 public class Dispatcher extends Thread JavaDoc
61 {
62     // TODO If one egg has a low priority message and another egg has
63
// a high priority message pending at the same time, it is not
64
// guaranteed that the high priority message will be delivered to
65
// its target egg before the low priority message is delivered to
66
// the other egg.
67

68     /** Class logger */
69     private static Log LOG = LogFactory.getLog(Dispatcher.class);
70
71     private static final Map JavaDoc _dispatchers = new HashMap JavaDoc();
72     
73     public static final String JavaDoc DEFAULT_DISPATCHER_NAME = "default-dispatcher";
74     
75     /** The default scheduler */
76     public static final Dispatcher DEFAULT_DISPATCHER;
77     
78     static
79     {
80         DEFAULT_DISPATCHER = new Dispatcher(DEFAULT_DISPATCHER_NAME);
81         _dispatchers.put(DEFAULT_DISPATCHER_NAME, DEFAULT_DISPATCHER);
82     }
83
84     /** The set of eggs that this scheduler is executing. */
85     private Set JavaDoc _scheduled = new HashSet JavaDoc();
86     
87     private BinaryTree _arrayPool = new BinaryTree();
88
89     public static Iterator JavaDoc iterator()
90     {
91         return _dispatchers.values().iterator();
92     }
93     
94     public static Dispatcher getDispatcher(final String JavaDoc name, final boolean start)
95     {
96         String JavaDoc id = (null == name) ? DEFAULT_DISPATCHER_NAME : name;
97         Dispatcher d = (Dispatcher)_dispatchers.get(id);
98         if (null == d)
99         {
100             d = new Dispatcher(id);
101             _dispatchers.put(id,d);
102         }
103         
104         if (start && !d.isAlive())
105             d.start();
106         
107         return d;
108     }
109     
110     public static Dispatcher getAnonymousDispatcher()
111     {
112         return new Dispatcher();
113     }
114     
115     private Dispatcher()
116     {
117         super();
118     }
119     
120     /**
121      * Construct a named dispatcher.
122      * @param name the name of the dispatcher.
123      */

124     private Dispatcher(final String JavaDoc name)
125     {
126         super(name);
127     }
128
129     /**
130      * Return a reference to the default dispatcher. This is the
131      * dispatcher that dispatches messages for all eggs that are
132      * constructed without specifying a particular dispatcher.
133      * @return the default scheduler.
134      */

135     static Dispatcher getDefaultScheduler()
136     {
137         return DEFAULT_DISPATCHER;
138     }
139
140     public void start()
141     {
142         if (LOG.isDebugEnabled())
143             LOG.debug("starting "+getName());
144         super.start();
145     }
146     /**
147      * Add an egg to the set of eggs assigned to this dispatcher.
148      * @param e the egg to add to the dispatcher's set.
149      */

150     final void add(final EggShell e)
151     {
152         LOG.trace("trace");
153         synchronized (_scheduled)
154         {
155             _scheduled.add(e);
156             _scheduled.notify();
157         }
158     }
159     /**
160      * Remove an egg from this dispatcher's set. After the
161      * egg has been removed, no more messages will be dispatched to the egg.
162      * @param e the egg to remove.
163      */

164     final void remove(final EggShell e)
165     {
166         LOG.trace("trace");
167         synchronized (_scheduled)
168         {
169             _scheduled.remove(e);
170             _scheduled.notify();
171         }
172     }
173
174     /**
175      * Implementation of the Thread superclass run method. This
176      * implementation delivers messsages in turn to each egg. Messages
177      * are dispatched based on priority.
178      */

179     public final void run()
180     {
181         LOG.trace("run(): starting");
182
183         while (!interrupted())
184         {
185             Object JavaDoc[] eggs = null;
186             int arraySize = 0;
187
188             while (null == eggs || 0 == eggs.length)
189             {
190                 synchronized (this)
191                 {
192                     synchronized (_scheduled)
193                     {
194                         if (!_scheduled.isEmpty())
195                         {
196                             eggs = getArray(_scheduled.size());
197                             arraySize = _scheduled.size();
198                             _scheduled.toArray(eggs);
199                         }
200                     }
201
202                     if (null == eggs || 0 == arraySize)
203                     {
204                         try
205                         {
206                             this.wait();
207                         }
208                         catch (InterruptedException JavaDoc e)
209                         {
210                             return;
211                         }
212                     }
213                 }
214             }
215
216             boolean startOver = false;
217
218             synchronized (this)
219             {
220                 int num = 0;
221                 while (0 == num)
222                 {
223                     for (int i = 0; i < arraySize; ++i)
224                     {
225                         EggShell egg = (EggShell) eggs[i];
226                         num += egg.getNumPendingMessages();
227                     }
228                     
229                     if (0 == num)
230                     {
231                         try
232                         {
233                             this.wait(); // wait for new egg or message
234
startOver = true;
235                             break;
236                         }
237                         catch (InterruptedException JavaDoc e)
238                         {
239                             return;
240                         }
241                     }
242                 }
243             }
244
245             if (startOver)
246             {
247                 releaseArray(eggs);
248                 continue;
249             }
250
251             for (int i = 0; i < arraySize; ++i)
252             {
253                 if (interrupted())
254                 {
255                     return;
256                 }
257                 EggShell egg = (EggShell) eggs[i];
258                 Message message = egg.getNextMessage();
259                 if (null != message)
260                 {
261                     egg.dispatch(message);
262                 }
263             }
264             releaseArray(eggs);
265         } //END while (!interrupted())
266

267     } // END METHOD run()
268

269     Object JavaDoc[] getArray(int size)
270     {
271         Object JavaDoc[] o = (Object JavaDoc[]) _arrayPool.getAtLeast(size);
272         if (null == o)
273         {
274             o = new Object JavaDoc[size];
275         }
276         else
277         {
278             _arrayPool.insert(o.length, null);
279         }
280         return o;
281     }
282     
283     private void releaseArray(Object JavaDoc[] array)
284     {
285         _arrayPool.insert(array.length, array);
286     }
287
288 }
289
Popular Tags