From 510b9bb490c574297d927a3b4c75c84fe502cde4 Mon Sep 17 00:00:00 2001 From: Luck Date: Wed, 21 Mar 2018 17:59:18 +0000 Subject: [PATCH] Update helper-js for latest scriptcontroller changes --- helper-js/pom.xml | 18 +- .../me/lucko/helper/js/HelperJsPlugin.java | 218 +++++++++++++++--- .../js/bindings/GeneralScriptBindings.java | 93 -------- .../js/bindings/HelperScriptBindings.java | 81 ------- .../me/lucko/helper/internal/LoaderUtils.java | 25 ++ 5 files changed, 229 insertions(+), 206 deletions(-) delete mode 100644 helper-js/src/main/java/me/lucko/helper/js/bindings/GeneralScriptBindings.java delete mode 100644 helper-js/src/main/java/me/lucko/helper/js/bindings/HelperScriptBindings.java diff --git a/helper-js/pom.xml b/helper-js/pom.xml index 5bc98682..a58dd171 100644 --- a/helper-js/pom.xml +++ b/helper-js/pom.xml @@ -18,6 +18,10 @@ JavaScript plugins using Nashorn. https://github.com/lucko/helper + + me.lucko.helper.js.external. + + clean package ${project.name} @@ -68,6 +72,12 @@ false false + + + io.github.lukehutch.fastclasspathscanner + ${shade.pattern}fcs + + @@ -116,7 +126,13 @@ me.lucko scriptcontroller - 1.0 + 1.0-SNAPSHOT + compile + + + io.github.lukehutch + fast-classpath-scanner + 2.9.5 compile diff --git a/helper-js/src/main/java/me/lucko/helper/js/HelperJsPlugin.java b/helper-js/src/main/java/me/lucko/helper/js/HelperJsPlugin.java index 06e12a9c..83e4b929 100644 --- a/helper-js/src/main/java/me/lucko/helper/js/HelperJsPlugin.java +++ b/helper-js/src/main/java/me/lucko/helper/js/HelperJsPlugin.java @@ -25,33 +25,113 @@ package me.lucko.helper.js; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; + import me.lucko.helper.Schedulers; -import me.lucko.helper.js.bindings.GeneralScriptBindings; -import me.lucko.helper.js.bindings.HelperScriptBindings; +import me.lucko.helper.internal.LoaderUtils; +import me.lucko.helper.menu.scheme.MenuScheme; +import me.lucko.helper.menu.scheme.SchemeMapping; +import me.lucko.helper.metadata.MetadataKey; import me.lucko.helper.plugin.ExtendedJavaPlugin; import me.lucko.helper.scheduler.Ticks; +import me.lucko.helper.terminable.composite.CompositeTerminable; +import me.lucko.helper.text.Text; import me.lucko.scriptcontroller.ScriptController; +import me.lucko.scriptcontroller.bindings.BindingsBuilder; +import me.lucko.scriptcontroller.bindings.BindingsSupplier; +import me.lucko.scriptcontroller.environment.ScriptEnvironment; import me.lucko.scriptcontroller.environment.loader.ScriptLoadingExecutor; +import me.lucko.scriptcontroller.environment.script.Script; +import me.lucko.scriptcontroller.environment.settings.EnvironmentSettings; import me.lucko.scriptcontroller.logging.SystemLogger; +import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; +import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; import javax.annotation.Nonnull; -public class HelperJsPlugin extends ExtendedJavaPlugin { +/** + * Uses {@link ScriptController} and helper to provide a javascript plugin environment for Bukkit. + */ +public class HelperJsPlugin extends ExtendedJavaPlugin implements ScriptLoadingExecutor { + + /** + * The packages to import by default when each script is executed. + * These strings are pattern specs for the FastClasspathScanner. + */ + private static final String[] DEFAULT_IMPORTS = new String[]{ + // import all of the packages in helper + "me.lucko.helper", + // import all of the packages in bukkit + "org.bukkit", + // exclude craftbukkit classes + "-org.bukkit.craftbukkit", + // exclude helper-js dependencies (the classpath scanner itself) + "-me.lucko.helper.js.external"}; + private ScriptController controller; + private ScriptEnvironment environment; @Override protected void enable() { // load config + getLogger().info("Loading configuration..."); YamlConfiguration config = loadConfig("config.yml"); + // search for packages which match the default import patterns + getLogger().info("Scanning the classpath to resolve default package imports..."); + FastClasspathScanner classpathScanner = new FastClasspathScanner(DEFAULT_IMPORTS).strictWhitelist(); + + // add the classloaders for helper implementation plugins + LoaderUtils.getHelperImplementationPlugins().forEach(pl -> classpathScanner.addClassLoader(pl.getClass().getClassLoader())); + + // form a list of matches packages + Set defaultPackages = classpathScanner.scan() + .getNamesOfAllClasses() + .stream() + .map(className -> { + // convert to a package name + return className.substring(0, className.lastIndexOf('.')); + }) + .collect(Collectors.toSet()); + + // setup the script controller + getLogger().info("Initialising script controller..."); + this.controller = ScriptController.builder() + .logger(SystemLogger.usingJavaLogger(getLogger())) + .defaultEnvironmentSettings(EnvironmentSettings.builder() + .loadExecutor(this) + .runExecutor(Schedulers.sync()) + .pollRate(Ticks.to(config.getLong("poll-interval", 20L), TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS) + .withBindings(new GeneralScriptBindings()) + .withBindings(new HelperScriptBindings(this)) + .withDefaultPackageImports(defaultPackages) + .build() + ) + .build(); + // get script directory Path scriptDirectory = Paths.get(config.getString("script-directory")); if (!Files.isDirectory(scriptDirectory)) { @@ -62,39 +142,115 @@ protected void enable() { } } - getLogger().info("Using script directory: " + scriptDirectory.toString() + "(" + scriptDirectory.toAbsolutePath().toString() + ")"); + // init a new environment for our scripts + getLogger().info("Creating new script environment at " + scriptDirectory.toString() + " (" + scriptDirectory.toAbsolutePath().toString() + ")"); + this.environment = this.controller.setupNewEnvironment(scriptDirectory); - this.controller = ScriptController.builder() - .withDirectory(scriptDirectory) - .loadExecutor(new ScriptLoadingExecutor() { - @Override - public AutoCloseable scheduleAtFixedRate(Runnable runnable, long l, TimeUnit timeUnit) { - return Schedulers.builder() - .async() - .after(0L) - .every(l, timeUnit) - .run(runnable); - } - - @Override - public void execute(@Nonnull Runnable command) { - Schedulers.async().run(command); - } - }) - .runExecutor(Schedulers.sync()) - .pollRate(Ticks.to(config.getLong("poll-interval", 20L), TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS) - .logger(new SystemLogger() { - @Override public void info(String s) { getLogger().info(s); } - @Override public void warning(String s) { getLogger().warning(s); } - @Override public void severe(String s) { getLogger().severe(s); } - }) - .withBindings(new GeneralScriptBindings()) - .withBindings(new HelperScriptBindings(this)) - .build(); + getLogger().info("Done!"); } @Override protected void disable() { this.controller.shutdown(); } + + @Override + public AutoCloseable scheduleAtFixedRate(Runnable runnable, long l, TimeUnit timeUnit) { + return Schedulers.builder() + .async() + .after(0L) + .every(l, timeUnit) + .run(runnable); + } + + @Override + public void execute(@Nonnull Runnable command) { + Schedulers.async().run(command); + } + + /** + * Some misc functions to help with using Java collections in JS + */ + public static class GeneralScriptBindings implements BindingsSupplier { + private static final Supplier ARRAY_LIST = ArrayList::new; + private static final Supplier LINKED_LIST = LinkedList::new; + private static final Supplier HASH_SET = HashSet::new; + private static final Supplier HASH_MAP = HashMap::new; + private static final Supplier COPY_ON_WRITE_ARRAY_LIST = CopyOnWriteArrayList::new; + private static final Supplier CONCURRENT_HASH_SET = ConcurrentHashMap::newKeySet; + private static final Supplier CONCURRENT_HASH_MAP = ConcurrentHashMap::new; + private static final Function LIST_OF = objects -> new ArrayList<>(Arrays.asList(objects)); + private static final Function SET_OF = objects -> new HashSet<>(Arrays.asList(objects)); + private static final Function IMMUTABLE_LIST_OF = ImmutableList::copyOf; + private static final Function IMMUTABLE_SET_OF = ImmutableSet::copyOf; + private static final Function PARSE_UUID = s -> { + try { + return UUID.fromString(s); + } catch (IllegalArgumentException e) { + return null; + } + }; + + @Override + public void supplyBindings(Script script, BindingsBuilder bindings) { + bindings.put("newArrayList", ARRAY_LIST); + bindings.put("newLinkedList", LINKED_LIST); + bindings.put("newHashSet", HASH_SET); + bindings.put("newHashMap", HASH_MAP); + bindings.put("newCopyOnWriteArrayList", COPY_ON_WRITE_ARRAY_LIST); + bindings.put("newConcurrentHashSet", CONCURRENT_HASH_SET); + bindings.put("newConcurrentHashMap", CONCURRENT_HASH_MAP); + bindings.put("listOf", LIST_OF); + bindings.put("setOf", SET_OF); + bindings.put("immutableListOf", IMMUTABLE_LIST_OF); + bindings.put("immutableSetOf", IMMUTABLE_SET_OF); + bindings.put("parseUuid", PARSE_UUID); + } + } + + /** + * Script bindings for helper utilities + */ + public static class HelperScriptBindings implements BindingsSupplier { + private final HelperJsPlugin plugin; + + public HelperScriptBindings(HelperJsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void supplyBindings(Script script, BindingsBuilder bindings) { + // provide a terminable registry + CompositeTerminable registry = CompositeTerminable.create(); + script.getClosables().bind(registry); + bindings.put("registry", registry); + + // provide core server classes + bindings.put("server", Bukkit.getServer()); + bindings.put("plugin", this.plugin); + bindings.put("services", Bukkit.getServicesManager()); + + // some util functions + bindings.put("colorize", (Function) HelperScriptBindings::colorize); + bindings.put("newMetadataKey", (Function) HelperScriptBindings::newMetadataKey); + bindings.put("newEmptyScheme", (Supplier) HelperScriptBindings::newScheme); + bindings.put("newScheme", (Function) HelperScriptBindings::newScheme); + } + + private static String colorize(Object object) { + return Text.colorize(object.toString()); + } + + private static MetadataKey newMetadataKey(Object id) { + return MetadataKey.create(id.toString(), new TypeToken(){}); + } + + private static MenuScheme newScheme() { + return new MenuScheme(); + } + + private static MenuScheme newScheme(SchemeMapping mapping) { + return new MenuScheme(mapping); + } + } } diff --git a/helper-js/src/main/java/me/lucko/helper/js/bindings/GeneralScriptBindings.java b/helper-js/src/main/java/me/lucko/helper/js/bindings/GeneralScriptBindings.java deleted file mode 100644 index f76a91cc..00000000 --- a/helper-js/src/main/java/me/lucko/helper/js/bindings/GeneralScriptBindings.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * This file is part of helper, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.lucko.helper.js.bindings; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; - -import me.lucko.scriptcontroller.bindings.BindingsBuilder; -import me.lucko.scriptcontroller.bindings.BindingsSupplier; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * Some misc functions to help with using Java collections in JS - */ -public class GeneralScriptBindings implements BindingsSupplier { - - private static final Supplier ARRAY_LIST = ArrayList::new; - private static final Supplier LINKED_LIST = LinkedList::new; - private static final Supplier HASH_SET = HashSet::new; - private static final Supplier HASH_MAP = HashMap::new; - private static final Supplier COPY_ON_WRITE_ARRAY_LIST = CopyOnWriteArrayList::new; - private static final Supplier CONCURRENT_HASH_SET = ConcurrentHashMap::newKeySet; - private static final Supplier CONCURRENT_HASH_MAP = ConcurrentHashMap::new; - - private static final Function LIST_OF = objects -> new ArrayList<>(Arrays.asList(objects)); - private static final Function SET_OF = objects -> new HashSet<>(Arrays.asList(objects)); - - private static final Function IMMUTABLE_LIST_OF = ImmutableList::copyOf; - private static final Function IMMUTABLE_SET_OF = ImmutableSet::copyOf; - - private static final Function PARSE_UUID = s -> { - try { - return UUID.fromString(s); - } catch (IllegalArgumentException e) { - return null; - } - }; - - public void accumulateTo(BindingsBuilder bindings) { - // standard java collections - bindings.put("newArrayList", ARRAY_LIST); - bindings.put("newLinkedList", LINKED_LIST); - bindings.put("newHashSet", HASH_SET); - bindings.put("newHashMap", HASH_MAP); - bindings.put("newCopyOnWriteArrayList", COPY_ON_WRITE_ARRAY_LIST); - bindings.put("newConcurrentHashSet", CONCURRENT_HASH_SET); - bindings.put("newConcurrentHashMap", CONCURRENT_HASH_MAP); - - bindings.put("listOf", LIST_OF); - bindings.put("setOf", SET_OF); - - // guava immutables - bindings.put("immutableListOf", IMMUTABLE_LIST_OF); - bindings.put("immutableSetOf", IMMUTABLE_SET_OF); - - // misc - bindings.put("parseUuid", PARSE_UUID); - } -} diff --git a/helper-js/src/main/java/me/lucko/helper/js/bindings/HelperScriptBindings.java b/helper-js/src/main/java/me/lucko/helper/js/bindings/HelperScriptBindings.java deleted file mode 100644 index 2db2f80e..00000000 --- a/helper-js/src/main/java/me/lucko/helper/js/bindings/HelperScriptBindings.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * This file is part of helper, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.lucko.helper.js.bindings; - -import com.google.common.reflect.TypeToken; - -import me.lucko.helper.js.HelperJsPlugin; -import me.lucko.helper.menu.scheme.MenuScheme; -import me.lucko.helper.menu.scheme.SchemeMapping; -import me.lucko.helper.metadata.MetadataKey; -import me.lucko.helper.text.Text; -import me.lucko.scriptcontroller.bindings.BindingsBuilder; -import me.lucko.scriptcontroller.bindings.BindingsSupplier; - -import org.bukkit.Bukkit; - -import java.util.function.Function; -import java.util.function.Supplier; - -public class HelperScriptBindings implements BindingsSupplier { - private final HelperJsPlugin plugin; - - public HelperScriptBindings(HelperJsPlugin plugin) { - this.plugin = plugin; - } - - @Override - public void accumulateTo(BindingsBuilder bindings) { - - // provide exports to access the exports registry & core server classes - bindings.put("server", Bukkit.getServer()); - bindings.put("plugin", this.plugin); - bindings.put("services", Bukkit.getServicesManager()); - - // some util functions - bindings.put("colorize", (Function) HelperScriptBindings::colorize); - bindings.put("newMetadataKey", (Function) HelperScriptBindings::newMetadataKey); - bindings.put("newEmptyScheme", (Supplier) HelperScriptBindings::newScheme); - bindings.put("newScheme", (Function) HelperScriptBindings::newScheme); - } - - private static String colorize(Object object) { - return Text.colorize(object.toString()); - } - - private static MetadataKey newMetadataKey(Object id) { - return MetadataKey.create(id.toString(), new TypeToken(){}); - } - - private static MenuScheme newScheme() { - return new MenuScheme(); - } - - private static MenuScheme newScheme(SchemeMapping mapping) { - return new MenuScheme(mapping); - } - -} diff --git a/helper/src/main/java/me/lucko/helper/internal/LoaderUtils.java b/helper/src/main/java/me/lucko/helper/internal/LoaderUtils.java index 79fb1e07..6d95d9b8 100644 --- a/helper/src/main/java/me/lucko/helper/internal/LoaderUtils.java +++ b/helper/src/main/java/me/lucko/helper/internal/LoaderUtils.java @@ -25,12 +25,14 @@ package me.lucko.helper.internal; +import com.google.common.collect.Streams; import com.google.common.reflect.TypeToken; import com.google.gson.JsonArray; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import me.lucko.helper.Helper; import me.lucko.helper.gson.GsonSerializable; import me.lucko.helper.gson.GsonSerializableConfigurateProxy; import me.lucko.helper.gson.configurate.JsonArraySerializer; @@ -40,11 +42,17 @@ import me.lucko.helper.plugin.HelperPlugin; import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import ninja.leaping.configurate.objectmapping.serialize.TypeSerializerCollection; import ninja.leaping.configurate.objectmapping.serialize.TypeSerializers; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import javax.annotation.Nonnull; /** @@ -68,6 +76,23 @@ public static synchronized HelperPlugin getPlugin() { return plugin; } + public static Set getHelperImplementationPlugins() { + return Streams.concat( + Stream.of(getPlugin()), + Arrays.stream(Helper.plugins().getPlugins()) + .filter(pl -> pl.getName().toLowerCase().startsWith("helper-")) + ).collect(Collectors.toSet()); + } + + public static Set getHelperPlugins() { + return Streams.concat( + Stream.of(getPlugin()), + Arrays.stream(Helper.plugins().getPlugins()) + .filter(pl -> pl instanceof HelperPlugin) + .map(pl -> (HelperPlugin) pl) + ).collect(Collectors.toSet()); + } + @Nonnull public static synchronized Thread getMainThread() { if (mainThread == null) {