/* * Copyright 2008-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.griffon.runtime.core.threading; import griffon.core.ExceptionHandler; import griffon.core.ExecutorServiceManager; import griffon.core.threading.UIThreadManager; import griffon.exceptions.GriffonException; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Named; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import static java.util.Objects.requireNonNull; /** * @author Andres Almiray * @since 2.0.0 */ public abstract class AbstractUIThreadManager implements UIThreadManager { protected static final String ERROR_RUNNABLE_NULL = "Argument 'runnable' must not be null"; protected static final String ERROR_CALLABLE_NULL = "Argument 'callable' must not be null"; private ExecutorServiceManager executorServiceManager; @Inject @Named("defaultExecutorService") private ExecutorService executorService; @Inject private ExceptionHandler exceptionHandler; @Inject public void setExecutorServiceManager(@Nonnull ExecutorServiceManager executorServiceManager) { requireNonNull(executorServiceManager, "Argument 'executorServiceManager' must not be null"); if (this.executorServiceManager != null) { this.executorServiceManager.remove(executorService); } this.executorServiceManager = executorServiceManager; this.executorServiceManager.add(executorService); } /** * Executes a code block as a Future on an ExecutorService. * * @param callable a code block to be executed * @return a Future that contains the result of the execution */ @Nonnull public <R> Future<R> runFuture(@Nonnull Callable<R> callable) { requireNonNull(callable, ERROR_CALLABLE_NULL); return runFuture(executorService, callable); } /** * Executes a code block as a Future on an ExecutorService. * * @param executorService the ExecutorService to use. Will use the default ExecutorService if null. * @param callable a code block to be executed * @return a Future that contains the result of the execution */ @Nonnull public <R> Future<R> runFuture(@Nonnull ExecutorService executorService, @Nonnull Callable<R> callable) { requireNonNull(executorService, "Argument 'executorService' must not be null"); requireNonNull(callable, ERROR_CALLABLE_NULL); return executorService.submit(callable); } public void runOutsideUI(@Nonnull final Runnable runnable) { requireNonNull(runnable, ERROR_RUNNABLE_NULL); if (!isUIThread()) { runnable.run(); } else { executorService.submit(new Runnable() { public void run() { try { runnable.run(); } catch (Throwable throwable) { exceptionHandler.uncaughtException(Thread.currentThread(), throwable); } } }); } } @Nullable @Override public <R> R runInsideUISync(@Nonnull Callable<R> callable) { requireNonNull(callable, ERROR_CALLABLE_NULL); FutureTask<R> ft = new FutureTask<>(callable); runInsideUISync(ft); try { return ft.get(); } catch (InterruptedException | ExecutionException e) { throw new GriffonException("An error occurred while executing a task inside the UI thread", e); } } }