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
019package org.fusesource.hawtdispatch;
020
021import org.fusesource.hawtdispatch.internal.DispatcherConfig;
022
023import java.nio.channels.SelectableChannel;
024import java.nio.channels.SelectionKey;
025import 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 */
069public 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     * Shutdown default dispatcher instance.
259     */
260    public static void shutdown() {
261        DISPATCHER.shutdown();
262    }
263
264    /**
265     * Restart default dispatcher instance.
266     */
267    public static void restart() {
268        DISPATCHER.restart();
269    }
270
271    /**
272     * A Runnable task that does nothing.
273     */
274    public static final Task NOOP = new Task() {
275        public void run() {}
276    };
277}