├── src ├── test │ ├── resources │ │ └── test.js │ └── java │ │ └── me │ │ └── lucko │ │ └── scriptcontroller │ │ └── ControllerTest.java └── main │ └── java │ └── me │ └── lucko │ └── scriptcontroller │ ├── environment │ ├── loader │ │ ├── EnvironmentScriptLoader.java │ │ ├── ScriptLoader.java │ │ ├── DelegateScriptLoader.java │ │ └── ScriptLoadingExecutor.java │ ├── registry │ │ ├── ScriptRegistry.java │ │ └── ScriptRegistryImpl.java │ ├── script │ │ └── Script.java │ ├── ScriptEnvironment.java │ └── settings │ │ └── EnvironmentSettings.java │ ├── internal │ ├── Duration.java │ ├── FallbackSystemLogger.java │ ├── ScriptEnvironmentImpl.java │ ├── ScriptControllerImpl.java │ ├── EnvironmentSettingsImpl.java │ ├── ScriptImpl.java │ └── ScriptLoaderImpl.java │ ├── logging │ ├── ScriptLogger.java │ ├── SystemLogger.java │ └── ScriptLoggerImpl.java │ ├── bindings │ ├── BindingsBuilderImpl.java │ ├── BindingsBuilder.java │ └── BindingsSupplier.java │ ├── closable │ ├── CompositeClosingException.java │ ├── CompositeAutoClosableImpl.java │ └── CompositeAutoClosable.java │ ├── exports │ ├── ExportRegistryImpl.java │ ├── ExportRegistry.java │ ├── Export.java │ └── ExportImpl.java │ └── ScriptController.java ├── LICENSE.txt ├── README.md ├── .gitignore └── pom.xml /src/test/resources/test.js: -------------------------------------------------------------------------------- 1 | // print some logger message 2 | logger.info("testing 123"); 3 | 4 | // set an import 5 | exports.get("test").put("Hello world"); 6 | 7 | // use a custom binding 8 | testCallback.run(); 9 | 10 | // test a pointer 11 | var specialList = exports.pointer("test"); 12 | logger.info("a pointer to test: " + specialList()); 13 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License. 2 | 3 | Copyright (c) lucko (Luck) 4 | Copyright (c) contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/environment/loader/EnvironmentScriptLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.environment.loader; 27 | 28 | /** 29 | * The environments script loader 30 | */ 31 | public interface EnvironmentScriptLoader extends ScriptLoader, Runnable { 32 | 33 | /** 34 | * Script loading loop 35 | */ 36 | @Override 37 | void run(); 38 | 39 | /** 40 | * Tries to recursively load scripts. 41 | */ 42 | void preload(); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/internal/Duration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of scriptcontroller, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.internal; 27 | 28 | import java.util.concurrent.TimeUnit; 29 | 30 | class Duration { 31 | private final long duration; 32 | private final TimeUnit unit; 33 | 34 | Duration(long duration, TimeUnit unit) { 35 | this.duration = duration; 36 | this.unit = unit; 37 | } 38 | 39 | public long getDuration() { 40 | return this.duration; 41 | } 42 | 43 | public TimeUnit getUnit() { 44 | return this.unit; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/logging/ScriptLogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.logging; 27 | 28 | import me.lucko.scriptcontroller.environment.script.Script; 29 | 30 | /** 31 | * A scripts logger instance 32 | */ 33 | public interface ScriptLogger { 34 | 35 | static ScriptLogger create(SystemLogger logger, Script script) { 36 | return new ScriptLoggerImpl(logger, script); 37 | } 38 | 39 | void info(Object... message); 40 | 41 | default void log(Object... message) { 42 | info(message); 43 | } 44 | 45 | void warn(Object... message); 46 | 47 | default void warning(Object... message) { 48 | warn(message); 49 | } 50 | 51 | void error(Object... message); 52 | 53 | default void severe(Object... message) { 54 | error(message); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/bindings/BindingsBuilderImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.bindings; 27 | 28 | import java.util.function.Consumer; 29 | 30 | import javax.script.Bindings; 31 | 32 | final class BindingsBuilderImpl implements BindingsBuilder { 33 | private final Bindings bindings; 34 | 35 | BindingsBuilderImpl(Bindings bindings) { 36 | this.bindings = bindings; 37 | } 38 | 39 | @Override 40 | public BindingsBuilder put(String name, Object object) { 41 | this.bindings.put(name, object); 42 | return this; 43 | } 44 | 45 | @Override 46 | public BindingsBuilder apply(Consumer action) { 47 | action.accept(this.bindings); 48 | return this; 49 | } 50 | 51 | @Override 52 | public Bindings build() { 53 | return this.bindings; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/closable/CompositeClosingException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.closable; 27 | 28 | import java.util.Collections; 29 | import java.util.List; 30 | 31 | /** 32 | * Exception thrown to propagate exceptions thrown by 33 | * {@link CompositeAutoClosable#close()}. 34 | */ 35 | public class CompositeClosingException extends Exception { 36 | private final List causes; 37 | 38 | public CompositeClosingException(List causes) { 39 | super("Exception(s) occurred whilst closing: " + causes.toString()); 40 | if (causes.isEmpty()) { 41 | throw new IllegalArgumentException("No causes"); 42 | } 43 | this.causes = Collections.unmodifiableList(causes); 44 | } 45 | 46 | public List getCauses() { 47 | return this.causes; 48 | } 49 | 50 | public void printAllStackTraces() { 51 | this.printStackTrace(); 52 | for (Throwable cause : this.causes) { 53 | cause.printStackTrace(); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/exports/ExportRegistryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.exports; 27 | 28 | import java.util.Collection; 29 | import java.util.Collections; 30 | import java.util.Map; 31 | import java.util.concurrent.ConcurrentHashMap; 32 | import java.util.function.Function; 33 | 34 | final class ExportRegistryImpl implements ExportRegistry, Function> { 35 | private final Map> exports = new ConcurrentHashMap<>(); 36 | 37 | @Override 38 | public Export apply(String s) { 39 | return new ExportImpl<>(s); 40 | } 41 | 42 | @Override 43 | public Export get(String name) { 44 | //noinspection unchecked 45 | return (Export) this.exports.computeIfAbsent(name.toLowerCase(), this); 46 | } 47 | 48 | @Override 49 | public void remove(String name) { 50 | Export export = this.exports.get(name.toLowerCase()); 51 | if (export != null) { 52 | export.clear(); 53 | } 54 | } 55 | 56 | @Override 57 | public Collection> getAll() { 58 | return Collections.unmodifiableCollection(this.exports.values()); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/environment/registry/ScriptRegistry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.environment.registry; 27 | 28 | import me.lucko.scriptcontroller.environment.script.Script; 29 | 30 | import java.nio.file.Path; 31 | import java.util.Map; 32 | 33 | /** 34 | * A registry of {@link Script}s 35 | */ 36 | public interface ScriptRegistry extends AutoCloseable { 37 | 38 | static ScriptRegistry create() { 39 | return new ScriptRegistryImpl(); 40 | } 41 | 42 | /** 43 | * Registers a script 44 | * 45 | * @param script the script to register 46 | */ 47 | void register(Script script); 48 | 49 | /** 50 | * Unregisters a script 51 | * 52 | * @param script the script to unregister 53 | */ 54 | void unregister(Script script); 55 | 56 | /** 57 | * Gets a script by path 58 | * 59 | * @param path the path 60 | * @return a script for the path, or null 61 | */ 62 | Script getScript(Path path); 63 | 64 | /** 65 | * Gets all scripts known to this registry 66 | * 67 | * @return the scripts 68 | */ 69 | Map getAll(); 70 | 71 | @Override 72 | void close(); 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/internal/FallbackSystemLogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.internal; 27 | 28 | import me.lucko.scriptcontroller.logging.SystemLogger; 29 | 30 | import java.util.function.Supplier; 31 | import java.util.logging.Logger; 32 | 33 | final class FallbackSystemLogger implements SystemLogger { 34 | public static final Supplier INSTANCE = FallbackSystemLogger::getInstance; 35 | 36 | private static SystemLogger instance = null; 37 | private static synchronized SystemLogger getInstance() { 38 | if (instance == null) { 39 | instance = new FallbackSystemLogger(); 40 | } 41 | return instance; 42 | } 43 | 44 | private final Logger logger = Logger.getLogger(ScriptControllerImpl.class.getName()); 45 | 46 | private FallbackSystemLogger() { 47 | 48 | } 49 | 50 | @Override 51 | public void info(String message) { 52 | this.logger.info(message); 53 | } 54 | 55 | @Override 56 | public void warning(String message) { 57 | this.logger.warning(message); 58 | } 59 | 60 | @Override 61 | public void severe(String message) { 62 | this.logger.severe(message); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/logging/SystemLogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.logging; 27 | 28 | import java.util.Objects; 29 | import java.util.logging.Logger; 30 | 31 | /** 32 | * Represents a bridge between the platforms logger and a ScriptController. 33 | */ 34 | public interface SystemLogger { 35 | 36 | /** 37 | * Creates a {@link SystemLogger} using a java logger 38 | * 39 | * @param logger the logger 40 | * @return a new system logger 41 | */ 42 | static SystemLogger usingJavaLogger(Logger logger) { 43 | Objects.requireNonNull(logger, "logger"); 44 | return new SystemLogger() { 45 | @Override 46 | public void info(String message) { 47 | logger.info(message); 48 | } 49 | 50 | @Override 51 | public void warning(String message) { 52 | logger.warning(message); 53 | } 54 | 55 | @Override 56 | public void severe(String message) { 57 | logger.severe(message); 58 | } 59 | }; 60 | } 61 | 62 | void info(String message); 63 | 64 | void warning(String message); 65 | 66 | void severe(String message); 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/environment/registry/ScriptRegistryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.environment.registry; 27 | 28 | import me.lucko.scriptcontroller.closable.CompositeAutoClosable; 29 | import me.lucko.scriptcontroller.environment.script.Script; 30 | 31 | import java.nio.file.Path; 32 | import java.util.Collections; 33 | import java.util.HashMap; 34 | import java.util.Map; 35 | 36 | final class ScriptRegistryImpl implements ScriptRegistry { 37 | private final Map scripts = new HashMap<>(); 38 | 39 | @Override 40 | public void register(Script script) { 41 | this.scripts.put(script.getPath(), script); 42 | } 43 | 44 | @Override 45 | public void unregister(Script script) { 46 | this.scripts.remove(script.getPath()); 47 | } 48 | 49 | @Override 50 | public Script getScript(Path path) { 51 | return this.scripts.get(path); 52 | } 53 | 54 | @Override 55 | public Map getAll() { 56 | return Collections.unmodifiableMap(this.scripts); 57 | } 58 | 59 | @Override 60 | public void close() { 61 | CompositeAutoClosable.create() 62 | .bindAll(this.scripts.values()) 63 | .closeAndReportExceptions(); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/bindings/BindingsBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.bindings; 27 | 28 | import java.util.function.Consumer; 29 | 30 | import javax.script.Bindings; 31 | 32 | /** 33 | * Chainable bindings builder. 34 | * 35 | * @see Bindings 36 | */ 37 | public interface BindingsBuilder { 38 | 39 | /** 40 | * Creates a new {@link BindingsBuilder} 41 | * 42 | * @param bindings the bindings to apply to 43 | * @return a new builder 44 | */ 45 | static BindingsBuilder wrap(Bindings bindings) { 46 | return new BindingsBuilderImpl(bindings); 47 | } 48 | 49 | /** 50 | * Adds a binding to the builder 51 | * 52 | * @param name the name of the binding 53 | * @param object the value of the binding 54 | * @return this builder (for chaining) 55 | */ 56 | BindingsBuilder put(String name, Object object); 57 | 58 | /** 59 | * Applies an action to this builder 60 | * 61 | * @param action the action to apply 62 | * @return this builder (for chaining) 63 | */ 64 | BindingsBuilder apply(Consumer action); 65 | 66 | /** 67 | * Returns the modified {@link Bindings} instance 68 | * 69 | * @return the bindings 70 | */ 71 | Bindings build(); 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/closable/CompositeAutoClosableImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.closable; 27 | 28 | import java.util.ArrayList; 29 | import java.util.Deque; 30 | import java.util.List; 31 | import java.util.Objects; 32 | import java.util.concurrent.ConcurrentLinkedDeque; 33 | 34 | /** 35 | * A simple implementation of {@link CompositeAutoClosable} using a 36 | * {@link ConcurrentLinkedDeque}. 37 | */ 38 | class CompositeAutoClosableImpl implements CompositeAutoClosable { 39 | private final Deque closeables = new ConcurrentLinkedDeque<>(); 40 | 41 | @Override 42 | public CompositeAutoClosable bind(AutoCloseable autoCloseable) { 43 | Objects.requireNonNull(autoCloseable, "autoCloseable"); 44 | this.closeables.push(autoCloseable); 45 | return this; 46 | } 47 | 48 | @Override 49 | public void close() throws CompositeClosingException { 50 | List caught = new ArrayList<>(); 51 | for (AutoCloseable ac; (ac = this.closeables.poll()) != null; ) { 52 | try { 53 | ac.close(); 54 | } catch (Exception e) { 55 | caught.add(e); 56 | } 57 | } 58 | 59 | if (!caught.isEmpty()) { 60 | throw new CompositeClosingException(caught); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/environment/loader/ScriptLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.environment.loader; 27 | 28 | import me.lucko.scriptcontroller.environment.ScriptEnvironment; 29 | 30 | import java.util.Arrays; 31 | import java.util.Collection; 32 | 33 | /** 34 | * An object capable of loadings scripts and monitoring them for updates. 35 | */ 36 | public interface ScriptLoader extends AutoCloseable { 37 | 38 | /** 39 | * Gets the script environment this loader is operating in 40 | * 41 | * @return the parent environment 42 | */ 43 | ScriptEnvironment getEnvironment(); 44 | 45 | /** 46 | * Loads and watches a script 47 | * 48 | * @param paths the path to watch 49 | */ 50 | default void watch(String... paths) { 51 | this.watchAll(Arrays.asList(paths)); 52 | } 53 | 54 | /** 55 | * Loads and watches a collection of scripts 56 | * 57 | * @param paths the paths to watch 58 | */ 59 | void watchAll(Collection paths); 60 | 61 | /** 62 | * Unloads a script 63 | * 64 | * @param paths the path to unwatch 65 | */ 66 | default void unwatch(String... paths) { 67 | this.unwatchAll(Arrays.asList(paths)); 68 | } 69 | 70 | /** 71 | * Unloads a collection of scripts 72 | * 73 | * @param paths the paths to unwatch 74 | */ 75 | void unwatchAll(Collection paths); 76 | 77 | @Override 78 | void close() throws Exception; 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/bindings/BindingsSupplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.bindings; 27 | 28 | import me.lucko.scriptcontroller.environment.script.Script; 29 | 30 | import java.util.Map; 31 | 32 | /** 33 | * Supplies a set of bindings for scripts to use at runtime. 34 | */ 35 | @FunctionalInterface 36 | public interface BindingsSupplier { 37 | 38 | /** 39 | * Returns a {@link BindingsSupplier} that encapsulates a single binding. 40 | * 41 | * @param name the name of the binding 42 | * @param value the corresponding value 43 | * @return the resultant bindings supplier 44 | */ 45 | static BindingsSupplier singleBinding(String name, Object value) { 46 | return (script, accumulator) -> accumulator.put(name, value); 47 | } 48 | 49 | /** 50 | * Returns a {@link BindingsSupplier} that encapsulates a map of objects. 51 | * 52 | * @param map the map of bindings 53 | * @return the resultant bindings supplier 54 | */ 55 | static BindingsSupplier ofMap(Map map) { 56 | return (script, accumulator) -> { 57 | for (Map.Entry entry : map.entrySet()) { 58 | accumulator.put(entry.getKey(), entry.getValue()); 59 | } 60 | }; 61 | } 62 | 63 | /** 64 | * Supplies this suppliers bindings for the given script. 65 | * 66 | * @param script the script the bindings are for 67 | * @param accumulator the accumulator 68 | */ 69 | void supplyBindings(Script script, BindingsBuilder accumulator); 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/logging/ScriptLoggerImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.logging; 27 | 28 | import me.lucko.scriptcontroller.environment.script.Script; 29 | 30 | final class ScriptLoggerImpl implements ScriptLogger { 31 | private static final String FORMAT = "[%s]%s"; 32 | private final SystemLogger logger; 33 | private final Script script; 34 | 35 | public ScriptLoggerImpl(SystemLogger logger, Script script) { 36 | this.logger = logger; 37 | this.script = script; 38 | } 39 | 40 | @Override 41 | public void info(Object... message) { 42 | this.logger.info(formatLog(message)); 43 | } 44 | 45 | @Override 46 | public void warn(Object... message) { 47 | this.logger.warning(formatLog(message)); 48 | } 49 | 50 | @Override 51 | public void error(Object... message) { 52 | this.logger.severe(formatLog(message)); 53 | } 54 | 55 | private String formatLog(Object... message) { 56 | return String.format(FORMAT, this.script.getName(), format(message)); 57 | } 58 | 59 | private static String format(Object[] message) { 60 | if (message == null || message.length == 0) { 61 | return " "; 62 | } else if (message.length == 1) { 63 | return " " + String.valueOf(message[0]); 64 | } else { 65 | StringBuilder sb = new StringBuilder(); 66 | for (Object o : message) { 67 | sb.append(" ").append(String.valueOf(o)); 68 | } 69 | return sb.toString(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/environment/loader/DelegateScriptLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.environment.loader; 27 | 28 | import me.lucko.scriptcontroller.environment.ScriptEnvironment; 29 | 30 | import java.util.Collection; 31 | import java.util.HashSet; 32 | import java.util.Set; 33 | 34 | /** 35 | * A {@link ScriptLoader} which delegates calls to a parent, 36 | * but keeps track of the files watched via its instance. 37 | */ 38 | public class DelegateScriptLoader implements ScriptLoader { 39 | private ScriptLoader parent; 40 | private Set paths = new HashSet<>(); 41 | 42 | public DelegateScriptLoader(ScriptLoader parent) { 43 | this.parent = parent; 44 | } 45 | 46 | @Override 47 | public ScriptEnvironment getEnvironment() { 48 | return this.parent.getEnvironment(); 49 | } 50 | 51 | @Override 52 | public void watchAll(Collection paths) { 53 | for (String s : paths) { 54 | if (this.paths.contains(s)) { 55 | continue; 56 | } 57 | 58 | this.paths.add(s); 59 | this.parent.watch(s); 60 | } 61 | } 62 | 63 | @Override 64 | public void unwatchAll(Collection paths) { 65 | for (String s : paths) { 66 | if (!this.paths.contains(s)) { 67 | continue; 68 | } 69 | 70 | this.paths.remove(s); 71 | this.parent.unwatch(s); 72 | } 73 | } 74 | 75 | @Override 76 | public void close() { 77 | this.parent.unwatchAll(this.paths); 78 | this.paths.clear(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/exports/ExportRegistry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.exports; 27 | 28 | import java.util.Collection; 29 | 30 | /** 31 | * A registry of {@link Export}s shared between scripts. 32 | * 33 | *

