From 2c40387e03390c31f95e7e49047d8a0f2ac35dcf Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Sun, 6 Aug 2017 21:55:09 -0700 Subject: [PATCH 1/9] Remove the useless caching in the plugin manager and the maps in plugins --- .../java/org/nwapw/abacus/plugin/Plugin.java | 80 +-------- .../nwapw/abacus/plugin/PluginManager.java | 159 +++++++----------- 2 files changed, 61 insertions(+), 178 deletions(-) diff --git a/src/main/java/org/nwapw/abacus/plugin/Plugin.java b/src/main/java/org/nwapw/abacus/plugin/Plugin.java index b569dea..042f424 100644 --- a/src/main/java/org/nwapw/abacus/plugin/Plugin.java +++ b/src/main/java/org/nwapw/abacus/plugin/Plugin.java @@ -17,18 +17,6 @@ import java.util.Set; */ public abstract class Plugin { - /** - * A hash map of functions mapped to their string names. - */ - private Map functions; - /** - * A hash map of operators mapped to their string names. - */ - private Map operators; - /** - * The map of the number implementations this plugin provides. - */ - private Map numberImplementations; /** * The plugin manager in which to search for functions * not inside this package, @@ -49,69 +37,9 @@ public abstract class Plugin { */ public Plugin(PluginManager manager) { this.manager = manager; - functions = new HashMap<>(); - operators = new HashMap<>(); - numberImplementations = new HashMap<>(); enabled = false; } - /** - * Gets the list of functions provided by this plugin. - * - * @return the list of registered functions. - */ - public final Set providedFunctions() { - return functions.keySet(); - } - - /** - * Gets the list of functions provided by this plugin. - * - * @return the list of registered functions. - */ - public final Set providedOperators() { - return operators.keySet(); - } - - /** - * Gets the list of number implementations provided by this plugin. - * - * @return the list of registered number implementations. - */ - public final Set providedNumberImplementations() { - return numberImplementations.keySet(); - } - - /** - * Gets a function under the given function name. - * - * @param functionName the name of the function to get - * @return the function, or null if this plugin doesn't provide it. - */ - public final Function getFunction(String functionName) { - return functions.get(functionName); - } - - /** - * Gets an operator under the given operator name. - * - * @param operatorName the name of the operator to get. - * @return the operator, or null if this plugin doesn't provide it. - */ - public final Operator getOperator(String operatorName) { - return operators.get(operatorName); - } - - /** - * Gets the number implementation under the given name. - * - * @param name the name of the number implementation to look up. - * @return the number implementation associated with that name, or null if the plugin doesn't provide it. - */ - public final NumberImplementation getNumberImplementation(String name) { - return numberImplementations.get(name); - } - /** * Enables the function, loading the necessary instances * of functions. @@ -129,8 +57,6 @@ public abstract class Plugin { public final void disable() { if (!enabled) return; onDisable(); - functions.clear(); - operators.clear(); enabled = false; } @@ -142,7 +68,7 @@ public abstract class Plugin { * @param toRegister the function implementation. */ protected final void registerFunction(String name, Function toRegister) { - functions.put(name, toRegister); + manager.registerFunction(name, toRegister); } /** @@ -154,7 +80,7 @@ public abstract class Plugin { * @param operator the operator to register. */ protected final void registerOperator(String name, Operator operator) { - operators.put(name, operator); + manager.registerOperator(name, operator); } /** @@ -165,7 +91,7 @@ public abstract class Plugin { * @param implementation the actual implementation class to register. */ protected final void registerNumberImplementation(String name, NumberImplementation implementation) { - numberImplementations.put(name, implementation); + manager.registerNumberImplementation(name, implementation); } /** diff --git a/src/main/java/org/nwapw/abacus/plugin/PluginManager.java b/src/main/java/org/nwapw/abacus/plugin/PluginManager.java index b1e5143..e40b481 100644 --- a/src/main/java/org/nwapw/abacus/plugin/PluginManager.java +++ b/src/main/java/org/nwapw/abacus/plugin/PluginManager.java @@ -23,20 +23,17 @@ public class PluginManager { */ private Set plugins; /** - * List of functions that have been cached, - * that is, found in a plugin and returned. + * The map of functions registered by the plugins. */ - private Map cachedFunctions; + private Map registeredFunctions; /** - * List of operators that have been cached, - * that is, found in a plugin and returned. + * The map of operators registered by the plugins */ - private Map cachedOperators; + private Map registeredOperators; /** - * The list of number implementations that have - * been cached, that is, found in a plugin and returned. + * The map of number implementations registered by the plugins. */ - private Map cachedNumberImplementations; + private Map registeredNumberImplementations; /** * The list of number implementations that have been * found by their implementation class. @@ -46,18 +43,6 @@ public class PluginManager { * The pi values for each implementation class that have already been computer. */ private Map, NumberInterface> cachedPi; - /** - * List of all functions loaded by the plugins. - */ - private Set allFunctions; - /** - * List of all operators loaded by the plugins. - */ - private Set allOperators; - /** - * List of all the number implementations loaded by the plugins. - */ - private Set allNumberImplementations; /** * The list of plugin listeners attached to this instance. */ @@ -77,79 +62,66 @@ public class PluginManager { this.abacus = abacus; loadedPluginClasses = new HashSet<>(); plugins = new HashSet<>(); - cachedFunctions = new HashMap<>(); - cachedOperators = new HashMap<>(); - cachedNumberImplementations = new HashMap<>(); + registeredFunctions = new HashMap<>(); + registeredOperators = new HashMap<>(); + registeredNumberImplementations = new HashMap<>(); cachedInterfaceImplementations = new HashMap<>(); cachedPi = new HashMap<>(); - allFunctions = new HashSet<>(); - allOperators = new HashSet<>(); - allNumberImplementations = new HashSet<>(); listeners = new HashSet<>(); } /** - * Searches the plugin list for a certain value, retrieving the Plugin's - * list of items of the type using the setFunction and getting the value - * of it is available via getFunction. If the value is contained - * in the cache, it returns the cached value instead. - * - * @param plugins the plugin list to search. - * @param cache the cache to use - * @param setFunction the function to retrieve a set of available T's from the plugin - * @param getFunction the function to get the T value under the given name - * @param name the name to search for - * @param the type of element being search - * @param the type of key that the cache is indexed by. - * @return the retrieved element, or null if it was not found. + * Registers a function under the given name. + * @param name the name of the function. + * @param function the function to register. */ - private static T searchCached(Collection plugins, Map cache, - java.util.function.Function> setFunction, - java.util.function.BiFunction getFunction, - K name) { - if (cache.containsKey(name)) return cache.get(name); - - T loadedValue = null; - for (Plugin plugin : plugins) { - if (setFunction.apply(plugin).contains(name)) { - loadedValue = getFunction.apply(plugin, name); - break; - } - } - - cache.put(name, loadedValue); - return loadedValue; + public void registerFunction(String name, Function function){ + registeredFunctions.put(name, function); } /** - * Gets a function under the given name. - * - * @param name the name of the function - * @return the function under the given name. - */ - public Function functionFor(String name) { - return searchCached(plugins, cachedFunctions, Plugin::providedFunctions, Plugin::getFunction, name); - } - - /** - * Gets an operator under the given name. - * + * Registers an operator under the given name. * @param name the name of the operator. - * @return the operator under the given name. + * @param operator the operator to register. */ - public Operator operatorFor(String name) { - return searchCached(plugins, cachedOperators, Plugin::providedOperators, Plugin::getOperator, name); + public void registerOperator(String name, Operator operator){ + registeredOperators.put(name, operator); } /** - * Gets the number implementation under the given name. - * - * @param name the name of the implementation. - * @return the implementation. + * Registers a number implementation under the given name. + * @param name the name of the number implementation. + * @param implementation the number implementation to register. */ - public NumberImplementation numberImplementationFor(String name) { - return searchCached(plugins, cachedNumberImplementations, Plugin::providedNumberImplementations, - Plugin::getNumberImplementation, name); + public void registerNumberImplementation(String name, NumberImplementation implementation){ + registeredNumberImplementations.put(name, implementation); + } + + /** + * Gets the function registered under the given name. + * @param name the name of the function. + * @return the function, or null if it was not found. + */ + public Function functionFor(String name){ + return registeredFunctions.get(name); + } + + /** + * Gets the operator registered under the given name. + * @param name the name of the operator. + * @return the operator, or null if it was not found. + */ + public Operator operatorFor(String name){ + return registeredOperators.get(name); + } + + /** + * Gets the number implementation registered under the given name. + * @param name the name of the number implementation. + * @return the number implementation, or null if it was not found. + */ + public NumberImplementation numberImplementationFor(String name){ + return registeredNumberImplementations.get(name); } /** @@ -161,14 +133,11 @@ public class PluginManager { public NumberImplementation interfaceImplementationFor(Class name) { if (cachedInterfaceImplementations.containsKey(name)) return cachedInterfaceImplementations.get(name); NumberImplementation toReturn = null; - outside: - for (Plugin plugin : plugins) { - for (String implementationName : plugin.providedNumberImplementations()) { - NumberImplementation implementation = plugin.getNumberImplementation(implementationName); - if (implementation.getImplementation().equals(name)) { - toReturn = implementation; - break outside; - } + for(String key : registeredNumberImplementations.keySet()){ + NumberImplementation implementation = registeredNumberImplementations.get(key); + if(implementation.getImplementation() == name) { + toReturn = implementation; + break; } } cachedInterfaceImplementations.put(name, toReturn); @@ -227,12 +196,6 @@ public class PluginManager { if (disabledPlugins.contains(plugin.getClass().getName())) continue; plugin.enable(); } - for (Plugin plugin : plugins) { - if (disabledPlugins.contains(plugin.getClass().getName())) continue; - allFunctions.addAll(plugin.providedFunctions()); - allOperators.addAll(plugin.providedOperators()); - allNumberImplementations.addAll(plugin.providedNumberImplementations()); - } listeners.forEach(e -> e.onLoad(this)); } @@ -246,14 +209,8 @@ public class PluginManager { if (disabledPlugins.contains(plugin.getClass().getName())) continue; plugin.disable(); } - cachedFunctions.clear(); - cachedOperators.clear(); - cachedNumberImplementations.clear(); cachedInterfaceImplementations.clear(); cachedPi.clear(); - allFunctions.clear(); - allOperators.clear(); - allNumberImplementations.clear(); listeners.forEach(e -> e.onUnload(this)); } @@ -271,7 +228,7 @@ public class PluginManager { * @return the set of all functions that were loaded. */ public Set getAllFunctions() { - return allFunctions; + return registeredFunctions.keySet(); } /** @@ -280,7 +237,7 @@ public class PluginManager { * @return the set of all operators that were loaded. */ public Set getAllOperators() { - return allOperators; + return registeredOperators.keySet(); } /** @@ -289,7 +246,7 @@ public class PluginManager { * @return the set of all implementations that were loaded. */ public Set getAllNumberImplementations() { - return allNumberImplementations; + return registeredNumberImplementations.keySet(); } /** From 402867171cda3c26294b2105fca0e5069465b52f Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Sun, 6 Aug 2017 21:56:49 -0700 Subject: [PATCH 2/9] Rename getPi to piFor. --- src/main/java/org/nwapw/abacus/plugin/Plugin.java | 2 +- src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/nwapw/abacus/plugin/Plugin.java b/src/main/java/org/nwapw/abacus/plugin/Plugin.java index 042f424..7a78764 100644 --- a/src/main/java/org/nwapw/abacus/plugin/Plugin.java +++ b/src/main/java/org/nwapw/abacus/plugin/Plugin.java @@ -139,7 +139,7 @@ public abstract class Plugin { * @param forClass the class to which to find the pi instance. * @return the pi value for the given class. */ - protected final NumberInterface getPi(Class forClass) { + protected final NumberInterface piFor(Class forClass) { return manager.piFor(forClass); } diff --git a/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java b/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java index 0e170fc..5ecf388 100755 --- a/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java @@ -358,7 +358,7 @@ public class StandardPlugin extends Plugin { @Override protected NumberInterface applyInternal(NumberInterface[] params) { - NumberInterface pi = getPi(params[0].getClass()); + NumberInterface pi = piFor(params[0].getClass()); NumberInterface twoPi = pi.multiply(new NaiveNumber(2).promoteTo(pi.getClass())); NumberInterface theta = getSmallAngle(params[0], pi); //System.out.println(theta); @@ -382,7 +382,7 @@ public class StandardPlugin extends Plugin { @Override protected NumberInterface applyInternal(NumberInterface[] params) { - return functionSin.apply(getPi(params[0].getClass()).divide(new NaiveNumber(2).promoteTo(params[0].getClass())) + return functionSin.apply(piFor(params[0].getClass()).divide(new NaiveNumber(2).promoteTo(params[0].getClass())) .subtract(params[0])); } }; From 40bdbd1948237a62b5c2841d8a0efe686ade3335 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 7 Aug 2017 08:58:47 -0700 Subject: [PATCH 3/9] Add a timer to the computation thread to stop it from running. --- .../java/org/nwapw/abacus/fx/AbacusController.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/org/nwapw/abacus/fx/AbacusController.java b/src/main/java/org/nwapw/abacus/fx/AbacusController.java index 06b10ac..96d5ad3 100644 --- a/src/main/java/org/nwapw/abacus/fx/AbacusController.java +++ b/src/main/java/org/nwapw/abacus/fx/AbacusController.java @@ -124,6 +124,17 @@ public class AbacusController implements PluginListener { * The alert shown when a press to "apply" is needed. */ private Alert reloadAlert; + /** + * The runnable that takes care of killing computations that take too long. + */ + private final Runnable TIMER_RUNNABLE = () -> { + try { + Thread.sleep(30 * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + performStop(); + }; /** * The runnable used to perform the calculation. */ @@ -239,6 +250,7 @@ public class AbacusController implements PluginListener { stopButton.setDisable(false); calculationThread = new Thread(CALCULATION_RUNNABLE); calculationThread.start(); + new Thread(TIMER_RUNNABLE).start(); } @FXML From b8f8c4486a953a7c58eb3b823e2655d5e3d48167 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 7 Aug 2017 09:22:11 -0700 Subject: [PATCH 4/9] Add a setting to the timeout delay. --- .../nwapw/abacus/config/Configuration.java | 28 ++++++++++++++++++- .../org/nwapw/abacus/fx/AbacusController.java | 4 ++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/nwapw/abacus/config/Configuration.java b/src/main/java/org/nwapw/abacus/config/Configuration.java index 2b68236..1bc7aa2 100644 --- a/src/main/java/org/nwapw/abacus/config/Configuration.java +++ b/src/main/java/org/nwapw/abacus/config/Configuration.java @@ -30,6 +30,10 @@ public class Configuration { */ private static final TomlWriter TOML_WRITER = new TomlWriter(); + /** + * The computation delay for which the thread can run without interruption. + */ + private double computationDelay = 0; /** * The implementation of the number that should be used. */ @@ -51,10 +55,12 @@ public class Configuration { /** * Creates a new configuration with the given values. * + * @param computationDelay the delay before the computation gets killed. * @param numberImplementation the number implementation, like "naive" or "precise" * @param disabledPlugins the list of disabled plugins. */ - public Configuration(String numberImplementation, String[] disabledPlugins) { + public Configuration(double computationDelay, String numberImplementation, String[] disabledPlugins) { + this.computationDelay = computationDelay; this.numberImplementation = numberImplementation; this.disabledPlugins.addAll(Arrays.asList(disabledPlugins)); } @@ -75,6 +81,7 @@ public class Configuration { * @param otherConfiguration the configuration to copy from. */ public void copyFrom(Configuration otherConfiguration) { + this.computationDelay = otherConfiguration.computationDelay; this.numberImplementation = otherConfiguration.numberImplementation; this.disabledPlugins.addAll(otherConfiguration.disabledPlugins); } @@ -130,4 +137,23 @@ public class Configuration { return disabledPlugins; } + + /** + * Gets the computation delay specified in the configuration. + * + * @return the computaton delay. + */ + public double getComputationDelay() { + return computationDelay; + } + + /** + * Sets the computation delay. + * + * @param computationDelay the new computation delay. + */ + public void setComputationDelay(double computationDelay) { + this.computationDelay = computationDelay; + } + } diff --git a/src/main/java/org/nwapw/abacus/fx/AbacusController.java b/src/main/java/org/nwapw/abacus/fx/AbacusController.java index 96d5ad3..6b5aae3 100644 --- a/src/main/java/org/nwapw/abacus/fx/AbacusController.java +++ b/src/main/java/org/nwapw/abacus/fx/AbacusController.java @@ -129,7 +129,9 @@ public class AbacusController implements PluginListener { */ private final Runnable TIMER_RUNNABLE = () -> { try { - Thread.sleep(30 * 1000); + Configuration abacusConfig = abacus.getConfiguration(); + if(abacusConfig.getComputationDelay() != 0) + Thread.sleep((long) (abacusConfig.getComputationDelay() * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } From b2fad93ce4487db62f46c4cd3af01b83a26de331 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 7 Aug 2017 09:55:06 -0700 Subject: [PATCH 5/9] Fix tests to work with the configuration. --- src/test/java/org/nwapw/abacus/tests/CalculationTests.java | 2 +- src/test/java/org/nwapw/abacus/tests/TokenizerTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/nwapw/abacus/tests/CalculationTests.java b/src/test/java/org/nwapw/abacus/tests/CalculationTests.java index 106daa8..e451732 100644 --- a/src/test/java/org/nwapw/abacus/tests/CalculationTests.java +++ b/src/test/java/org/nwapw/abacus/tests/CalculationTests.java @@ -11,7 +11,7 @@ import org.nwapw.abacus.tree.TreeNode; public class CalculationTests { - private static Abacus abacus = new Abacus(new Configuration("precise", new String[]{})); + private static Abacus abacus = new Abacus(new Configuration(0, "precise", new String[]{})); @BeforeClass public static void prepareTests(){ diff --git a/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java b/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java index 6ba223c..56515e3 100644 --- a/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java +++ b/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java @@ -19,7 +19,7 @@ import java.util.List; public class TokenizerTests { - private static Abacus abacus = new Abacus(new Configuration("precise", new String[]{})); + private static Abacus abacus = new Abacus(new Configuration(0, "precise", new String[]{})); private static LexerTokenizer lexerTokenizer = new LexerTokenizer(); private static Function subtractFunction = new Function() { @Override From ed7d60800b674bae90db1a930b3ce12ef5bff36d Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 7 Aug 2017 10:30:37 -0700 Subject: [PATCH 6/9] Read delay input from input field, and kill delay thread. --- .../org/nwapw/abacus/fx/AbacusController.java | 37 +++++++++++++++---- src/main/resources/abacus.fxml | 4 +- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/nwapw/abacus/fx/AbacusController.java b/src/main/java/org/nwapw/abacus/fx/AbacusController.java index 6b5aae3..f3f2acc 100644 --- a/src/main/java/org/nwapw/abacus/fx/AbacusController.java +++ b/src/main/java/org/nwapw/abacus/fx/AbacusController.java @@ -1,6 +1,8 @@ package org.nwapw.abacus.fx; import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; @@ -89,6 +91,8 @@ public class AbacusController implements PluginListener { private ComboBox numberImplementationBox; @FXML private ListView enabledPluginView; + @FXML + private TextField computationLimitField; /** * The list of history entries, created by the users. @@ -130,12 +134,10 @@ public class AbacusController implements PluginListener { private final Runnable TIMER_RUNNABLE = () -> { try { Configuration abacusConfig = abacus.getConfiguration(); - if(abacusConfig.getComputationDelay() != 0) + if(abacusConfig.getComputationDelay() == 0) return; Thread.sleep((long) (abacusConfig.getComputationDelay() * 1000)); - } catch (InterruptedException e) { - e.printStackTrace(); - } - performStop(); + performStop(); + } catch (InterruptedException e) { } }; /** * The runnable used to perform the calculation. @@ -174,6 +176,7 @@ public class AbacusController implements PluginListener { }); } }; + private Thread computationLimitThread; /** * The thread in which the computation runs. */ @@ -237,6 +240,15 @@ public class AbacusController implements PluginListener { } abacusPluginManager.reload(); + computationLimitField.setText(Double.toString(abacus.getConfiguration().getComputationDelay())); + computationLimitField.textProperty().addListener((observable, oldValue, newValue) -> { + if(!newValue.matches("(\\d+(\\.\\d*)?)?")) { + computationLimitField.setText(oldValue); + } else { + changesMade = true; + } + }); + changesMade = false; reloadAlertShown = false; @@ -252,13 +264,20 @@ public class AbacusController implements PluginListener { stopButton.setDisable(false); calculationThread = new Thread(CALCULATION_RUNNABLE); calculationThread.start(); - new Thread(TIMER_RUNNABLE).start(); + computationLimitThread = new Thread(TIMER_RUNNABLE); + computationLimitThread.start(); } @FXML private void performStop(){ - if(calculationThread != null) + if(calculationThread != null) { calculationThread.interrupt(); + calculationThread = null; + } + if(computationLimitThread != null){ + computationLimitThread.interrupt(); + computationLimitThread = null; + } } @FXML @@ -284,6 +303,9 @@ public class AbacusController implements PluginListener { for (ToggleablePlugin pluginEntry : enabledPlugins) { if (!pluginEntry.isEnabled()) disabledPlugins.add(pluginEntry.getClassName()); } + if(computationLimitField.getText().matches("\\d*(\\.\\d+)?") && computationLimitField.getText().length() != 0) + configuration.setComputationDelay(Double.parseDouble(computationLimitField.getText())); + System.out.println(configuration.getComputationDelay()); configuration.saveTo(CONFIG_FILE); changesMade = false; reloadAlertShown = false; @@ -310,4 +332,5 @@ public class AbacusController implements PluginListener { enabledPlugins.clear(); numberImplementationOptions.clear(); } + } diff --git a/src/main/resources/abacus.fxml b/src/main/resources/abacus.fxml index 495c654..495187c 100644 --- a/src/main/resources/abacus.fxml +++ b/src/main/resources/abacus.fxml @@ -50,7 +50,9 @@ - + +