001    /**
002     * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
003     * Copyright (C) 2012 FuseSource, Inc.
004     * http://fusesource.com
005     *
006     * Licensed under the Apache License, Version 2.0 (the "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.fusesource.hawtdispatch;
020    
021    import org.fusesource.hawtdispatch.internal.DispatcherConfig;
022    
023    import java.nio.channels.SelectableChannel;
024    import java.nio.channels.SelectionKey;
025    import java.util.List;
026    
027    /**
028     * <p>
029     * The Dispatch class is used to get or create dispatch objects such
030     * as global queues, thread queues, serial queues, or dispatch sources.
031     * </p><p>
032     * It is encouraged that end users of this api do a static import of the
033     * methods defined in this class.
034     * <pre>
035     * import static org.fusesource.hawtdispatch.Dispatch.*;
036     * </pre>
037     * </p><p>
038     * The dispatch queues are {@link java.util.concurrent.Executor}
039     * objects that execute tasks asynchronously on thread pools managed by the
040     * Dispatcher.
041     *
042     * <ul>
043     * <li>
044     *   <b>Global Queues:</b> The tasks submitted to a concurrent dispatch
045     *   queue will execute concurrently on the first available thread of
046     *   the thread pool.  The order of execution of the tasks is non
047     *   deterministic.
048     * </li><li>
049     *   <b>Thread Queues:</b> The tasks submitted to a thread dispatch
050     *   queue will execute serially (FIFO order) on a single thread of
051     *   the thread pool.
052     * </li><li>
053     *   <b>Serial Queues:</b> The tasks submitted to a serial dispatch
054     *   queue will execute serially (FIFO order) on the first available
055     *   thread of the thread pool.
056     * </li>
057     * </p><p>
058     * All dispatch queues use a shared fixed size thread pool to execute
059     * tasks.  All tasks submitted on a dispatch queue should be non-blocking
060     * and wait free.
061     * </p><p>
062     * Dispatch sources provide a way to trigger execution of a user task on
063     * on a user selected dispatch queue in response to NIO or application
064     * defined events.
065     * </p>
066     *
067     * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
068     */
069    public class Dispatch {
070    
071        final private static Dispatcher DISPATCHER = DispatcherConfig.getDefaultDispatcher();
072    
073        public static final DispatchPriority HIGH    = DispatchPriority.HIGH;
074        public static final DispatchPriority DEFAULT = DispatchPriority.DEFAULT;
075        public static final DispatchPriority LOW     = DispatchPriority.LOW;
076    
077        /**
078         * <p>
079         * Returns the global concurrent queue of default priority.
080         * </p>
081         *
082         * @see #getGlobalQueue(DispatchPriority)  
083         * @return the default priority global queue.
084         */
085        public static DispatchQueue getGlobalQueue() {
086            return DISPATCHER.getGlobalQueue();
087        }
088    
089        /**
090         * <p>
091         * Returns a well-known global concurrent queue of a given priority level.
092         * </p><p>
093         * The well-known global concurrent queues may not be modified. Calls to
094         * {@link Suspendable#suspend()}, {@link Suspendable#resume()}, etc., will
095         * have no effect when used with queues returned by this function.
096         * </p>
097         *
098         * @param priority
099         * A priority defined in dispatch_queue_priority_t
100         * @return the requested global queue.
101         */
102        public static DispatchQueue getGlobalQueue(DispatchPriority priority) {
103            return DISPATCHER.getGlobalQueue(priority);
104        }
105    
106        /**
107         * <p>
108         * Creates a new serial dispatch queue to which runnable objects may be submitted.
109         * </p><p>
110         * Serial dispatch queues execute runnables submitted to them serially in FIFO order. A
111         * queue will only invoke one runnable at a time, but independent queues may each
112         * execute their runnables concurrently with respect to each other.
113         * </p><p>
114         * Conceptually a dispatch queue may have its own thread of execution, and
115         * interaction between queues is highly asynchronous.
116         * </p><p>
117         *
118         * @param label the label to assign the dispatch queue, can be null
119         * @return the newly created dispatch queue
120         */
121        public static DispatchQueue createQueue(String label) {
122            return DISPATCHER.createQueue(label);
123        }
124    
125        /**
126         * <p>
127         * Creates a new serial dispatch queue to which runnable objects may be submitted.
128         * </p>
129         * <p>
130         * Same thing as <code>createQueue(null)</code>
131         * </p>
132         * @see #createQueue(String)
133         * @return the newly created dispatch queue
134         */
135        public static DispatchQueue createQueue() {
136            return DISPATCHER.createQueue(null);
137        }
138    
139        /**
140         * <p>
141         * Returns the queue on which the currently executing runnable is running.
142         * </p><p>
143         * When {@link #getCurrentQueue()} is called outside of the context of a
144         * submitted runnable, it will return null.
145         * </p>
146         *
147         * @return the queue on which the currently executing runnable is running.
148         */
149        public static DispatchQueue getCurrentQueue() {
150            return DISPATCHER.getCurrentQueue();
151        }
152    
153        /**
154         * <p>
155         * Creates a new {@link DispatchSource} to monitor {@link SelectableChannel} objects and
156         * automatically submit a handler runnable to a dispatch queue in response to events.
157         * </p><p>
158         * You are allowed to create multiple dispatch sources to the same {@link SelectableChannel}
159         * object.
160         * </p>
161         *
162         * @param channel the channel to monitor.
163         * @param interestOps A mask of interest ops ({@link SelectionKey#OP_ACCEPT},
164         *        {@link SelectionKey#OP_CONNECT}, {@link SelectionKey#OP_READ}, or
165         *        {@link SelectionKey#OP_WRITE}) specifying which events are desired.
166         * @param queue The dispatch queue to which the event handler tasks will be submited.
167         *
168         * @return the newly created DispatchSource
169         */
170        public static DispatchSource createSource(SelectableChannel channel, int interestOps, DispatchQueue queue) {
171            return DISPATCHER.createSource(channel, interestOps, queue);
172        }
173    
174        /**
175         * <p>
176         * Creates a new {@link CustomDispatchSource} to monitor events merged into
177         * the dispatch source and automatically submit a handler runnable to a dispatch queue
178         * in response to the events.
179         * </p>
180         * 
181         * @param aggregator the data aggregation strategy to use.
182         * @param queue The dispatch queue to which the event handler tasks will be submited.
183         *
184         * @return the newly created CustomDispatchSource
185         */
186        public static <Event, MergedEvent> CustomDispatchSource<Event, MergedEvent> createSource(EventAggregator<Event, MergedEvent> aggregator, DispatchQueue queue) {
187            return DISPATCHER.createSource(aggregator, queue);
188        }
189    
190        /**
191         * @return the thread level dispatch queues for a given dispatch priority.
192         */
193        public static DispatchQueue[] getThreadQueues(DispatchPriority priority) {
194            return DISPATCHER.getThreadQueues(priority);
195        }
196    
197        /**
198         *
199         * @return the current thread queue or null of not executing on a thread queue.
200         */
201        public static DispatchQueue getCurrentThreadQueue() {
202            return DISPATCHER.getCurrentThreadQueue();
203        }
204    
205    // Being able to execute stuff on the main thread is critical for some GUI implementations.  For now
206    // we will not expose these interfaces until are fully cooked / have good test cases for them.
207    //
208    //    /**
209    //     * <p>
210    //     * Returns the default queue that is bound to the main thread.
211    //     * </p><p>
212    //     * In order to invoke runnables submitted to the main queue, the application must
213    //     * call {@link #dispatchMain()}}.
214    //     * </p>
215    //     *
216    //     * @return the main queue.
217    //     */
218    //    public static DispatchQueue getMainQueue() {
219    //        return DISPATCHER.getMainQueue();
220    //    }
221    //
222    //    /**
223    //     * <p>
224    //     * Execute runnables submitted to the main queue.
225    //     * </p><p>
226    //     * This function "parks" the main thread and waits for runnables to be submitted
227    //     * to the main queue. This function never returns.
228    //     * </p>
229    //     */
230    //    public static void dispatchMain() {
231    //        DISPATCHER.dispatchMain();
232    //    }
233    //
234    
235        /**
236         * If enabled then it enables profiling on the global
237         * queues and any newly created queues.  If not enabled
238         * then it disables profiling support on all the currently
239         * profiled queues and any queues created in the future.
240         *
241         * @param enabled
242         */
243        public static void profile(boolean enabled) {
244            DISPATCHER.profile(enabled);
245        }
246    
247        /**
248         * Used to get profiling metrics for all the queues
249         * currently being profiled.
250         *
251         * @return
252         */
253        public static List<Metrics> metrics() {
254            return DISPATCHER.metrics();
255        }
256    
257        /**
258         * A Runnable task that does nothing.
259         */
260        public static final Task NOOP = new Task() {
261            public void run() {}
262        };
263    }