Allows scripts to share persistent state, or provide a resource in a known 34 | * namespace.

35 | * 36 | *

Some scripts will be designed to be totally stateless, and may use exports 37 | * to store state between invocations.

38 | */ 39 | public interface ExportRegistry { 40 | 41 | /** 42 | * Creates a new standalone {@link ExportRegistry}. 43 | * 44 | * @return a new export registry 45 | */ 46 | static ExportRegistry create() { 47 | return new ExportRegistryImpl(); 48 | } 49 | 50 | /** 51 | * Gets an export 52 | * 53 | * @param name the name of the export 54 | * @param the export type 55 | * @return the export 56 | */ 57 | Export get(String name); 58 | 59 | /** 60 | * Gets a pointer to an export 61 | * 62 | * @param name the name of the export 63 | * @param the export type 64 | * @return a pointer 65 | * @see Export.Pointer 66 | */ 67 | default Export.Pointer pointer(String name) { 68 | return this.get(name).pointer(); 69 | } 70 | 71 | /** 72 | * Deletes an export 73 | * 74 | * @param name the name of the export to remove. 75 | */ 76 | void remove(String name); 77 | 78 | /** 79 | * Returns a collection of all known exports. 80 | * 81 | * @return a collection of known exports 82 | */ 83 | Collection> getAll(); 84 | 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ScriptController 2 | 3 | Extended API for Java's [Scripting Engine framework](https://docs.oracle.com/javase/8/docs/api/javax/script/package-summary.html) (`javax.script`) with the Nashorn JavaScript engine. 4 | 5 | 6 | ScriptController provides: 7 | 8 | * Automatic detection & reloading of script files 9 | * Global export registry system 10 | * Builder-style API for constructing new controllers and environments 11 | 12 | ### Usage 13 | 14 | The main entry point into the API is via `ScriptController`. 15 | 16 | The following is a valid way to obtain an instance. 17 | 18 | ```java 19 | ScriptController controller = ScriptController.builder().build(); 20 | ``` 21 | 22 | However, it's likely that you'll want to customize certain aspects of the controller. 23 | 24 | ```java 25 | Logger logger = Logger.getLogger("my-logger"); 26 | SpecialObject mySpecialObject = new SpecialObject(); 27 | 28 | EnvironmentSettings environmentSettings = EnvironmentSettings.builder() 29 | .initScript("init.js") 30 | .withDefaultPackageImport("java.util") 31 | .withDefaultTypeImport("me.lucko.test.MyTestClass") 32 | .withDefaultTypeImport("com.example.RuntimeManager") 33 | .withBindings((script, accumulator) -> { 34 | accumulator.put("specialObject", mySpecialObject); 35 | accumulator.put("bootstrap", this); 36 | }) 37 | .build(); 38 | 39 | ScriptController controller = ScriptController.builder() 40 | .logger(SystemLogger.usingJavaLogger(logger)) 41 | .withDirectory(Paths.get("scripts/")) 42 | .defaultEnvironmentSettings(environmentSettings) 43 | .build(); 44 | ``` 45 | 46 | These are just a few examples of the available settings. ScriptController is designed with flexibility in mind. 47 | 48 | `ScriptController`s "manage" a number of `ScriptEnvironments`, which center around a root scripts directory. 49 | 50 | You can define these environments when building the controller, using `.withDirectory(...)`, or after the controller has been constructed. 51 | 52 | ```java 53 | ScriptController controller = ScriptController.builder().build(); 54 | ScriptEnvironment env = controller.setupNewEnvironment(Paths.get("src"), EnvironmentSettings.defaults()); 55 | ``` 56 | 57 | `ScriptEnvironment` exposes further instances which make up the overall system. 58 | 59 | ```java 60 | ExportRegistry exports = env.getExportRegistry(); 61 | EnvironmentScriptLoader loader = env.getLoader(); 62 | ScriptRegistry scriptRegistry = env.getScriptRegistry(); 63 | ``` 64 | 65 | * `ExportRegistry` holds a shared set of "exports". This is effectively a namespace which is shared between scripts. 66 | * `EnvironmentScriptLoader` is responsible for loading/reloading/unloading scripts, and monitoring the source directory for changes. 67 | * `ScriptRegistry` holds all currently loaded scripts. 68 | 69 | The library has extensive JavaDocs - all public classes, methods and fields have documentation. More detailed commentary and explanation on the purpose, behaviour and usage of methods and classes can be found there. 70 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/environment/script/Script.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.environment.script; 27 | 28 | import me.lucko.scriptcontroller.closable.CompositeAutoClosable; 29 | import me.lucko.scriptcontroller.logging.ScriptLogger; 30 | 31 | import java.nio.file.Path; 32 | import java.util.Set; 33 | 34 | /** 35 | * Represents an individual script 36 | */ 37 | public interface Script extends AutoCloseable { 38 | 39 | /** 40 | * Gets the name of the script, usually formed from the scripts 41 | * {@link #getPath() path} {@link Path#getFileName() file name}. 42 | * 43 | * @return the name of the script 44 | */ 45 | String getName(); 46 | 47 | /** 48 | * Gets the path of the script. 49 | * 50 | *

The path is relative to the loader directory.

51 | * 52 | * @return the path 53 | */ 54 | Path getPath(); 55 | 56 | /** 57 | * Gets the scripts logger instance 58 | * 59 | * @return the logger 60 | */ 61 | ScriptLogger getLogger(); 62 | 63 | /** 64 | * Gets the scripts composite closable registry. 65 | * 66 | * @return the scripts closable registry 67 | */ 68 | CompositeAutoClosable getClosables(); 69 | 70 | /** 71 | * Gets the other scripts depended on by this script. 72 | * 73 | * @return this scripts dependencies 74 | */ 75 | Set getDependencies(); 76 | 77 | /** 78 | * Marks that this script depends on another script. 79 | * 80 | * @param path the other script 81 | */ 82 | void depend(String path); 83 | 84 | /** 85 | * Marks that this script depends on another script. 86 | * 87 | * @param path the other script 88 | */ 89 | void depend(Path path); 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/environment/loader/ScriptLoadingExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.environment.loader; 27 | 28 | import java.util.Objects; 29 | import java.util.concurrent.Executor; 30 | import java.util.concurrent.ScheduledExecutorService; 31 | import java.util.concurrent.ScheduledFuture; 32 | import java.util.concurrent.TimeUnit; 33 | 34 | /** 35 | * A simplified scheduler for {@link ScriptLoader}s. 36 | */ 37 | public interface ScriptLoadingExecutor extends Executor { 38 | 39 | /** 40 | * Creates a {@link ScriptLoadingExecutor} using a java executor service 41 | * 42 | * @param service the service 43 | * @return a new loading scheduler 44 | */ 45 | static ScriptLoadingExecutor usingJavaScheduler(ScheduledExecutorService service) { 46 | Objects.requireNonNull(service, "service"); 47 | return new ScriptLoadingExecutor() { 48 | @Override 49 | public AutoCloseable scheduleAtFixedRate(Runnable task, long time, TimeUnit unit) { 50 | ScheduledFuture future = service.scheduleAtFixedRate(task, 0L, time, unit); 51 | return () -> future.cancel(false); 52 | } 53 | 54 | @Override 55 | public void execute(Runnable command) { 56 | service.execute(command); 57 | } 58 | }; 59 | } 60 | 61 | /** 62 | * Schedules a task to run at a fixed rate, with the first execution 63 | * occurring with no delay. 64 | * 65 | * @param task the task 66 | * @param time the time 67 | * @param unit the unit of the time 68 | * @return an {@link AutoCloseable}, which will cancel the task when 69 | * {@link AutoCloseable#close() closed}. 70 | * @see java.util.concurrent.ScheduledExecutorService#scheduleAtFixedRate(Runnable, long, long, TimeUnit) 71 | */ 72 | AutoCloseable scheduleAtFixedRate(Runnable task, long time, TimeUnit unit); 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/environment/ScriptEnvironment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.environment; 27 | 28 | import me.lucko.scriptcontroller.ScriptController; 29 | import me.lucko.scriptcontroller.environment.loader.EnvironmentScriptLoader; 30 | import me.lucko.scriptcontroller.environment.registry.ScriptRegistry; 31 | import me.lucko.scriptcontroller.environment.settings.EnvironmentSettings; 32 | import me.lucko.scriptcontroller.exports.ExportRegistry; 33 | 34 | import java.nio.file.Path; 35 | 36 | /** 37 | * Represents an isolated environment in which scripts run 38 | * 39 | * Each environment operates within a given root {@link Path directory}, under a 40 | * {@link ScriptController}. 41 | */ 42 | public interface ScriptEnvironment extends AutoCloseable { 43 | 44 | /** 45 | * Gets the script controller which created this environment 46 | * 47 | * @return the parent controller 48 | */ 49 | ScriptController getController(); 50 | 51 | /** 52 | * Gets the environment settings 53 | * 54 | * @return the settings 55 | */ 56 | EnvironmentSettings getSettings(); 57 | 58 | /** 59 | * Gets the environments root scripts directory 60 | * 61 | * @return the root directory of this environment 62 | */ 63 | Path getDirectory(); 64 | 65 | /** 66 | * Gets the script loader used by this environment. 67 | * 68 | *

Each environment has it's own loader.

69 | * 70 | * @return the script loader 71 | */ 72 | EnvironmentScriptLoader getLoader(); 73 | 74 | /** 75 | * Gets the script registry, containing all loaded scripts within this 76 | * environment 77 | * 78 | * @return the script registry 79 | */ 80 | ScriptRegistry getScriptRegistry(); 81 | 82 | /** 83 | * Gets the export registry for this environment 84 | * 85 | * @return the export registry 86 | */ 87 | ExportRegistry getExportRegistry(); 88 | 89 | } 90 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/ 2 | 3 | ### Intellij ### 4 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 5 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 6 | 7 | # User-specific stuff: 8 | .idea/ 9 | *.iws 10 | /out/ 11 | *.iml 12 | .idea_modules/ 13 | 14 | # JIRA plugin 15 | atlassian-ide-plugin.xml 16 | 17 | # Crashlytics plugin (for Android Studio and IntelliJ) 18 | com_crashlytics_export_strings.xml 19 | crashlytics.properties 20 | crashlytics-build.properties 21 | fabric.properties 22 | 23 | 24 | ### Maven ### 25 | target/ 26 | pom.xml.tag 27 | pom.xml.releaseBackup 28 | pom.xml.versionsBackup 29 | pom.xml.next 30 | release.properties 31 | dependency-reduced-pom.xml 32 | buildNumber.properties 33 | .mvn/timing.properties 34 | 35 | 36 | ### Eclipse ### 37 | 38 | .metadata 39 | bin/ 40 | tmp/ 41 | *.tmp 42 | *.bak 43 | *.swp 44 | *~.nib 45 | local.properties 46 | .settings/ 47 | .loadpath 48 | .recommenders 49 | 50 | # Eclipse Core 51 | .project 52 | 53 | # External tool builders 54 | .externalToolBuilders/ 55 | 56 | # Locally stored "Eclipse launch configurations" 57 | *.launch 58 | 59 | # PyDev specific (Python IDE for Eclipse) 60 | *.pydevproject 61 | 62 | # CDT-specific (C/C++ Development Tooling) 63 | .cproject 64 | 65 | # JDT-specific (Eclipse Java Development Tools) 66 | .classpath 67 | 68 | # Java annotation processor (APT) 69 | .factorypath 70 | 71 | # PDT-specific (PHP Development Tools) 72 | .buildpath 73 | 74 | # sbteclipse plugin 75 | .target 76 | 77 | # Tern plugin 78 | .tern-project 79 | 80 | # TeXlipse plugin 81 | .texlipse 82 | 83 | # STS (Spring Tool Suite) 84 | .springBeans 85 | 86 | # Code Recommenders 87 | .recommenders/ 88 | 89 | 90 | ### Linux ### 91 | *~ 92 | 93 | # temporary files which can be created if a process still has a handle open of a deleted file 94 | .fuse_hidden* 95 | 96 | # KDE directory preferences 97 | .directory 98 | 99 | # Linux trash folder which might appear on any partition or disk 100 | .Trash-* 101 | 102 | # .nfs files are created when an open file is removed but is still being accessed 103 | .nfs* 104 | 105 | 106 | ### macOS ### 107 | *.DS_Store 108 | .AppleDouble 109 | .LSOverride 110 | 111 | # Icon must end with two \r 112 | Icon 113 | # Thumbnails 114 | ._* 115 | # Files that might appear in the root of a volume 116 | .DocumentRevisions-V100 117 | .fseventsd 118 | .Spotlight-V100 119 | .TemporaryItems 120 | .Trashes 121 | .VolumeIcon.icns 122 | .com.apple.timemachine.donotpresent 123 | # Directories potentially created on remote AFP share 124 | .AppleDB 125 | .AppleDesktop 126 | Network Trash Folder 127 | Temporary Items 128 | .apdisk 129 | 130 | 131 | ### Windows ### 132 | # Windows image file caches 133 | Thumbs.db 134 | ehthumbs.db 135 | 136 | # Folder config file 137 | Desktop.ini 138 | 139 | # Recycle Bin used on file shares 140 | $RECYCLE.BIN/ 141 | 142 | # Windows Installer files 143 | *.cab 144 | *.msi 145 | *.msm 146 | *.msp 147 | 148 | # Windows shortcuts 149 | *.lnk 150 | 151 | 152 | ### Java ### 153 | *.class 154 | 155 | # Mobile Tools for Java (J2ME) 156 | .mtj.tmp/ 157 | 158 | # Package Files # 159 | *.jar 160 | *.war 161 | *.ear 162 | 163 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 164 | hs_err_pid* -------------------------------------------------------------------------------- /src/test/java/me/lucko/scriptcontroller/ControllerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller; 27 | 28 | import com.google.common.io.Resources; 29 | 30 | import me.lucko.scriptcontroller.bindings.BindingsSupplier; 31 | import me.lucko.scriptcontroller.environment.ScriptEnvironment; 32 | import me.lucko.scriptcontroller.environment.settings.EnvironmentSettings; 33 | import me.lucko.scriptcontroller.exports.ExportRegistry; 34 | 35 | import org.junit.Rule; 36 | import org.junit.Test; 37 | import org.junit.rules.TemporaryFolder; 38 | 39 | import java.io.File; 40 | import java.io.FileOutputStream; 41 | import java.io.IOException; 42 | import java.net.URL; 43 | import java.util.Collection; 44 | import java.util.concurrent.atomic.AtomicBoolean; 45 | 46 | import static org.junit.Assert.assertEquals; 47 | import static org.junit.Assert.assertTrue; 48 | 49 | public class ControllerTest { 50 | 51 | @Rule 52 | public TemporaryFolder folder = new TemporaryFolder(); 53 | 54 | @Test 55 | public void test() throws IOException { 56 | File scripts = this.folder.newFolder("scripts"); 57 | copyResource(getClass().getResource("/test.js"), scripts, "init.js"); 58 | 59 | AtomicBoolean callback = new AtomicBoolean(false); 60 | 61 | ScriptController controller = ScriptController.builder() 62 | .withDirectory(scripts.toPath()) 63 | .defaultEnvironmentSettings(EnvironmentSettings.builder() 64 | .withBindings(BindingsSupplier.singleBinding("testCallback", (Runnable) () -> callback.set(true))) 65 | .build() 66 | ) 67 | .build(); 68 | 69 | assertTrue(callback.get()); 70 | 71 | Collection environments = controller.getEnvironments(); 72 | assertEquals(1, environments.size()); 73 | 74 | ScriptEnvironment environment = environments.iterator().next(); 75 | 76 | ExportRegistry exports = environment.getExportRegistry(); 77 | assertEquals("Hello world", exports.get("test").get()); 78 | 79 | controller.shutdown(); 80 | } 81 | 82 | private static void copyResource(URL in, File out, String name) throws IOException { 83 | File outFile = new File(out, name); 84 | try (FileOutputStream outputStream = new FileOutputStream(outFile)) { 85 | Resources.copy(in, outputStream); 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/exports/Export.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.exports; 27 | 28 | import java.util.function.Supplier; 29 | 30 | /** 31 | * A namespaced value wrapper. 32 | * 33 | * @param the export type 34 | */ 35 | public interface Export { 36 | 37 | /** 38 | * Gets the name of the export 39 | * 40 | * @return the name 41 | */ 42 | String name(); 43 | 44 | /** 45 | * Returns a pointer to this export 46 | * 47 | * @return a pointer 48 | */ 49 | Pointer pointer(); 50 | 51 | /** 52 | * Gets the current value of the export 53 | * 54 | * @return the current value 55 | */ 56 | T get(); 57 | 58 | /** 59 | * Gets the current value of the export, or returns the other if a value 60 | * isn't present. 61 | * 62 | * @param other the other value 63 | * @return the value 64 | */ 65 | T get(T other); 66 | 67 | /** 68 | * Sets the value of the export 69 | * 70 | * @param value the value to set 71 | * @return this 72 | */ 73 | Export put(T value); 74 | 75 | /** 76 | * Sets the value of the export if a value isn't already present, 77 | * then returns the export 78 | * 79 | * @param value the value to set if absent 80 | * @return this 81 | */ 82 | Export putIfAbsent(T value); 83 | 84 | /** 85 | * Uses the provided function to compute a value if one isn't already present. 86 | * 87 | * @param other the other value 88 | * @return the value 89 | */ 90 | Export computeIfAbsent(Supplier other); 91 | 92 | /** 93 | * Gets if this export has a value 94 | * 95 | * @return true if this export has a value 96 | */ 97 | boolean containsValue(); 98 | 99 | /** 100 | * Clears the export 101 | */ 102 | void clear(); 103 | 104 | /** 105 | * A pointer to the value of an export. 106 | * 107 | *

Can be used in scripts to simplify the process of obtaining an export 108 | * whose instance is likely to change during runtime.

109 | * 110 | *

e.g.

111 | * 112 | * 113 | * const someExport = exports.pointer("example-namespace"); 114 | * someExport().doSomething(); 115 | * 116 | * 117 | * @param the type 118 | */ 119 | interface Pointer extends Supplier { 120 | 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/exports/ExportImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.exports; 27 | 28 | import java.util.concurrent.locks.Lock; 29 | import java.util.concurrent.locks.ReadWriteLock; 30 | import java.util.concurrent.locks.ReentrantReadWriteLock; 31 | import java.util.function.Supplier; 32 | 33 | /** 34 | * Atomic implementation of {@link Export}. 35 | * 36 | * @param the type 37 | */ 38 | final class ExportImpl implements Export { 39 | private final String name; 40 | private final ReadWriteLock lock = new ReentrantReadWriteLock(); 41 | 42 | private T value = null; 43 | private Pointer pointer = null; 44 | 45 | ExportImpl(String name) { 46 | this.name = name; 47 | } 48 | 49 | private Lock readLock() { return this.lock.readLock(); } 50 | private Lock writeLock() { return this.lock.writeLock(); } 51 | 52 | @Override 53 | public String name() { 54 | return this.name; 55 | } 56 | 57 | @Override 58 | public synchronized Pointer pointer() { 59 | if (this.pointer == null) { 60 | this.pointer = new PointerImpl<>(this); 61 | } 62 | return this.pointer; 63 | } 64 | 65 | @Override 66 | public T get() { 67 | readLock().lock(); 68 | try { 69 | return this.value; 70 | } finally { 71 | readLock().unlock(); 72 | } 73 | } 74 | 75 | @Override 76 | public T get(T other) { 77 | T value = get(); 78 | return value != null ? value : other; 79 | } 80 | 81 | @Override 82 | public Export put(T value) { 83 | writeLock().lock(); 84 | try { 85 | this.value = value; 86 | } finally { 87 | writeLock().unlock(); 88 | } 89 | return this; 90 | } 91 | 92 | @Override 93 | public Export putIfAbsent(T value) { 94 | writeLock().lock(); 95 | try { 96 | if (this.value == null) { 97 | this.value = value; 98 | } 99 | } finally { 100 | writeLock().unlock(); 101 | } 102 | return this; 103 | } 104 | 105 | @Override 106 | public Export computeIfAbsent(Supplier other) { 107 | writeLock().lock(); 108 | try { 109 | if (this.value == null) { 110 | this.value = other.get(); 111 | } 112 | } finally { 113 | writeLock().unlock(); 114 | } 115 | return this; 116 | } 117 | 118 | @Override 119 | public boolean containsValue() { 120 | readLock().lock(); 121 | try { 122 | return this.value != null; 123 | } finally { 124 | readLock().unlock(); 125 | } 126 | } 127 | 128 | @Override 129 | public void clear() { 130 | writeLock().lock(); 131 | try { 132 | this.value = null; 133 | } finally { 134 | writeLock().unlock(); 135 | } 136 | } 137 | 138 | private static final class PointerImpl implements Pointer { 139 | private final Export export; 140 | 141 | private PointerImpl(Export export) { 142 | this.export = export; 143 | } 144 | 145 | @Override 146 | public T get() { 147 | return this.export.get(); 148 | } 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/ScriptController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller; 27 | 28 | import me.lucko.scriptcontroller.environment.ScriptEnvironment; 29 | import me.lucko.scriptcontroller.environment.settings.EnvironmentSettings; 30 | import me.lucko.scriptcontroller.internal.ScriptControllerImpl; 31 | import me.lucko.scriptcontroller.logging.SystemLogger; 32 | 33 | import java.nio.file.Path; 34 | import java.util.Collection; 35 | 36 | /** 37 | * Controls the execution and management of {@link ScriptEnvironment}s. 38 | */ 39 | public interface ScriptController { 40 | 41 | /** 42 | * Creates a new {@link Builder} using the internal implementation. 43 | * 44 | * @return the builder 45 | */ 46 | static Builder builder() { 47 | //noinspection deprecation 48 | return ScriptControllerImpl.builder(); 49 | } 50 | 51 | /** 52 | * Gets the {@link ScriptEnvironment}s being processed by the controller 53 | * 54 | * @return the environments 55 | */ 56 | Collection getEnvironments(); 57 | 58 | /** 59 | * Sets up a new {@link ScriptEnvironment} in the given load directory. 60 | * 61 | * @param loadDirectory the directory 62 | * @param settings the environment settings 63 | * @return the new environment 64 | * @throws UnsupportedOperationException if the controller does not support 65 | * setting up new environments after construction 66 | */ 67 | ScriptEnvironment setupNewEnvironment(Path loadDirectory, EnvironmentSettings settings); 68 | 69 | /** 70 | * Sets up a new {@link ScriptEnvironment} in the given load directory. 71 | * 72 | * @param loadDirectory the directory 73 | * @return the new environment 74 | * @throws UnsupportedOperationException if the controller does not support 75 | * setting up new environments after construction 76 | */ 77 | default ScriptEnvironment setupNewEnvironment(Path loadDirectory) { 78 | return setupNewEnvironment(loadDirectory, EnvironmentSettings.defaults()); 79 | } 80 | 81 | /** 82 | * Shuts down this script controller 83 | */ 84 | void shutdown(); 85 | 86 | /** 87 | * Builds a {@link ScriptController} 88 | */ 89 | interface Builder { 90 | 91 | /** 92 | * Add a directory to be handled by this script controller 93 | * 94 | * @param loadDirectory the directory 95 | * @return this builder 96 | */ 97 | Builder withDirectory(Path loadDirectory); 98 | 99 | /** 100 | * Defines the logger to use. 101 | * 102 | * @param logger the logger 103 | * @return this builder 104 | */ 105 | Builder logger(SystemLogger logger); 106 | 107 | /** 108 | * Defines the default {@link EnvironmentSettings} to use when this 109 | * controller creates new {@link ScriptEnvironment}s. 110 | * 111 | * @param settings the default settings 112 | * @return this builder 113 | */ 114 | Builder defaultEnvironmentSettings(EnvironmentSettings settings); 115 | 116 | /** 117 | * Builds a new {@link ScriptController} from the settings defined in 118 | * this builder 119 | * 120 | * @return a new controller 121 | */ 122 | ScriptController build(); 123 | 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/internal/ScriptEnvironmentImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.internal; 27 | 28 | import me.lucko.scriptcontroller.environment.ScriptEnvironment; 29 | import me.lucko.scriptcontroller.environment.loader.EnvironmentScriptLoader; 30 | import me.lucko.scriptcontroller.environment.registry.ScriptRegistry; 31 | import me.lucko.scriptcontroller.exports.ExportRegistry; 32 | 33 | import java.io.IOException; 34 | import java.nio.file.Path; 35 | 36 | import javax.script.ScriptEngine; 37 | import javax.script.ScriptEngineManager; 38 | 39 | class ScriptEnvironmentImpl implements ScriptEnvironment { 40 | 41 | /** The script controller */ 42 | private final ScriptControllerImpl controller; 43 | 44 | /** The environment settings */ 45 | private final EnvironmentSettingsImpl settings; 46 | 47 | /** The root directory of this environment */ 48 | private final Path directory; 49 | 50 | /** The script registry for scripts loaded in this environment */ 51 | private final ScriptRegistry scriptRegistry; 52 | 53 | /** The script export registry */ 54 | private final ExportRegistry exportRegistry; 55 | 56 | /** The script engine */ 57 | private final ScriptEngine scriptEngine; 58 | 59 | /** The script loader operating within this environment */ 60 | private final EnvironmentScriptLoader loader; 61 | 62 | /** An autoclosable which represents the repeating load task */ 63 | private final AutoCloseable loaderPollingTask; 64 | 65 | public ScriptEnvironmentImpl(ScriptControllerImpl controller, Path directory, EnvironmentSettingsImpl settings) { 66 | this.controller = controller; 67 | this.directory = directory; 68 | this.settings = settings; 69 | 70 | this.scriptRegistry = ScriptRegistry.create(); 71 | this.exportRegistry = ExportRegistry.create(); 72 | this.scriptEngine = new ScriptEngineManager(ScriptEnvironmentImpl.class.getClassLoader()).getEngineByName("nashorn"); 73 | try { 74 | this.loader = new ScriptLoaderImpl(this); 75 | } catch (IOException e) { 76 | throw new RuntimeException(e); 77 | } 78 | this.loader.watch(settings.getInitScript()); 79 | this.loader.preload(); 80 | 81 | // setup a ticking task on the environments loader 82 | Duration rate = settings.getPollRate(); 83 | this.loaderPollingTask = settings.getLoadExecutor().scheduleAtFixedRate(this.loader, rate.getDuration(), rate.getUnit()); 84 | } 85 | 86 | @Override 87 | public ScriptControllerImpl getController() { 88 | return this.controller; 89 | } 90 | 91 | @Override 92 | public EnvironmentSettingsImpl getSettings() { 93 | return this.settings; 94 | } 95 | 96 | @Override 97 | public Path getDirectory() { 98 | return this.directory; 99 | } 100 | 101 | @Override 102 | public EnvironmentScriptLoader getLoader() { 103 | return this.loader; 104 | } 105 | 106 | public ScriptEngine getScriptEngine() { 107 | return this.scriptEngine; 108 | } 109 | 110 | @Override 111 | public ScriptRegistry getScriptRegistry() { 112 | return this.scriptRegistry; 113 | } 114 | 115 | @Override 116 | public ExportRegistry getExportRegistry() { 117 | return this.exportRegistry; 118 | } 119 | 120 | @Override 121 | public void close() throws Exception { 122 | this.loaderPollingTask.close(); 123 | this.loader.close(); 124 | this.scriptRegistry.close(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/closable/CompositeAutoClosable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.closable; 27 | 28 | /** 29 | * Represents an {@link AutoCloseable} made up of several other 30 | * {@link AutoCloseable}s. 31 | * 32 | *

The {@link #close()} method closes in LIFO (Last-In-First-Out) order.

33 | * 34 | *

{@link CompositeAutoClosable}s can be reused. The instance is effectively 35 | * cleared on each invocation of {@link #close()}.

36 | */ 37 | public interface CompositeAutoClosable extends AutoCloseable { 38 | 39 | /** 40 | * Creates a new standalone {@link CompositeAutoClosable}. 41 | * 42 | * @return a new {@link CompositeAutoClosable}. 43 | */ 44 | static CompositeAutoClosable create() { 45 | return new CompositeAutoClosableImpl(); 46 | } 47 | 48 | /** 49 | * Binds an {@link AutoCloseable} with this composite closable. 50 | * 51 | *

Note that implementations do not keep track of duplicate contains 52 | * closables. If a single {@link AutoCloseable} is added twice, it will be 53 | * {@link #close() closed} twice.

54 | * 55 | * @param autoCloseable the closable to bind 56 | * @throws NullPointerException if the closable is null 57 | * @return this (for chaining) 58 | */ 59 | CompositeAutoClosable bind(AutoCloseable autoCloseable); 60 | 61 | /** 62 | * Binds all given {@link AutoCloseable} with this composite closable. 63 | * 64 | *

Note that implementations do not keep track of duplicate contains 65 | * closables. If a single {@link AutoCloseable} is added twice, it will be 66 | * {@link #close() closed} twice.

67 | * 68 | *

Ignores null values.

69 | * 70 | * @param autoCloseables the closables to bind 71 | * @return this (for chaining) 72 | */ 73 | default CompositeAutoClosable bindAll(AutoCloseable... autoCloseables) { 74 | for (AutoCloseable autoCloseable : autoCloseables) { 75 | if (autoCloseable == null) { 76 | continue; 77 | } 78 | bind(autoCloseable); 79 | } 80 | return this; 81 | } 82 | 83 | /** 84 | * Binds all given {@link AutoCloseable} with this composite closable. 85 | * 86 | *

Note that implementations do not keep track of duplicate contains 87 | * closables. If a single {@link AutoCloseable} is added twice, it will be 88 | * {@link #close() closed} twice.

89 | * 90 | *

Ignores null values.

91 | * 92 | * @param autoCloseables the closables to bind 93 | * @return this (for chaining) 94 | */ 95 | default CompositeAutoClosable bindAll(Iterable autoCloseables) { 96 | for (AutoCloseable autoCloseable : autoCloseables) { 97 | if (autoCloseable == null) { 98 | continue; 99 | } 100 | bind(autoCloseable); 101 | } 102 | return this; 103 | } 104 | 105 | /** 106 | * Closes this composite resource. 107 | * 108 | * @throws CompositeClosingException if any of the sub instances throw an 109 | * exception whilst closing 110 | */ 111 | @Override 112 | void close() throws CompositeClosingException; 113 | 114 | /** 115 | * Closes this composite resource, but doesn't rethrow or print any 116 | * exceptions. 117 | * 118 | * @see #close() 119 | */ 120 | default void closeSilently() { 121 | try { 122 | close(); 123 | } catch (CompositeClosingException e) { 124 | // ignore 125 | } 126 | } 127 | 128 | /** 129 | * Closes this composite resource, but simply prints any resultant 130 | * exceptions instead of rethrowing them. 131 | * 132 | * @see #close() 133 | * @see CompositeClosingException#printAllStackTraces() 134 | */ 135 | default void closeAndReportExceptions() { 136 | try { 137 | close(); 138 | } catch (CompositeClosingException e) { 139 | e.printAllStackTraces(); 140 | } 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.lucko 8 | scriptcontroller 9 | 1.3-SNAPSHOT 10 | 11 | ScriptController 12 | Extended API for Java's Scripting Engine framework 13 | https://github.com/lucko/ScriptController 14 | 15 | 16 | 17 | MIT 18 | https://opensource.org/licenses/MIT 19 | 20 | 21 | 22 | 23 | 24 | Luck 25 | git@lucko.me 26 | https://github.com/lucko 27 | 28 | 29 | 30 | 31 | scm:git:https://github.com/lucko/ScriptController.git 32 | scm:git:git@github.com:lucko/ScriptController.git 33 | https://github.com/lucko/ScriptController 34 | 35 | 36 | 37 | UTF-8 38 | 1.8 39 | 1.8 40 | 41 | 42 | true 43 | true 44 | 45 | 46 | 47 | 48 | luck-snapshots 49 | https://nexus.lucko.me/repository/maven-snapshots/ 50 | 51 | 52 | luck-releases 53 | https://nexus.lucko.me/repository/maven-releases/ 54 | 55 | 56 | 57 | 58 | 59 | junit 60 | junit 61 | 4.12 62 | test 63 | 64 | 65 | com.google.guava 66 | guava 67 | 23.0 68 | test 69 | 70 | 71 | 72 | 73 | 74 | sign 75 | 76 | 77 | 78 | org.apache.maven.plugins 79 | maven-gpg-plugin 80 | 1.6 81 | 82 | 83 | sign-artifacts 84 | verify 85 | 86 | sign 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | ossrh 96 | 97 | 98 | ossrh 99 | https://oss.sonatype.org/content/repositories/snapshots 100 | 101 | 102 | ossrh 103 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 104 | 105 | 106 | 107 | 108 | deployment 109 | 110 | 111 | 112 | org.apache.maven.plugins 113 | maven-source-plugin 114 | 3.0.1 115 | 116 | 117 | attach-sources 118 | 119 | jar 120 | 121 | 122 | 123 | 124 | 125 | org.apache.maven.plugins 126 | maven-javadoc-plugin 127 | 2.10.4 128 | 129 | 130 | attach-javadocs 131 | 132 | jar 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/internal/ScriptControllerImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.internal; 27 | 28 | import me.lucko.scriptcontroller.ScriptController; 29 | import me.lucko.scriptcontroller.closable.CompositeAutoClosable; 30 | import me.lucko.scriptcontroller.environment.ScriptEnvironment; 31 | import me.lucko.scriptcontroller.environment.settings.EnvironmentSettings; 32 | import me.lucko.scriptcontroller.logging.SystemLogger; 33 | 34 | import java.nio.file.Path; 35 | import java.util.Collection; 36 | import java.util.Collections; 37 | import java.util.HashMap; 38 | import java.util.HashSet; 39 | import java.util.Map; 40 | import java.util.Objects; 41 | import java.util.Set; 42 | import java.util.function.Supplier; 43 | 44 | public final class ScriptControllerImpl implements ScriptController { 45 | 46 | @Deprecated 47 | @SuppressWarnings("DeprecatedIsStillUsed") 48 | public static ScriptController.Builder builder() { 49 | return new Builder(); 50 | } 51 | 52 | @Deprecated 53 | @SuppressWarnings("DeprecatedIsStillUsed") 54 | public static EnvironmentSettings defaultSettings() { 55 | return EnvironmentSettingsImpl.defaults(); 56 | } 57 | 58 | @Deprecated 59 | @SuppressWarnings("DeprecatedIsStillUsed") 60 | public static EnvironmentSettings.Builder newSettingsBuilder() { 61 | return EnvironmentSettingsImpl.builder(); 62 | } 63 | 64 | /** 65 | * The sub environments originating from this controller 66 | */ 67 | private final Map environments = new HashMap<>(); 68 | 69 | // various settings and properties defined when the controller was created. 70 | private final SystemLogger logger; 71 | private final EnvironmentSettings defaultSettings; 72 | 73 | private ScriptControllerImpl(Builder builder) { 74 | this.logger = builder.logger.get(); 75 | this.defaultSettings = builder.settings; 76 | 77 | // setup the initial environments 78 | for (Path path : builder.directories) { 79 | //noinspection ResultOfMethodCallIgnored 80 | setupNewEnvironment(path); 81 | } 82 | } 83 | 84 | @Override 85 | public Collection getEnvironments() { 86 | return Collections.unmodifiableCollection(this.environments.values()); 87 | } 88 | 89 | @Override 90 | public synchronized ScriptEnvironment setupNewEnvironment(Path loadDirectory, EnvironmentSettings settings) { 91 | if (this.environments.containsKey(loadDirectory)) { 92 | throw new IllegalStateException("Already an environment setup at path " + loadDirectory.toString()); 93 | } 94 | 95 | // merge the provided setting with out defaults 96 | EnvironmentSettings mergedSettings = this.defaultSettings.toBuilder().mergeSettingsFrom(settings).build(); 97 | 98 | // create a new environment 99 | ScriptEnvironmentImpl environment = new ScriptEnvironmentImpl(this, loadDirectory, (EnvironmentSettingsImpl) mergedSettings); 100 | // store a ref to the new environment in the controller 101 | this.environments.put(loadDirectory, environment); 102 | return environment; 103 | } 104 | 105 | @Override 106 | public void shutdown() { 107 | CompositeAutoClosable.create() 108 | .bindAll(this.environments.values()) 109 | .closeAndReportExceptions(); 110 | } 111 | 112 | SystemLogger getLogger() { 113 | return this.logger; 114 | } 115 | 116 | private static final class Builder implements ScriptController.Builder { 117 | private final Set directories = new HashSet<>(); 118 | private Supplier logger = FallbackSystemLogger.INSTANCE; 119 | private EnvironmentSettings settings = EnvironmentSettings.defaults(); 120 | 121 | @Override 122 | public Builder withDirectory(Path loadDirectory) { 123 | this.directories.add(Objects.requireNonNull(loadDirectory, "loadDirectory")); 124 | return this; 125 | } 126 | 127 | @Override 128 | public Builder logger(SystemLogger logger) { 129 | Objects.requireNonNull(logger, "logger"); 130 | this.logger = () -> logger; 131 | return this; 132 | } 133 | 134 | @Override 135 | public Builder defaultEnvironmentSettings(EnvironmentSettings settings) { 136 | this.settings = Objects.requireNonNull(settings, "settings"); 137 | return this; 138 | } 139 | 140 | @Override 141 | public ScriptController build() { 142 | return new ScriptControllerImpl(this); 143 | } 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/environment/settings/EnvironmentSettings.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of scriptcontroller, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.environment.settings; 27 | 28 | import me.lucko.scriptcontroller.bindings.BindingsSupplier; 29 | import me.lucko.scriptcontroller.environment.ScriptEnvironment; 30 | import me.lucko.scriptcontroller.environment.loader.ScriptLoadingExecutor; 31 | import me.lucko.scriptcontroller.internal.ScriptControllerImpl; 32 | 33 | import java.util.Collection; 34 | import java.util.concurrent.Executor; 35 | import java.util.concurrent.TimeUnit; 36 | 37 | /** 38 | * Represents the settings for a given {@link ScriptEnvironment}. 39 | */ 40 | public interface EnvironmentSettings { 41 | 42 | /** 43 | * Creates a new {@link Builder}. 44 | * 45 | * @return a new builder 46 | */ 47 | static Builder builder() { 48 | //noinspection deprecation 49 | return ScriptControllerImpl.newSettingsBuilder(); 50 | } 51 | 52 | /** 53 | * Returns a default set of environment settings 54 | * 55 | * @return the default settings 56 | */ 57 | static EnvironmentSettings defaults() { 58 | //noinspection deprecation 59 | return ScriptControllerImpl.defaultSettings(); 60 | } 61 | 62 | /** 63 | * Returns a builder encapsulating the properties already defined by this 64 | * instance 65 | * 66 | * @return a builder 67 | */ 68 | default Builder toBuilder() { 69 | return builder().mergeSettingsFrom(this); 70 | } 71 | 72 | /** 73 | * Builds {@link EnvironmentSettings} 74 | */ 75 | interface Builder { 76 | 77 | /** 78 | * Applies the settings from the give instance to this builder 79 | * 80 | * @param other the other settings 81 | * @return this builder 82 | */ 83 | Builder mergeSettingsFrom(EnvironmentSettings other); 84 | 85 | /** 86 | * Define the executor service used to setup task to poll scripts for 87 | * changes and load new scripts. 88 | * 89 | * @param executor the executor 90 | * @return this builder 91 | */ 92 | Builder loadExecutor(ScriptLoadingExecutor executor); 93 | 94 | /** 95 | * Define the executor used to run scripts 96 | * 97 | * @param executor the executor 98 | * @return this builder 99 | */ 100 | Builder runExecutor(Executor executor); 101 | 102 | /** 103 | * Adds a bindings supplier to the settings 104 | * 105 | * @param supplier the bindings supplier 106 | * @return this builder 107 | */ 108 | Builder withBindings(BindingsSupplier supplier); 109 | 110 | /** 111 | * Marks that a {@link Package} should be imported by default. 112 | * 113 | * @param packageName the name of the package - see {@link Package#getName()}. 114 | * @return this builder 115 | */ 116 | Builder withDefaultPackageImport(String packageName); 117 | 118 | /** 119 | * Marks that {@link Package}s should be imported by default. 120 | * 121 | * @param packageNames the package names - see {@link Package#getName()}. 122 | * @return this builder 123 | */ 124 | Builder withDefaultPackageImports(Collection packageNames); 125 | 126 | /** 127 | * Marks that a {@link Class} should be imported by default. 128 | * 129 | * @param type the name of the class - see {@link Class#getName()} 130 | * @return this builder 131 | */ 132 | Builder withDefaultTypeImport(String type); 133 | 134 | /** 135 | * Marks that {@link Class}es should be imported by default. 136 | * 137 | * @param types class names - see {@link Class#getName()} 138 | * @return this builder 139 | */ 140 | Builder withDefaultTypeImports(Collection types); 141 | 142 | /** 143 | * Define how often the script loader should poll scripts for updates 144 | * 145 | * @param time the time 146 | * @param unit the unit 147 | * @return this builder 148 | */ 149 | Builder pollRate(long time, TimeUnit unit); 150 | 151 | /** 152 | * Defines the init script for the environment 153 | * 154 | * @param path the path 155 | * @return this builder 156 | */ 157 | Builder initScript(String path); 158 | 159 | /** 160 | * Builds a new {@link EnvironmentSettings} instance. 161 | * 162 | * @return the resultant environment settings 163 | */ 164 | EnvironmentSettings build(); 165 | 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/internal/EnvironmentSettingsImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of scriptcontroller, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.internal; 27 | 28 | import me.lucko.scriptcontroller.bindings.BindingsSupplier; 29 | import me.lucko.scriptcontroller.environment.loader.ScriptLoadingExecutor; 30 | import me.lucko.scriptcontroller.environment.settings.EnvironmentSettings; 31 | 32 | import java.util.Collection; 33 | import java.util.Collections; 34 | import java.util.HashSet; 35 | import java.util.LinkedHashSet; 36 | import java.util.Objects; 37 | import java.util.Set; 38 | import java.util.concurrent.Executor; 39 | import java.util.concurrent.Executors; 40 | import java.util.concurrent.TimeUnit; 41 | import java.util.function.Supplier; 42 | 43 | class EnvironmentSettingsImpl implements EnvironmentSettings { 44 | private static final Supplier DEFAULT_LOAD_EXECUTOR = () -> ScriptLoadingExecutor.usingJavaScheduler(Executors.newSingleThreadScheduledExecutor()); 45 | private static final Executor DEFAULT_RUN_EXECUTOR = Runnable::run; 46 | private static final Duration DEFAULT_POLL_RATE = new Duration(1, TimeUnit.SECONDS); 47 | private static final String DEFAULT_INIT_SCRIPT = "init.js"; 48 | 49 | private static final EnvironmentSettings DEFAULT = builder().build(); 50 | 51 | static EnvironmentSettings defaults() { 52 | return DEFAULT; 53 | } 54 | 55 | static EnvironmentSettings.Builder builder() { 56 | return new Builder(); 57 | } 58 | 59 | private final ScriptLoadingExecutor loadExecutor; 60 | private final Executor runExecutor; 61 | private final Set bindings; 62 | private final Set packageImports; 63 | private final Set typeImports; 64 | private final Duration pollRate; 65 | private final String initScript; 66 | 67 | private EnvironmentSettingsImpl(Builder builder) { 68 | this.pollRate = builder.pollRate; 69 | this.loadExecutor = builder.loadExecutor; 70 | this.runExecutor = builder.runExecutor; 71 | this.bindings = Collections.unmodifiableSet(new HashSet<>(builder.bindings)); 72 | this.packageImports = Collections.unmodifiableSet(new LinkedHashSet<>(builder.packageImports)); 73 | this.typeImports = Collections.unmodifiableSet(new LinkedHashSet<>(builder.typeImports)); 74 | this.initScript = builder.initScript; 75 | } 76 | 77 | public ScriptLoadingExecutor getLoadExecutor() { 78 | if (this.loadExecutor == null) { 79 | return DEFAULT_LOAD_EXECUTOR.get(); 80 | } 81 | return this.loadExecutor; 82 | } 83 | 84 | public Executor getRunExecutor() { 85 | if (this.runExecutor == null) { 86 | return DEFAULT_RUN_EXECUTOR; 87 | } 88 | return this.runExecutor; 89 | } 90 | 91 | public Set getBindings() { 92 | return this.bindings; 93 | } 94 | 95 | public Set getPackageImports() { 96 | return this.packageImports; 97 | } 98 | 99 | public Set getTypeImports() { 100 | return this.typeImports; 101 | } 102 | 103 | public Duration getPollRate() { 104 | if (this.pollRate == null) { 105 | return DEFAULT_POLL_RATE; 106 | } 107 | return this.pollRate; 108 | } 109 | 110 | public String getInitScript() { 111 | if (this.initScript == null) { 112 | return DEFAULT_INIT_SCRIPT; 113 | } 114 | return this.initScript; 115 | } 116 | 117 | private static final class Builder implements EnvironmentSettings.Builder { 118 | private ScriptLoadingExecutor loadExecutor = null; 119 | private Executor runExecutor = null; 120 | private final Set bindings = new HashSet<>(); 121 | private final Set packageImports = new LinkedHashSet<>(); 122 | private final Set typeImports = new LinkedHashSet<>(); 123 | private Duration pollRate = null; 124 | private String initScript = null; 125 | 126 | @Override 127 | public Builder mergeSettingsFrom(EnvironmentSettings other) { 128 | Objects.requireNonNull(other, "other"); 129 | EnvironmentSettingsImpl that = (EnvironmentSettingsImpl) other; 130 | 131 | if (that.loadExecutor != null) { 132 | this.loadExecutor = that.loadExecutor; 133 | } 134 | if (that.runExecutor != null) { 135 | this.runExecutor = that.runExecutor; 136 | } 137 | this.bindings.addAll(that.bindings); 138 | this.packageImports.addAll(that.packageImports); 139 | this.typeImports.addAll(that.typeImports); 140 | if (that.pollRate != null) { 141 | this.pollRate = that.pollRate; 142 | } 143 | return this; 144 | } 145 | 146 | @Override 147 | public Builder loadExecutor(ScriptLoadingExecutor executor) { 148 | Objects.requireNonNull(executor, "executor"); 149 | this.loadExecutor = executor; 150 | return this; 151 | } 152 | 153 | @Override 154 | public Builder runExecutor(Executor executor) { 155 | this.runExecutor = Objects.requireNonNull(executor, "executor"); 156 | return this; 157 | } 158 | 159 | @Override 160 | public Builder withBindings(BindingsSupplier supplier) { 161 | this.bindings.add(Objects.requireNonNull(supplier, "supplier")); 162 | return this; 163 | } 164 | 165 | @Override 166 | public Builder withDefaultPackageImport(String packageName) { 167 | this.packageImports.add(packageName); 168 | return this; 169 | } 170 | 171 | @Override 172 | public EnvironmentSettings.Builder withDefaultPackageImports(Collection packageNames) { 173 | this.packageImports.addAll(packageNames); 174 | return this; 175 | } 176 | 177 | @Override 178 | public Builder withDefaultTypeImport(String type) { 179 | this.typeImports.add(type); 180 | return this; 181 | } 182 | 183 | @Override 184 | public EnvironmentSettings.Builder withDefaultTypeImports(Collection types) { 185 | this.typeImports.addAll(types); 186 | return this; 187 | } 188 | 189 | @Override 190 | public Builder pollRate(long time, TimeUnit unit) { 191 | this.pollRate = new Duration(time, Objects.requireNonNull(unit, "unit")); 192 | return this; 193 | } 194 | 195 | @Override 196 | public EnvironmentSettings.Builder initScript(String path) { 197 | this.initScript = Objects.requireNonNull(path, "path"); 198 | return this; 199 | } 200 | 201 | @Override 202 | public EnvironmentSettings build() { 203 | return new EnvironmentSettingsImpl(this); 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/internal/ScriptImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.internal; 27 | 28 | import me.lucko.scriptcontroller.bindings.BindingsBuilder; 29 | import me.lucko.scriptcontroller.bindings.BindingsSupplier; 30 | import me.lucko.scriptcontroller.closable.CompositeAutoClosable; 31 | import me.lucko.scriptcontroller.environment.loader.DelegateScriptLoader; 32 | import me.lucko.scriptcontroller.environment.loader.ScriptLoader; 33 | import me.lucko.scriptcontroller.environment.script.Script; 34 | import me.lucko.scriptcontroller.logging.ScriptLogger; 35 | 36 | import java.nio.file.Path; 37 | import java.nio.file.Paths; 38 | import java.util.Collections; 39 | import java.util.HashSet; 40 | import java.util.Set; 41 | import java.util.function.Consumer; 42 | import java.util.function.Function; 43 | 44 | import javax.script.ScriptContext; 45 | import javax.script.ScriptEngine; 46 | import javax.script.SimpleScriptContext; 47 | 48 | class ScriptImpl implements Script, Runnable { 49 | 50 | /** 51 | * Header which is evaluated before the content of the actual script is 52 | * loaded. It... 53 | * 54 | * Loads the nashorn mozilla_compat script, which provides importClass and 55 | * importPackage functions (among other things) 56 | * 57 | * Redefines the load function to prepend the loader directory and register 58 | * loaded scripts as dependencies 59 | */ 60 | private static final String GLOBAL_SCRIPT_HEADER = 61 | /* 62 | load("nashorn:mozilla_compat.js"); 63 | var __load = load; 64 | var load = function(file) { 65 | __load(rsd + file); 66 | depend(file); 67 | }; 68 | */ 69 | "load(\"nashorn:mozilla_compat.js\");\r\n" + 70 | "var __load = load;\r\n" + 71 | "var load = function(file) {\r\n" + 72 | " __load(rsd + file);\r\n" + 73 | " depend(file);\r\n" + 74 | "};"; 75 | 76 | /** 77 | * Function which returns the string evaluate in order to load a js file at 78 | * the given path 79 | */ 80 | private static final Function LOAD_FUNCTION = path -> "__load(\"" + path.toString().replace("\\", "/") + "\");"; 81 | 82 | // functions to import packages / classes 83 | private static final Function IMPORT_PACKAGE = pkg -> "importPackage(\"" + pkg + "\");"; 84 | private static final Function IMPORT_TYPE = type -> { 85 | String name = type.substring(type.lastIndexOf('.') + 1); 86 | return "var " + name + " = Java.type(\"" + type + "\")"; 87 | }; 88 | 89 | private final ScriptLoaderImpl loader; 90 | 91 | /** The name of this script */ 92 | private final String name; 93 | 94 | /** The associated script file */ 95 | private final Path path; 96 | 97 | /** The loader instance handling this script */ 98 | private final ScriptLoader delegateLoader; 99 | 100 | /** The scripts logger */ 101 | private final ScriptLogger logger; 102 | 103 | /** The terminable registry used by this script */ 104 | private final CompositeAutoClosable compositeAutoClosable = CompositeAutoClosable.create(); 105 | 106 | /** The scripts dependencies */ 107 | private final Set depends = new HashSet<>(); 108 | 109 | public ScriptImpl(ScriptLoaderImpl loader, Path path) { 110 | this.loader = loader; 111 | 112 | String name = path.getFileName().toString(); 113 | if (name.endsWith(".js")) { 114 | this.name = name.substring(0, name.length() - 3); 115 | } else { 116 | this.name = name; 117 | } 118 | this.path = path; 119 | 120 | this.delegateLoader = new DelegateScriptLoader(loader); 121 | this.logger = ScriptLogger.create(loader.getEnvironment().getController().getLogger(), this); 122 | this.depends.add(this.path); 123 | } 124 | 125 | @Override 126 | public String getName() { 127 | return this.name; 128 | } 129 | 130 | @Override 131 | public Path getPath() { 132 | return this.path; 133 | } 134 | 135 | @Override 136 | public ScriptLogger getLogger() { 137 | return this.logger; 138 | } 139 | 140 | @Override 141 | public CompositeAutoClosable getClosables() { 142 | return this.compositeAutoClosable; 143 | } 144 | 145 | @Override 146 | public void run() { 147 | try { 148 | Path loaderDirectory = this.loader.getEnvironment().getDirectory().normalize(); 149 | ScriptEngine scriptEngine = this.loader.getEnvironment().getScriptEngine(); 150 | 151 | // create bindings 152 | BindingsBuilder bindings = BindingsBuilder.wrap(scriptEngine.createBindings()); 153 | 154 | // provide an export for various script attributes 155 | bindings.put("loader", this.delegateLoader) 156 | .put("closableRegistry", this.compositeAutoClosable) 157 | .put("exports", this.loader.getEnvironment().getExportRegistry()) 158 | .put("logger", this.logger) 159 | .put("cwd", this.path.normalize().toString().replace("\\", "/")) // the path of the script file (current working directory) 160 | .put("rsd", loaderDirectory.toString().replace("\\", "/") + "/") // the root scripts directory 161 | .put("depend", (Consumer) this::depend); // function to depend on another script 162 | 163 | // accumulate global bindings 164 | Set systemBindings = this.loader.getEnvironment().getSettings().getBindings(); 165 | for (BindingsSupplier supplier : systemBindings) { 166 | supplier.supplyBindings(this, bindings); 167 | } 168 | 169 | // create a new script context, and attach our bindings 170 | ScriptContext context = new SimpleScriptContext(); 171 | context.setBindings(bindings.build(), ScriptContext.ENGINE_SCOPE); 172 | 173 | // evaluate the header 174 | scriptEngine.eval(GLOBAL_SCRIPT_HEADER, context); 175 | 176 | // apply default package/type imports 177 | for (String packageName : this.loader.getEnvironment().getSettings().getPackageImports()) { 178 | scriptEngine.eval(IMPORT_PACKAGE.apply(packageName), context); 179 | } 180 | for (String className : this.loader.getEnvironment().getSettings().getTypeImports()) { 181 | scriptEngine.eval(IMPORT_TYPE.apply(className), context); 182 | } 183 | 184 | // resolve the load path, relative to the loader directory. 185 | Path loadPath = loaderDirectory.resolve(this.path); 186 | scriptEngine.eval(LOAD_FUNCTION.apply(loadPath), context); 187 | } catch (Throwable t) { 188 | this.logger.error("Exception occurred whilst loading script (" + this.path + ")"); 189 | t.printStackTrace(); 190 | } 191 | } 192 | 193 | @Override 194 | public Set getDependencies() { 195 | return Collections.unmodifiableSet(this.depends); 196 | } 197 | 198 | @Override 199 | public void depend(String path) { 200 | depend(Paths.get(path)); 201 | } 202 | 203 | @Override 204 | public void depend(Path path) { 205 | if (this.path.equals(path)) { 206 | return; 207 | } 208 | 209 | this.depends.add(path); 210 | } 211 | 212 | @Override 213 | public void close() throws Exception { 214 | this.delegateLoader.close(); 215 | this.compositeAutoClosable.close(); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/main/java/me/lucko/scriptcontroller/internal/ScriptLoaderImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of ScriptController, licensed under the MIT License. 3 | * 4 | * Copyright (c) lucko (Luck) 5 | * Copyright (c) contributors 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package me.lucko.scriptcontroller.internal; 27 | 28 | import me.lucko.scriptcontroller.closable.CompositeAutoClosable; 29 | import me.lucko.scriptcontroller.environment.loader.EnvironmentScriptLoader; 30 | import me.lucko.scriptcontroller.environment.registry.ScriptRegistry; 31 | import me.lucko.scriptcontroller.environment.script.Script; 32 | import me.lucko.scriptcontroller.logging.SystemLogger; 33 | 34 | import java.io.IOException; 35 | import java.nio.file.Files; 36 | import java.nio.file.Path; 37 | import java.nio.file.Paths; 38 | import java.nio.file.StandardWatchEventKinds; 39 | import java.nio.file.WatchEvent; 40 | import java.nio.file.WatchKey; 41 | import java.nio.file.WatchService; 42 | import java.util.ArrayList; 43 | import java.util.Collection; 44 | import java.util.HashSet; 45 | import java.util.Iterator; 46 | import java.util.LinkedHashSet; 47 | import java.util.List; 48 | import java.util.Map; 49 | import java.util.Set; 50 | import java.util.concurrent.CopyOnWriteArrayList; 51 | import java.util.concurrent.Executor; 52 | import java.util.concurrent.locks.ReentrantLock; 53 | import java.util.stream.Collectors; 54 | import java.util.stream.Stream; 55 | 56 | class ScriptLoaderImpl implements EnvironmentScriptLoader { 57 | private static final WatchEvent.Kind[] EVENTS = new WatchEvent.Kind[]{ 58 | StandardWatchEventKinds.ENTRY_CREATE, 59 | StandardWatchEventKinds.ENTRY_DELETE, 60 | StandardWatchEventKinds.ENTRY_MODIFY 61 | }; 62 | 63 | /** The environment this loader is operating within */ 64 | private final ScriptEnvironmentImpl environment; 65 | 66 | /** The watch service monitoring the directory */ 67 | private final WatchService watchService; 68 | 69 | /** The watch key for the script directory */ 70 | private final List watchKeys = new CopyOnWriteArrayList<>(); 71 | 72 | /** 73 | * The script files currently being monitored by this instance. 74 | * These paths are relative to the script directory 75 | */ 76 | private List files = new ArrayList<>(); 77 | 78 | /** The instance mutex */ 79 | private final ReentrantLock lock = new ReentrantLock(); 80 | 81 | public ScriptLoaderImpl(ScriptEnvironmentImpl environment) throws IOException { 82 | this.environment = environment; 83 | 84 | // init file watcher 85 | this.watchService = environment.getDirectory().getFileSystem().newWatchService(); 86 | try (Stream dirs = Files.walk(environment.getDirectory())) { 87 | List directories = dirs.filter(Files::isDirectory).collect(Collectors.toList()); 88 | for (Path dir : directories) { 89 | this.watchKeys.add(dir.register(this.watchService, EVENTS)); 90 | } 91 | } 92 | } 93 | 94 | @Override 95 | public ScriptEnvironmentImpl getEnvironment() { 96 | return this.environment; 97 | } 98 | 99 | @Override 100 | public void watchAll(Collection paths) { 101 | this.lock.lock(); 102 | try { 103 | for (String s : paths) { 104 | this.files.add(Paths.get(s)); 105 | } 106 | } finally { 107 | this.lock.unlock(); 108 | } 109 | } 110 | 111 | @Override 112 | public void unwatchAll(Collection paths) { 113 | this.lock.lock(); 114 | try { 115 | for (String s : paths) { 116 | this.files.remove(Paths.get(s)); 117 | } 118 | } finally { 119 | this.lock.unlock(); 120 | } 121 | } 122 | 123 | @Override 124 | public void preload() { 125 | // keep running until we stop loading files 126 | int filesLength; 127 | do { 128 | filesLength = this.files.size(); 129 | reload(true); 130 | } while (filesLength != this.files.size()); 131 | } 132 | 133 | @Override 134 | public void run() { 135 | this.lock.lock(); 136 | try { 137 | reload(false); 138 | } catch (Throwable t) { 139 | t.printStackTrace(); 140 | } finally { 141 | this.lock.unlock(); 142 | } 143 | } 144 | 145 | private void reload(boolean runImmediately) { 146 | ScriptRegistry registry = this.environment.getScriptRegistry(); 147 | SystemLogger logger = this.environment.getController().getLogger(); 148 | 149 | // gather work 150 | Set toReload = new LinkedHashSet<>(); 151 | Set toLoad = new LinkedHashSet<>(); 152 | Set