001 /*
002 * SPDX-License-Identifier: Apache-2.0
003 *
004 * Copyright 2008-2017 the original author or authors.
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 package org.codehaus.griffon.runtime.core.threading;
019
020 import griffon.core.ExceptionHandler;
021 import griffon.core.ExecutorServiceManager;
022 import griffon.core.threading.UIThreadManager;
023 import griffon.exceptions.GriffonException;
024
025 import javax.annotation.Nonnull;
026 import javax.annotation.Nullable;
027 import javax.inject.Inject;
028 import javax.inject.Named;
029 import java.util.concurrent.Callable;
030 import java.util.concurrent.ExecutionException;
031 import java.util.concurrent.ExecutorService;
032 import java.util.concurrent.Future;
033 import java.util.concurrent.FutureTask;
034
035 import static java.util.Objects.requireNonNull;
036
037 /**
038 * @author Andres Almiray
039 * @since 2.0.0
040 */
041 public abstract class AbstractUIThreadManager implements UIThreadManager {
042 protected static final String ERROR_RUNNABLE_NULL = "Argument 'runnable' must not be null";
043 protected static final String ERROR_CALLABLE_NULL = "Argument 'callable' must not be null";
044
045 private ExecutorServiceManager executorServiceManager;
046
047 @Inject @Named("defaultExecutorService")
048 private ExecutorService executorService;
049
050 @Inject
051 private ExceptionHandler exceptionHandler;
052
053 @Inject
054 public void setExecutorServiceManager(@Nonnull ExecutorServiceManager executorServiceManager) {
055 requireNonNull(executorServiceManager, "Argument 'executorServiceManager' must not be null");
056 if (this.executorServiceManager != null) {
057 this.executorServiceManager.remove(executorService);
058 }
059 this.executorServiceManager = executorServiceManager;
060 this.executorServiceManager.add(executorService);
061 }
062
063 /**
064 * Executes a code block as a Future on an ExecutorService.
065 *
066 * @param callable a code block to be executed
067 *
068 * @return a Future that contains the result of the execution
069 */
070 @Nonnull
071 @Override
072 public <R> Future<R> runFuture(@Nonnull Callable<R> callable) {
073 requireNonNull(callable, ERROR_CALLABLE_NULL);
074 return runFuture(executorService, callable);
075 }
076
077 /**
078 * Executes a code block as a Future on an ExecutorService.
079 *
080 * @param executorService the ExecutorService to use. Will use the default ExecutorService if null.
081 * @param callable a code block to be executed
082 *
083 * @return a Future that contains the result of the execution
084 */
085 @Nonnull
086 @Override
087 public <R> Future<R> runFuture(@Nonnull ExecutorService executorService, @Nonnull Callable<R> callable) {
088 requireNonNull(executorService, "Argument 'executorService' must not be null");
089 requireNonNull(callable, ERROR_CALLABLE_NULL);
090 return executorService.submit(callable);
091 }
092
093 @Override
094 public void runOutsideUI(@Nonnull final Runnable runnable) {
095 requireNonNull(runnable, ERROR_RUNNABLE_NULL);
096 if (!isUIThread()) {
097 runnable.run();
098 } else {
099 executorService.submit(new Runnable() {
100 public void run() {
101 try {
102 runnable.run();
103 } catch (Throwable throwable) {
104 exceptionHandler.uncaughtException(Thread.currentThread(), throwable);
105 }
106 }
107 });
108 }
109 }
110
111 @Override
112 public void runOutsideUIAsync(@Nonnull final Runnable runnable) {
113 requireNonNull(runnable, ERROR_RUNNABLE_NULL);
114
115 executorService.submit(new Runnable() {
116 public void run() {
117 try {
118 runnable.run();
119 } catch (Throwable throwable) {
120 exceptionHandler.uncaughtException(Thread.currentThread(), throwable);
121 }
122 }
123 });
124 }
125
126 @Nullable
127 @Override
128 public <R> R runInsideUISync(@Nonnull Callable<R> callable) {
129 requireNonNull(callable, ERROR_CALLABLE_NULL);
130 FutureTask<R> ft = new FutureTask<>(callable);
131 runInsideUISync(ft);
132 try {
133 return ft.get();
134 } catch (InterruptedException | ExecutionException e) {
135 throw new GriffonException("An error occurred while executing a task inside the UI thread", e);
136 }
137 }
138
139 @Nonnull
140 protected ExecutorServiceManager getExecutorServiceManager() {
141 return executorServiceManager;
142 }
143
144 @Nonnull
145 protected ExecutorService getExecutorService() {
146 return executorService;
147 }
148
149 @Nonnull
150 protected ExceptionHandler getExceptionHandler() {
151 return exceptionHandler;
152 }
153 }
|