From 0df29b5b82369bc14fee431f2c1bf550ecdb4bb9 Mon Sep 17 00:00:00 2001 From: Naoghuman Date: Wed, 19 Dec 2018 17:09:52 +0100 Subject: [PATCH] #7 [api] Delete content from 'afterburner.fx' after prototyping the new api. --- ...ept_Basic_v0.1.0-PRERELEASE_2018-12-dd.txt | 1 + ...ease_v0.1.0-PRERELEASE_2018-12-dd_HH-mm.md | 1 + .../configuration/Configurator.java | 114 ------ .../afterburner/injection/Injector.java | 244 ------------- .../injection/PresenterFactory.java | 79 ----- .../airhacks/afterburner/views/FXMLView.java | 327 ------------------ 6 files changed, 2 insertions(+), 764 deletions(-) delete mode 100644 src/main/java/com/airhacks/afterburner/configuration/Configurator.java delete mode 100644 src/main/java/com/airhacks/afterburner/injection/Injector.java delete mode 100644 src/main/java/com/airhacks/afterburner/injection/PresenterFactory.java delete mode 100644 src/main/java/com/airhacks/afterburner/views/FXMLView.java diff --git a/concept/Concept_Basic_v0.1.0-PRERELEASE_2018-12-dd.txt b/concept/Concept_Basic_v0.1.0-PRERELEASE_2018-12-dd.txt index 05a4f6f..17b2051 100644 --- a/concept/Concept_Basic_v0.1.0-PRERELEASE_2018-12-dd.txt +++ b/concept/Concept_Basic_v0.1.0-PRERELEASE_2018-12-dd.txt @@ -23,6 +23,7 @@ SPECIFICATION - Package : com.package.my - Mandory files : MyView.java, MyPresenter.java where this files must end with the suffix 'View' and 'Presenter'. + and CamelCase from the prefix from the classes are mandory. - Optional files: my.fxml, my.properties, my.css where the file name and -type are mandory if they are exists. diff --git a/release/Release_v0.1.0-PRERELEASE_2018-12-dd_HH-mm.md b/release/Release_v0.1.0-PRERELEASE_2018-12-dd_HH-mm.md index 6f12067..941dc3e 100644 --- a/release/Release_v0.1.0-PRERELEASE_2018-12-dd_HH-mm.md +++ b/release/Release_v0.1.0-PRERELEASE_2018-12-dd_HH-mm.md @@ -31,6 +31,7 @@ TODO #### Refactoring +#7 [api] Delete content from 'afterburner.fx' after prototyping the new api. diff --git a/src/main/java/com/airhacks/afterburner/configuration/Configurator.java b/src/main/java/com/airhacks/afterburner/configuration/Configurator.java deleted file mode 100644 index 24a745d..0000000 --- a/src/main/java/com/airhacks/afterburner/configuration/Configurator.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2014 Adam Bien. - * - * 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 com.airhacks.afterburner.configuration; - -/* - * #%L - * afterburner.fx - * %% - * Copyright (C) 2013 - 2014 Adam Bien - * %% - * 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. - * #L% - */ -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * - * @author airhacks.com - */ -public class Configurator { - - public final static String CONFIGURATION_FILE = "configuration.properties"; - - private final Properties systemProperties; - private Function customConfigurator; - - private Consumer LOG; - - public Configurator() { - this.systemProperties = System.getProperties(); - this.LOG = l -> { - }; - } - - public Configurator set(Function custom) { - this.customConfigurator = custom; - return this; - } - - public Configurator setLogger(Consumer log) { - this.LOG = log; - return this; - } - - Properties getProperties(Class clazz) { - Properties configuration = new Properties(); - try (InputStream stream = clazz.getResourceAsStream(CONFIGURATION_FILE)) { - if (stream == null) { - return null; - } - configuration.load(stream); - } catch (IOException ex) { - //a property file does not have to exist... - } - return configuration; - } - - /** - * - * @param clazz is used to locate the properties @see - * java.lang.Class#getResourceAsStream - * @param key to be resolved - * @return the resolved value. - */ - public Object getProperty(Class clazz, Object key) { - Object value = this.systemProperties.get(key); - if (value != null) { - return value; - } - if (customConfigurator != null) { - value = customConfigurator.apply(key); - if (value != null) { - return value; - } - } - Properties clazzProperties = this.getProperties(clazz); - if (clazzProperties != null) { - value = clazzProperties.get(key); - } - return value; - } - - public void forgetAll() { - this.customConfigurator = null; - } - -} diff --git a/src/main/java/com/airhacks/afterburner/injection/Injector.java b/src/main/java/com/airhacks/afterburner/injection/Injector.java deleted file mode 100644 index e472bf0..0000000 --- a/src/main/java/com/airhacks/afterburner/injection/Injector.java +++ /dev/null @@ -1,244 +0,0 @@ -package com.airhacks.afterburner.injection; - -/* - * #%L - * afterburner.fx - * %% - * Copyright (C) 2013 Adam Bien - * %% - * 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. - * #L% - */ -import com.airhacks.afterburner.configuration.Configurator; -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import java.util.WeakHashMap; -import java.util.function.Consumer; -import java.util.function.Function; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.inject.Inject; - -/** - * - * @author adam-bien.com - */ -public class Injector { - - private static final Map, Object> modelsAndServices = new WeakHashMap<>(); - private static final Set presenters = Collections.newSetFromMap(new WeakHashMap<>()); - - private static Function, Object> instanceSupplier = getDefaultInstanceSupplier(); - - private static Consumer LOG = getDefaultLogger(); - - private static final Configurator configurator = new Configurator(); - - public static T instantiatePresenter(Class clazz, Function injectionContext) { - @SuppressWarnings("unchecked") - T presenter = registerExistingAndInject((T) instanceSupplier.apply(clazz)); - //after the regular, conventional initialization and injection, perform postinjection - Field[] fields = clazz.getDeclaredFields(); - for (final Field field : fields) { - if (field.isAnnotationPresent(Inject.class)) { - final String fieldName = field.getName(); - final Object value = injectionContext.apply(fieldName); - if (value != null) { - injectIntoField(field, presenter, value); - } - } - } - return presenter; - } - - public static T instantiatePresenter(Class clazz) { - return instantiatePresenter(clazz, f -> null); - } - - public static void setInstanceSupplier(Function, Object> instanceSupplier) { - Injector.instanceSupplier = instanceSupplier; - } - - public static void setLogger(Consumer logger) { - LOG = logger; - } - - public static void setConfigurationSource(Function configurationSupplier) { - configurator.set(configurationSupplier); - } - - public static void resetInstanceSupplier() { - instanceSupplier = getDefaultInstanceSupplier(); - } - - public static void resetConfigurationSource() { - configurator.forgetAll(); - } - - /** - * Caches the passed presenter internally and injects all fields - * - * @param the class to initialize - * @param instance An already existing (legacy) presenter interesting in - * injection - * @return presenter with injected fields - */ - public static T registerExistingAndInject(T instance) { - T product = injectAndInitialize(instance); - presenters.add(product); - return product; - } - - @SuppressWarnings("unchecked") - public static T instantiateModelOrService(Class clazz) { - T product = (T) modelsAndServices.get(clazz); - if (product == null) { - product = injectAndInitialize((T) instanceSupplier.apply(clazz)); - modelsAndServices.putIfAbsent(clazz, product); - } - return clazz.cast(product); - } - - public static void setModelOrService(Class clazz, T instance) { - modelsAndServices.put(clazz, instance); - } - - static T injectAndInitialize(T product) { - injectMembers(product); - initialize(product); - return product; - } - - static void injectMembers(final Object instance) { - Class clazz = instance.getClass(); - injectMembers(clazz, instance); - } - - public static void injectMembers(Class clazz, final Object instance) throws SecurityException { - LOG.accept("Injecting members for class " + clazz + " and instance " + instance); - Field[] fields = clazz.getDeclaredFields(); - for (final Field field : fields) { - if (field.isAnnotationPresent(Inject.class)) { - LOG.accept("Field annotated with @Inject found: " + field); - Class type = field.getType(); - String key = field.getName(); - Object value = configurator.getProperty(clazz, key); - LOG.accept("Value returned by configurator is: " + value); - if (value == null && isNotPrimitiveOrString(type)) { - LOG.accept("Field is not a JDK class"); - value = instantiateModelOrService(type); - } - if (value != null) { - LOG.accept("Value is a primitive, injecting..."); - injectIntoField(field, instance, value); - } - } - } - Class superclass = clazz.getSuperclass(); - if (superclass != null) { - LOG.accept("Injecting members of: " + superclass); - injectMembers(superclass, instance); - } - } - - static void injectIntoField(final Field field, final Object instance, final Object target) { - AccessController.doPrivileged((PrivilegedAction) () -> { - boolean wasAccessible = field.isAccessible(); - try { - field.setAccessible(true); - field.set(instance, target); - return null; // return nothing... - } catch (IllegalArgumentException | IllegalAccessException ex) { - throw new IllegalStateException("Cannot set field: " + field + " with value " + target, ex); - } finally { - field.setAccessible(wasAccessible); - } - }); - } - - static void initialize(Object instance) { - Class clazz = instance.getClass(); - invokeMethodWithAnnotation(clazz, instance, PostConstruct.class - ); - } - - static void destroy(Object instance) { - Class clazz = instance.getClass(); - invokeMethodWithAnnotation(clazz, instance, PreDestroy.class - ); - } - - static void invokeMethodWithAnnotation(Class clazz, final Object instance, final Class annotationClass) throws IllegalStateException, SecurityException { - Method[] declaredMethods = clazz.getDeclaredMethods(); - for (final Method method : declaredMethods) { - if (method.isAnnotationPresent(annotationClass)) { - AccessController.doPrivileged((PrivilegedAction) () -> { - boolean wasAccessible = method.isAccessible(); - try { - method.setAccessible(true); - return method.invoke(instance, new Object[]{}); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { - throw new IllegalStateException("Problem invoking " + annotationClass + " : " + method, ex); - } finally { - method.setAccessible(wasAccessible); - } - }); - } - } - Class superclass = clazz.getSuperclass(); - if (superclass != null) { - invokeMethodWithAnnotation(superclass, instance, annotationClass); - } - } - - public static void forgetAll() { - Collection values = modelsAndServices.values(); - values.stream().forEach((object) -> { - destroy(object); - }); - presenters.stream().forEach((object) -> { - destroy(object); - }); - presenters.clear(); - modelsAndServices.clear(); - resetInstanceSupplier(); - resetConfigurationSource(); - } - - static Function, Object> getDefaultInstanceSupplier() { - return (c) -> { - try { - return c.newInstance(); - } catch (InstantiationException | IllegalAccessException ex) { - throw new IllegalStateException("Cannot instantiate view: " + c, ex); - } - }; - } - - public static Consumer getDefaultLogger() { - return l -> { - }; - } - - private static boolean isNotPrimitiveOrString(Class type) { - return !type.isPrimitive() && !type.isAssignableFrom(String.class); - } -} diff --git a/src/main/java/com/airhacks/afterburner/injection/PresenterFactory.java b/src/main/java/com/airhacks/afterburner/injection/PresenterFactory.java deleted file mode 100644 index 0ebbf93..0000000 --- a/src/main/java/com/airhacks/afterburner/injection/PresenterFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2016 Adam Bien. - * - * 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 com.airhacks.afterburner.injection; - -/* - * #%L - * afterburner.fx - * %% - * Copyright (C) 2013 - 2016 Adam Bien - * %% - * 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. - * #L% - */ -import java.util.ServiceLoader; -import java.util.function.Function; - -/** - * The implementation of this interface is fully optional and only needed in - * case you would like to replaced the default Dependency Injection mechanism. - *

