From 1c7ad90c82b2f989ce63dfad9fdbcec280819860 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 16 Sep 2024 13:48:23 +0200 Subject: [PATCH] Improve addon loading exception logs --- .../bluemap/common/addons/AddonException.java | 30 --------- .../bluemap/common/addons/Addons.java | 61 +++++++++++++++---- 2 files changed, 50 insertions(+), 41 deletions(-) delete mode 100644 common/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java diff --git a/common/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java b/common/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java deleted file mode 100644 index cbb84f4b..00000000 --- a/common/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * 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 de.bluecolored.bluemap.common.addons; - -import lombok.experimental.StandardException; - -@StandardException -public class AddonException extends Exception {} diff --git a/common/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java b/common/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java index 298e087c..54e44490 100644 --- a/common/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java +++ b/common/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java @@ -26,6 +26,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import de.bluecolored.bluemap.common.config.ConfigurationException; import de.bluecolored.bluemap.core.BlueMap; import de.bluecolored.bluemap.core.logger.Logger; import org.jetbrains.annotations.Nullable; @@ -47,6 +48,10 @@ public final class Addons { + private static final String PLUGIN_YML = "plugin.yml"; + private static final String MODS_TOML = "META-INF/mods.toml"; + private static final String FABRIC_MOD_JSON = "fabric.mod.json"; + private static final Gson GSON = new GsonBuilder().create(); private static final Map LOADED_ADDONS = new ConcurrentHashMap<>(); @@ -73,13 +78,15 @@ public static void tryLoadAddons(Path root, boolean expectOnlyAddons) { public static void tryLoadAddon(Path addonJarFile) { try { AddonInfo addonInfo = loadAddonInfo(addonJarFile); - if (addonInfo == null) throw new AddonException("No %s found in '%s'".formatted(ADDON_INFO_FILE, addonJarFile)); + if (addonInfo == null) throw createRichExceptionForFile(addonJarFile); if (LOADED_ADDONS.containsKey(addonInfo.getId())) return; loadAddon(addonJarFile, addonInfo); - } catch (IOException | AddonException e) { - Logger.global.logError("Failed to load addon '%s'".formatted(addonJarFile), e); + } catch (ConfigurationException e) { + ConfigurationException e2 = new ConfigurationException("BlueMap failed to load the addon '%s'!".formatted(addonJarFile), e); + Logger.global.logWarning(e2.getFormattedExplanation()); + Logger.global.logError(e2); } } @@ -94,16 +101,19 @@ public static void tryLoadJar(Path addonJarFile) { if (LOADED_ADDONS.containsKey(addonInfo.getId())) return; loadAddon(addonJarFile, addonInfo); - } catch (IOException | AddonException e) { - Logger.global.logError("Failed to load addon '%s'".formatted(addonJarFile), e); + } catch (ConfigurationException e) { + ConfigurationException e2 = new ConfigurationException("BlueMap failed to load the addon '%s'!".formatted(addonJarFile), e); + Logger.global.logWarning(e2.getFormattedExplanation()); + Logger.global.logError(e2); } } - public synchronized static void loadAddon(Path jarFile, AddonInfo addonInfo) throws AddonException { + public synchronized static void loadAddon(Path jarFile, AddonInfo addonInfo) throws ConfigurationException { Logger.global.logInfo("Loading BlueMap Addon: %s (%s)".formatted(addonInfo.getId(), jarFile)); if (LOADED_ADDONS.containsKey(addonInfo.getId())) - throw new AddonException("Addon with id '%s' is already loaded".formatted(addonInfo.getId())); + throw new ConfigurationException("There is already an addon with same id ('%s') loaded!" + .formatted(addonInfo.getId())); try { ClassLoader addonClassLoader = BlueMap.class.getClassLoader(); @@ -134,11 +144,11 @@ public synchronized static void loadAddon(Path jarFile, AddonInfo addonInfo) thr runnable.run(); } catch (Exception e) { - throw new AddonException("Failed to load addon '%s'".formatted(jarFile), e); + throw new ConfigurationException("There was an exception trying to initialize the addon!", e); } } - public static @Nullable AddonInfo loadAddonInfo(Path addonJarFile) throws IOException, AddonException { + public static @Nullable AddonInfo loadAddonInfo(Path addonJarFile) throws ConfigurationException { try (FileSystem fileSystem = FileSystems.newFileSystem(addonJarFile, (ClassLoader) null)) { for (Path root : fileSystem.getRootDirectories()) { Path addonInfoFile = root.resolve(ADDON_INFO_FILE); @@ -148,17 +158,46 @@ public synchronized static void loadAddon(Path jarFile, AddonInfo addonInfo) thr AddonInfo addonInfo = GSON.fromJson(reader, AddonInfo.class); if (addonInfo.getId() == null) - throw new AddonException("'id' is missing"); + throw new ConfigurationException("'id' is missing"); if (addonInfo.getEntrypoint() == null) - throw new AddonException("'entrypoint' is missing"); + throw new ConfigurationException("'entrypoint' is missing"); return addonInfo; } } + } catch (IOException e) { + throw new ConfigurationException("There was an exception trying to access the file.", e); } return null; } + private static ConfigurationException createRichExceptionForFile(Path jarFile) { + boolean isPlugin = false; + boolean isMod = false; + + try (FileSystem fileSystem = FileSystems.newFileSystem(jarFile, (ClassLoader) null)) { + for (Path root : fileSystem.getRootDirectories()) { + if (Files.exists(root.resolve(PLUGIN_YML))) isPlugin = true; + if (Files.exists(root.resolve(MODS_TOML))) isMod = true; + if (Files.exists(root.resolve(FABRIC_MOD_JSON))) isMod = true; + } + } catch (IOException e) { + Logger.global.logError("Failed to log file-info for '%s'".formatted(jarFile), e); + } + + if (!(isPlugin || isMod)) return new ConfigurationException(""" + File '%s' does not seem to be a valid native bluemap addon. + """.strip().formatted(jarFile)); + + String type = isPlugin ? "plugin" : "mod"; + String targetFolder = isPlugin ? "./plugins" : "./mods"; + + return new ConfigurationException(""" + File '%s' seems to be a %s and not a native bluemap addon. + Try adding it to the '%s' folder of your server instead! + """.strip().formatted(jarFile, type, targetFolder)); + } + }