001 /*
002 * Copyright 2008-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.codehaus.griffon.runtime.core.threading;
017
018 import griffon.core.ExceptionHandler;
019 import griffon.core.ExecutorServiceManager;
020 import griffon.core.threading.UIThreadManager;
021 import griffon.exceptions.GriffonException;
022
023 import javax.annotation.Nonnull;
024 import javax.annotation.Nullable;
025 import javax.inject.Inject;
026 import javax.inject.Named;
027 import java.util.concurrent.Callable;
028 import java.util.concurrent.ExecutionException;
029 import java.util.concurrent.ExecutorService;
030 import java.util.concurrent.Future;
031 import java.util.concurrent.FutureTask;
032
033 import static java.util.Objects.requireNonNull;
034
035 /**
036 * @author Andres Almiray
037 * @since 2.0.0
038 */
039 public abstract class AbstractUIThreadManager implements UIThreadManager {
040 protected static final String ERROR_RUNNABLE_NULL = "Argument 'runnable' must not be null";
041 protected static final String ERROR_CALLABLE_NULL = "Argument 'callable' must not be null";
042
043 private ExecutorServiceManager executorServiceManager;
044
045 @Inject @Named("defaultExecutorService")
046 private ExecutorService executorService;
047
048 @Inject
049 private ExceptionHandler exceptionHandler;
050
051 @Inject
052 public void setExecutorServiceManager(@Nonnull ExecutorServiceManager executorServiceManager) {
053 requireNonNull(executorServiceManager, "Argument 'executorServiceManager' must not be null");
054 if (this.executorServiceManager != null) {
055 this.executorServiceManager.remove(executorService);
056 }
057 this.executorServiceManager = executorServiceManager;
058 this.executorServiceManager.add(executorService);
059 }
060
061 /**
062 * Executes a code block as a Future on an ExecutorService.
063 *
064 * @param callable a code block to be executed
065 *
066 * @return a Future that contains the result of the execution
067 */
068 @Nonnull
069 @Override
070 public <R> Future<R> runFuture(@Nonnull Callable<R> callable) {
071 requireNonNull(callable, ERROR_CALLABLE_NULL);
072 return runFuture(executorService, callable);
073 }
074
075 /**
076 * Executes a code block as a Future on an ExecutorService.
077 *
078 * @param executorService the ExecutorService to use. Will use the default ExecutorService if null.
079 * @param callable a code block to be executed
080 *
081 * @return a Future that contains the result of the execution
082 */
083 @Nonnull
084 @Override
085 public <R> Future<R> runFuture(@Nonnull ExecutorService executorService, @Nonnull Callable<R> callable) {
086 requireNonNull(executorService, "Argument 'executorService' must not be null");
087 requireNonNull(callable, ERROR_CALLABLE_NULL);
088 return executorService.submit(callable);
089 }
090
091 @Override
092 public void runOutsideUI(@Nonnull final Runnable runnable) {
093 requireNonNull(runnable, ERROR_RUNNABLE_NULL);
094 if (!isUIThread()) {
095 runnable.run();
096 } else {
097 executorService.submit(new Runnable() {
098 public void run() {
099 try {
100 runnable.run();
101 } catch (Throwable throwable) {
102 exceptionHandler.uncaughtException(Thread.currentThread(), throwable);
103 }
104 }
105 });
106 }
107 }
108
109 @Override
110 public void runOutsideUIAsync(@Nonnull final Runnable runnable) {
111 requireNonNull(runnable, ERROR_RUNNABLE_NULL);
112
113 executorService.submit(new Runnable() {
114 public void run() {
115 try {
116 runnable.run();
117 } catch (Throwable throwable) {
118 exceptionHandler.uncaughtException(Thread.currentThread(), throwable);
119 }
120 }
121 });
122 }
123
124 @Nullable
125 @Override
126 public <R> R runInsideUISync(@Nonnull Callable<R> callable) {
127 requireNonNull(callable, ERROR_CALLABLE_NULL);
128 FutureTask<R> ft = new FutureTask<>(callable);
129 runInsideUISync(ft);
130 try {
131 return ft.get();
132 } catch (InterruptedException | ExecutionException e) {
133 throw new GriffonException("An error occurred while executing a task inside the UI thread", e);
134 }
135 }
136
137 @Nonnull
138 protected ExecutorServiceManager getExecutorServiceManager() {
139 return executorServiceManager;
140 }
141
142 @Nonnull
143 protected ExecutorService getExecutorService() {
144 return executorService;
145 }
146
147 @Nonnull
148 protected ExceptionHandler getExceptionHandler() {
149 return exceptionHandler;
150 }
151 }
|