- * Afterburner will discover the implementations of this interface using the - * Java extension mechanism. - *

- *

- * You will have to register the an implementation by placing a text file: - * META-INF/services/com.airhacks.afterburner.injection.PresenterFactory - * containing the fully qualified name of the implementation. - *

- * - * @author airhacks.com - */ -@FunctionalInterface -public interface PresenterFactory { - - /** - * This method method replaces the standard afterburner dependency - * injection. - * - * @param the type of the presenter - * @param clazz presenter class containing the default constructor. - * @param injectionContext a cache of already instantiated and initialized - * instances. - * @return a fully initialized presenter with injected dependencies. - */ - T instantiatePresenter(Class clazz, Function injectionContext); - - /** - * - * @return all discovered implementations of PresenterFactory using the - * {@link java.util.ServiceLoader} mechanism - */ - static Iterable discover() { - return ServiceLoader.load(PresenterFactory.class); - } - -} diff --git a/src/main/java/com/airhacks/afterburner/views/FXMLView.java b/src/main/java/com/airhacks/afterburner/views/FXMLView.java deleted file mode 100644 index b803896..0000000 --- a/src/main/java/com/airhacks/afterburner/views/FXMLView.java +++ /dev/null @@ -1,327 +0,0 @@ -package com.airhacks.afterburner.views; - -/* - * #%L - * afterburner.fx - * %% - * Copyright (C) 2015 Adam Bien - * %% - * 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. - * #L% - */ -import com.airhacks.afterburner.injection.Injector; -import com.airhacks.afterburner.injection.PresenterFactory; -import java.io.IOException; -import java.net.URL; -import java.util.List; -import java.util.MissingResourceException; -import java.util.ResourceBundle; -import static java.util.ResourceBundle.getBundle; -import java.util.concurrent.CompletableFuture; -import static java.util.concurrent.CompletableFuture.supplyAsync; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; -import javafx.application.Platform; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ObservableValue; -import javafx.collections.ObservableList; -import javafx.fxml.FXMLLoader; -import javafx.scene.Node; -import javafx.scene.Parent; -import javafx.scene.layout.StackPane; -import javafx.util.Callback; - -/** - * @author adam-bien.com - */ -public abstract class FXMLView extends StackPane { - - public final static String DEFAULT_ENDING = "View"; - protected ObjectProperty presenterProperty; - protected FXMLLoader fxmlLoader; - protected String bundleName; - protected ResourceBundle bundle; - protected final Function injectionContext; - protected URL resource; - protected static Executor FX_PLATFORM_EXECUTOR = Platform::runLater; - - protected final static ExecutorService PARENT_CREATION_POOL = getExecutorService(); - - /** - * Constructs the view lazily (fxml is not loaded) with empty injection - * context. - */ - public FXMLView() { - this(f -> null); - } - - /** - * - * @param injectionContext the function is used as a injection source. - * Values matching for the keys are going to be used for injection into the - * corresponding presenter. - */ - public FXMLView(Function injectionContext) { - this.injectionContext = injectionContext; - this.init(getFXMLName()); - } - - private void init(final String conventionalName) { - this.presenterProperty = new SimpleObjectProperty<>(); - this.resource = getClass().getResource(conventionalName); - this.bundleName = getBundleName(); - this.bundle = getResourceBundle(bundleName); - } - - FXMLLoader loadSynchronously(final URL resource, ResourceBundle bundle, final String conventionalName) throws IllegalStateException { - final FXMLLoader loader = new FXMLLoader(resource, bundle); - PresenterFactory factory = discover(); - Callback, Object> controllerFactory = (Class p) -> factory.instantiatePresenter(p, this.injectionContext); - loader.setControllerFactory(controllerFactory); - try { - loader.load(); - } catch (IOException ex) { - throw new IllegalStateException("Cannot load " + conventionalName, ex); - } - return loader; - } - - PresenterFactory discover() { - Iterable discoveredFactories = PresenterFactory.discover(); - List factories = StreamSupport.stream(discoveredFactories.spliterator(), false). - collect(Collectors.toList()); - if (factories.isEmpty()) { - return Injector::instantiatePresenter; - } - - if (factories.size() == 1) { - return factories.get(0); - } else { - factories.forEach(System.err::println); - throw new IllegalStateException("More than one PresenterFactories discovered"); - } - - } - - void initializeFXMLLoader() { - if (this.fxmlLoader == null) { - this.fxmlLoader = this.loadSynchronously(resource, bundle, bundleName); - this.presenterProperty.set(this.fxmlLoader.getController()); - } - } - - /** - * Initializes the view by loading the FXML (if not happened yet) and - * returns the top Node (parent) specified in - * - * @return the node loaded by FXMLLoader - */ - public Parent getView() { - this.initializeFXMLLoader(); - Parent parent = fxmlLoader.getRoot(); - addCSSIfAvailable(parent); - return parent; - } - - /** - * Initializes the view synchronously and invokes and passes the created - * parent Node to the consumer within the FX UI thread. - * - * @param consumer - an object interested in received the Parent as callback - */ - public void getView(Consumer consumer) { - Supplier supplier = this::getView; - supplyAsync(supplier, FX_PLATFORM_EXECUTOR). - thenAccept(consumer). - exceptionally(this::exceptionReporter); - } - - /** - * Creates the view asynchronously using an internal thread pool and passes - * the parent node within the UI Thread. - * - * - * @param consumer - an object interested in received the Parent as callback - */ - public void getViewAsync(Consumer consumer) { - Supplier supplier = this::getView; - CompletableFuture.supplyAsync(supplier, PARENT_CREATION_POOL). - thenAcceptAsync(consumer, FX_PLATFORM_EXECUTOR). - exceptionally(this::exceptionReporter); - - } - - /** - * Scene Builder creates for each FXML document a root container. This - * method omits the root container (e.g. AnchorPane) and gives you the - * access to its first child. - * - * @return the first child of the AnchorPane - */ - public Node getViewWithoutRootContainer() { - final ObservableList children = getView().getChildrenUnmodifiable(); - if (children.isEmpty()) { - return null; - } - return children.listIterator().next(); - } - - void addCSSIfAvailable(Parent parent) { - URL uri = getClass().getResource(getStyleSheetName()); - if (uri == null) { - return; - } - String uriToCss = uri.toExternalForm(); - parent.getStylesheets().add(uriToCss); - } - - String getStyleSheetName() { - return getResourceCamelOrLowerCase(false, ".css"); - } - - /** - * - * @return the name of the fxml file derived from the FXML view. e.g. The - * name for the AirhacksView is going to be airhacks.fxml. - */ - final String getFXMLName() { - return getResourceCamelOrLowerCase(true, ".fxml"); - } - - String getResourceCamelOrLowerCase(boolean mandatory, String ending) { - String name = getConventionalName(true, ending); - URL found = getClass().getResource(name); - if (found != null) { - return name; - } - System.err.println("File: " + name + " not found, attempting with camel case"); - name = getConventionalName(false, ending); - found = getClass().getResource(name); - if (mandatory && found == null) { - final String message = "Cannot load file " + name; - System.err.println(message); - System.err.println("Stopping initialization phase..."); - throw new IllegalStateException(message); - } - return name; - } - - /** - * In case the view was not initialized yet, the conventional fxml - * (airhacks.fxml for the AirhacksView and AirhacksPresenter) are loaded and - * the specified presenter / controller is going to be constructed and - * returned. - * - * @return the corresponding controller / presenter (usually for a - * AirhacksView the AirhacksPresenter) - */ - public Object getPresenter() { - this.initializeFXMLLoader(); - return this.presenterProperty.get(); - } - - /** - * Does not initialize the view. Only registers the Consumer and waits until - * the the view is going to be created / the method FXMLView#getView or - * FXMLView#getViewAsync invoked. - * - * @param presenterConsumer listener for the presenter construction - */ - public void getPresenter(Consumer presenterConsumer) { - this.presenterProperty.addListener((ObservableValue o, Object oldValue, Object newValue) -> { - presenterConsumer.accept(newValue); - }); - } - - /** - * - * @param lowercase indicates whether the simple class name should be - * converted to lowercase of left unchanged - * @param ending the suffix to append - * @return the conventional name with stripped ending - */ - protected String getConventionalName(boolean lowercase, String ending) { - return getConventionalName(lowercase) + ending; - } - - /** - * - * @param lowercase indicates whether the simple class name should be - * @return the name of the view without the "View" prefix. - */ - protected String getConventionalName(boolean lowercase) { - final String clazzWithEnding = this.getClass().getSimpleName(); - String clazz = stripEnding(clazzWithEnding); - if (lowercase) { - clazz = clazz.toLowerCase(); - } - return clazz; - } - - String getBundleName() { - String conventionalName = getConventionalName(true); - return this.getClass().getPackage().getName() + "." + conventionalName; - } - - static String stripEnding(String clazz) { - if (!clazz.endsWith(DEFAULT_ENDING)) { - return clazz; - } - int viewIndex = clazz.lastIndexOf(DEFAULT_ENDING); - return clazz.substring(0, viewIndex); - } - - public static ResourceBundle getResourceBundle(String name) { - try { - return getBundle(name); - } catch (MissingResourceException ex) { - return null; - } - } - - /** - * - * @return an existing resource bundle, or null - */ - public ResourceBundle getResourceBundle() { - return this.bundle; - } - - static ExecutorService getExecutorService() { - return Executors.newCachedThreadPool((r) -> { - Thread thread = Executors.defaultThreadFactory().newThread(r); - String name = thread.getName(); - thread.setName("afterburner.fx-" + name); - thread.setDaemon(true); - return thread; - }); - } - - /** - * - * @param t exception to report - * @return nothing - */ - public Void exceptionReporter(Throwable t) { - System.err.println(t); - return null; - } - -}