/mycila-event/tags/mycila-event-3.2/src/main/java/com/mycila/event/spi/Dispatchers.java

http://mycila.googlecode.com/ · Java · 279 lines · 209 code · 45 blank · 25 comment · 1 complexity · b13f75b16b3d413ea678247ea7245139 MD5 · raw file

  1. /**
  2. * Copyright (C) 2009 Mathieu Carbou <mathieu.carbou@gmail.com>
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.mycila.event.spi;
  17. import com.mycila.event.api.Dispatcher;
  18. import com.mycila.event.api.ErrorHandler;
  19. import com.mycila.event.api.ErrorHandlers;
  20. import java.util.concurrent.CompletionService;
  21. import java.util.concurrent.Executor;
  22. import java.util.concurrent.ExecutorCompletionService;
  23. import java.util.concurrent.ExecutorService;
  24. import java.util.concurrent.LinkedBlockingQueue;
  25. import java.util.concurrent.RejectedExecutionHandler;
  26. import java.util.concurrent.ThreadPoolExecutor;
  27. import java.util.concurrent.TimeUnit;
  28. /**
  29. * @author Mathieu Carbou (mathieu.carbou@gmail.com)
  30. */
  31. public final class Dispatchers {
  32. private Dispatchers() {
  33. }
  34. /* custom */
  35. public static Dispatcher custom(Executor publishExecutor,
  36. Executor subscriberExecutor) {
  37. return custom(ErrorHandlers.rethrow(), publishExecutor, subscriberExecutor);
  38. }
  39. public static Dispatcher custom(ErrorHandler errorHandler,
  40. Executor publishExecutor,
  41. Executor subscriberExecutor) {
  42. return new DefaultDispatcher(errorHandler, publishExecutor, subscriberExecutor);
  43. }
  44. public static Dispatcher custom(ExecutorService publishExecutor,
  45. ExecutorService subscriberExecutor) {
  46. return custom(ErrorHandlers.rethrow(), publishExecutor, subscriberExecutor);
  47. }
  48. public static Dispatcher custom(ErrorHandler errorHandler,
  49. final ExecutorService publishExecutor,
  50. final ExecutorService subscriberExecutor) {
  51. return new DefaultDispatcher(errorHandler, publishExecutor, subscriberExecutor) {
  52. @Override
  53. public void close() {
  54. publishExecutor.shutdown();
  55. subscriberExecutor.shutdown();
  56. }
  57. };
  58. }
  59. /* synchronousSafe */
  60. public static Dispatcher synchronousSafe(long blockingTimeout, TimeUnit unit) {
  61. return synchronousSafe(ErrorHandlers.rethrow(), blockingTimeout, unit);
  62. }
  63. public static Dispatcher synchronousSafe(ErrorHandler errorHandler, long blockingTimeout, TimeUnit unit) {
  64. return new DefaultDispatcher(errorHandler, Executors.blocking(blockingTimeout, unit), Executors.immediate());
  65. }
  66. public static Dispatcher synchronousSafe() {
  67. return synchronousSafe(ErrorHandlers.rethrow());
  68. }
  69. public static Dispatcher synchronousSafe(ErrorHandler errorHandler) {
  70. return new DefaultDispatcher(errorHandler, Executors.blocking(), Executors.immediate());
  71. }
  72. /* synchronousUnsafe */
  73. public static Dispatcher synchronousUnsafe() {
  74. return asynchronousUnsafe(ErrorHandlers.rethrow());
  75. }
  76. public static Dispatcher synchronousUnsafe(ErrorHandler errorHandler) {
  77. return new DefaultDispatcher(errorHandler, Executors.immediate(), Executors.immediate());
  78. }
  79. /* asynchronousSafe */
  80. public static Dispatcher asynchronousSafe() {
  81. return asynchronousSafe(ErrorHandlers.rethrow());
  82. }
  83. public static Dispatcher asynchronousSafe(ErrorHandler errorHandler) {
  84. final ExecutorService executor = new ThreadPoolExecutor(
  85. 1, 1,
  86. 0L, TimeUnit.MILLISECONDS,
  87. new LinkedBlockingQueue<Runnable>(),
  88. new DefaultThreadFactory("AsynchronousSafe", "dispatcher", false),
  89. new RejectedExecutionHandler() {
  90. public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
  91. r.run();
  92. }
  93. });
  94. return new DefaultDispatcher(errorHandler, executor, Executors.immediate()) {
  95. @Override
  96. public void close() {
  97. executor.shutdown();
  98. }
  99. };
  100. }
  101. /* asynchronousUnsafe */
  102. public static Dispatcher asynchronousUnsafe() {
  103. return asynchronousUnsafe(ErrorHandlers.rethrow());
  104. }
  105. public static Dispatcher asynchronousUnsafe(ErrorHandler errorHandler) {
  106. return asynchronousUnsafe(Runtime.getRuntime().availableProcessors() * 4, errorHandler);
  107. }
  108. public static Dispatcher asynchronousUnsafe(int corePoolSize) {
  109. return asynchronousUnsafe(corePoolSize, ErrorHandlers.rethrow());
  110. }
  111. public static Dispatcher asynchronousUnsafe(int corePoolSize, ErrorHandler errorHandler) {
  112. final ExecutorService executor = new ThreadPoolExecutor(
  113. corePoolSize, corePoolSize,
  114. 0L, TimeUnit.MILLISECONDS,
  115. new LinkedBlockingQueue<Runnable>(),
  116. new DefaultThreadFactory("AsynchronousSafe", "dispatcher", false),
  117. new RejectedExecutionHandler() {
  118. public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
  119. r.run();
  120. }
  121. });
  122. return new DefaultDispatcher(errorHandler, executor, Executors.immediate()) {
  123. @Override
  124. public void close() {
  125. executor.shutdown();
  126. }
  127. };
  128. }
  129. /* broadcastOrdered */
  130. public static Dispatcher broadcastOrdered() {
  131. return broadcastOrdered(ErrorHandlers.rethrow());
  132. }
  133. public static Dispatcher broadcastOrdered(ErrorHandler errorHandler) {
  134. return broadcastOrdered(Runtime.getRuntime().availableProcessors() * 4, errorHandler);
  135. }
  136. public static Dispatcher broadcastOrdered(int corePoolSize) {
  137. return broadcastOrdered(corePoolSize, ErrorHandlers.rethrow());
  138. }
  139. public static Dispatcher broadcastOrdered(int corePoolSize, ErrorHandler errorHandler) {
  140. final ExecutorService publishingExecutor = new ThreadPoolExecutor(
  141. 1, 1,
  142. 0L, TimeUnit.MILLISECONDS,
  143. new LinkedBlockingQueue<Runnable>(),
  144. new DefaultThreadFactory("BroadcastOrdered", "dispatcher", false),
  145. new RejectedExecutionHandler() {
  146. public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
  147. r.run();
  148. }
  149. });
  150. final ExecutorService subscriberExecutor = new ThreadPoolExecutor(
  151. corePoolSize, corePoolSize,
  152. 0L, TimeUnit.MILLISECONDS,
  153. new LinkedBlockingQueue<Runnable>(),
  154. new DefaultThreadFactory("BroadcastOrdered", "dispatcher", false),
  155. new RejectedExecutionHandler() {
  156. public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
  157. r.run();
  158. }
  159. });
  160. final SubscriberCompletionExecutor subscriberCompletionExecutor = new SubscriberCompletionExecutor(subscriberExecutor);
  161. return new DefaultDispatcher(errorHandler, new Executor() {
  162. public void execute(final Runnable command) {
  163. publishingExecutor.execute(new Runnable() {
  164. public void run() {
  165. subscriberCompletionExecutor.onPublishStarting();
  166. try {
  167. command.run();
  168. } finally {
  169. subscriberCompletionExecutor.waitForCompletion();
  170. }
  171. }
  172. });
  173. }
  174. }, subscriberCompletionExecutor) {
  175. @Override
  176. public void close() {
  177. publishingExecutor.shutdown();
  178. subscriberExecutor.shutdown();
  179. }
  180. };
  181. }
  182. private static final class SubscriberCompletionExecutor implements Executor {
  183. final Executor executor;
  184. CompletionService<Void> completionService;
  185. int count = 0;
  186. SubscriberCompletionExecutor(Executor executor) {
  187. this.executor = executor;
  188. }
  189. public void execute(Runnable command) {
  190. completionService.submit(command, null);
  191. count++;
  192. }
  193. void onPublishStarting() {
  194. completionService = new ExecutorCompletionService<Void>(executor);
  195. count = 0;
  196. }
  197. void waitForCompletion() {
  198. try {
  199. while (count-- > 0)
  200. completionService.take();
  201. } catch (InterruptedException e) {
  202. Thread.currentThread().interrupt();
  203. }
  204. }
  205. }
  206. /* broadcastUnordered */
  207. public static Dispatcher broadcastUnordered() {
  208. return broadcastUnordered(ErrorHandlers.rethrow());
  209. }
  210. public static Dispatcher broadcastUnordered(ErrorHandler errorHandler) {
  211. return broadcastUnordered(Runtime.getRuntime().availableProcessors() * 4, errorHandler);
  212. }
  213. public static Dispatcher broadcastUnordered(int corePoolSize) {
  214. return broadcastUnordered(corePoolSize, ErrorHandlers.rethrow());
  215. }
  216. public static Dispatcher broadcastUnordered(int corePoolSize, ErrorHandler errorHandler) {
  217. final ExecutorService executor = new ThreadPoolExecutor(
  218. corePoolSize, corePoolSize,
  219. 0L, TimeUnit.MILLISECONDS,
  220. new LinkedBlockingQueue<Runnable>(),
  221. new DefaultThreadFactory("BroadcastUnordered", "dispatcher", false),
  222. new RejectedExecutionHandler() {
  223. public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
  224. r.run();
  225. }
  226. });
  227. return new DefaultDispatcher(errorHandler, executor, executor) {
  228. @Override
  229. public void close() {
  230. executor.shutdown();
  231. }
  232. };
  233. }
  234. }