Made build in extension registration more resistant:

- Attempt to reduce the amount of exceptions that might slip through
  and fail to start Plan

Affects issues:
- Close #1134
This commit is contained in:
Rsl1122 2019-08-12 09:31:57 +03:00
parent 3ab4d2b68a
commit e66b63281d
5 changed files with 75 additions and 33 deletions

View File

@ -68,8 +68,13 @@ public final class ExtensionExtractor {
} }
} }
private <T extends Annotation> Optional<T> getClassAnnotation(Class<T> ofClass) { private static <V extends DataExtension, T extends Annotation> Optional<T> getClassAnnotation(Class<V> from, Class<T> ofClass) {
return Optional.ofNullable(extension.getClass().getAnnotation(ofClass)); return Optional.ofNullable(from.getAnnotation(ofClass));
}
public static <T extends DataExtension> String getPluginName(Class<T> extensionClass) {
return getClassAnnotation(extensionClass, PluginInfo.class).map(PluginInfo::name)
.orElseThrow(() -> new IllegalArgumentException("Given class had no PluginInfo annotation"));
} }
private Method[] getMethods() { private Method[] getMethods() {
@ -282,8 +287,13 @@ public final class ExtensionExtractor {
} }
} }
private <T extends Annotation> Optional<T> getClassAnnotation(Class<T> ofClass) {
return getClassAnnotation(extension.getClass(), ofClass);
}
private void extractPluginInfo() { private void extractPluginInfo() {
pluginInfo = getClassAnnotation(PluginInfo.class).orElseThrow(() -> new IllegalArgumentException("Given class had no PluginInfo annotation")); pluginInfo = getClassAnnotation(PluginInfo.class)
.orElseThrow(() -> new IllegalArgumentException("Given class had no PluginInfo annotation"));
if (pluginInfo.name().length() > 50) { if (pluginInfo.name().length() > 50) {
warnings.add(extensionName + " PluginInfo 'name' was over 50 characters."); warnings.add(extensionName + " PluginInfo 'name' was over 50 characters.");

View File

@ -20,6 +20,8 @@ import com.djrapitops.plan.system.settings.config.ConfigNode;
import com.djrapitops.plan.system.settings.config.PlanConfig; import com.djrapitops.plan.system.settings.config.PlanConfig;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
/** /**
* Class responsible for generating and generating settings for PluginData * Class responsible for generating and generating settings for PluginData
@ -74,4 +76,16 @@ public class PluginsConfigSection {
ConfigNode section = getPluginsSection(); ConfigNode section = getPluginsSection();
return section.getBoolean(pluginName + ".Enabled"); return section.getBoolean(pluginName + ".Enabled");
} }
public Set<String> getDisabled() {
ConfigNode section = getPluginsSection();
Set<String> disabledPlugins = new HashSet<>();
for (ConfigNode plugin : section.getChildren()) {
if (!plugin.getBoolean("Enabled")) {
disabledPlugins.add(plugin.getKey(false));
}
}
return disabledPlugins;
}
} }

View File

@ -83,11 +83,11 @@ public class ExtensionServiceImplementation implements ExtensionService {
public void register() { public void register() {
try { try {
extensionRegister.registerBuiltInExtensions(); extensionRegister.registerBuiltInExtensions(config.getPluginsConfigSection().getDisabled());
if (Check.isBukkitAvailable()) extensionRegister.registerBukkitExtensions(); if (Check.isBukkitAvailable()) extensionRegister.registerBukkitExtensions();
if (Check.isBungeeAvailable()) extensionRegister.registerBungeeExtensions(); if (Check.isBungeeAvailable()) extensionRegister.registerBungeeExtensions();
} catch (IllegalStateException failedToRegisterOne) { } catch (IllegalStateException failedToRegisterOne) {
logger.warn("One or more extensions failed to register:"); logger.warn("One or more extensions failed to register, see suppressed exceptions.");
errorHandler.log(L.WARN, this.getClass(), failedToRegisterOne); errorHandler.log(L.WARN, this.getClass(), failedToRegisterOne);
} }
} }

View File

@ -349,6 +349,10 @@ public class ConfigNode {
return nodeOrder; return nodeOrder;
} }
public Collection<ConfigNode> getChildren() {
return childNodes.values();
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;

View File

@ -19,10 +19,12 @@ package com.djrapitops.plan.extension.implementation;
import com.djrapitops.extension.*; import com.djrapitops.extension.*;
import com.djrapitops.plan.extension.DataExtension; import com.djrapitops.plan.extension.DataExtension;
import com.djrapitops.plan.extension.ExtensionService; import com.djrapitops.plan.extension.ExtensionService;
import com.djrapitops.plan.extension.extractor.ExtensionExtractor;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
@ -34,47 +36,49 @@ import java.util.function.Supplier;
public class ExtensionRegister { public class ExtensionRegister {
private IllegalStateException registerException; private IllegalStateException registerException;
private Set<String> disabledExtensions;
@Inject @Inject
public ExtensionRegister() { public ExtensionRegister() {
/* Required for dagger injection */ /* Required for dagger injection */
} }
public void registerBuiltInExtensions() { public void registerBuiltInExtensions(Set<String> disabledExtensions) {
this.disabledExtensions = disabledExtensions;
// No need to catch exceptions here, // No need to catch exceptions here,
// registerBuiltInExtensions method will not be called unless Plan has enabled properly // registerBuiltInExtensions method will not be called unless Plan has enabled properly
ExtensionService extensionService = ExtensionService.getInstance(); ExtensionService extensionService = ExtensionService.getInstance();
register(new AACExtensionFactory()::createExtension); register(new AACExtensionFactory()::createExtension, AACExtensionFactory.class);
register(new AdvancedAchievementsExtensionFactory()::createExtension); register(new AdvancedAchievementsExtensionFactory()::createExtension, AdvancedAchievementsExtensionFactory.class);
register(new AdvancedBanExtensionFactory()::createExtension); register(new AdvancedBanExtensionFactory()::createExtension, AdvancedBanExtensionFactory.class);
register(new ASkyBlockExtensionFactory()::createExtension); register(new ASkyBlockExtensionFactory()::createExtension, ASkyBlockExtensionFactory.class);
register(new BanManagerExtensionFactory()::createExtension); register(new BanManagerExtensionFactory()::createExtension, BanManagerExtensionFactory.class);
register(new CoreProtectExtensionFactory()::createExtension); register(new CoreProtectExtensionFactory()::createExtension, CoreProtectExtensionFactory.class);
register(new DiscordSRVExtensionFactory()::createExtension); register(new DiscordSRVExtensionFactory()::createExtension, DiscordSRVExtensionFactory.class);
registerEssentialsExtension(extensionService); registerEssentialsExtension(extensionService);
register(new GriefPreventionExtensionFactory()::createExtension); register(new GriefPreventionExtensionFactory()::createExtension, GriefPreventionExtensionFactory.class);
register(new GriefPreventionSpongeExtensionFactory()::createExtension); register(new GriefPreventionSpongeExtensionFactory()::createExtension, GriefPreventionSpongeExtensionFactory.class);
register(new GriefPreventionPlusExtensionFactory()::createExtension); register(new GriefPreventionPlusExtensionFactory()::createExtension, GriefPreventionPlusExtensionFactory.class);
register(new McMMOExtensionFactory()::createExtension); register(new McMMOExtensionFactory()::createExtension, McMMOExtensionFactory.class);
registerMinigameLibExtensions(extensionService); registerMinigameLibExtensions(extensionService);
register(new NucleusExtensionFactory()::createExtension); register(new NucleusExtensionFactory()::createExtension, NucleusExtensionFactory.class);
register(new NuVotifierExtensionFactory()::createExtension); register(new NuVotifierExtensionFactory()::createExtension, NuVotifierExtensionFactory.class);
register(new ProtocolSupportExtensionFactory()::createExtension); register(new ProtocolSupportExtensionFactory()::createExtension, ProtocolSupportExtensionFactory.class);
register(new RedProtectExtensionFactory()::createExtension); register(new RedProtectExtensionFactory()::createExtension, RedProtectExtensionFactory.class);
register(new SpongeEconomyExtensionFactory()::createExtension); register(new SpongeEconomyExtensionFactory()::createExtension, SpongeEconomyExtensionFactory.class);
register(new SuperbVoteExtensionFactory()::createExtension); register(new SuperbVoteExtensionFactory()::createExtension, SuperbVoteExtensionFactory.class);
register(new VaultExtensionFactory()::createExtension); register(new VaultExtensionFactory()::createExtension, VaultExtensionFactory.class);
if (registerException != null) throw registerException; if (registerException != null) throw registerException;
} }
public void registerBukkitExtensions() { public void registerBukkitExtensions() {
register(new ViaVersionBukkitExtensionFactory()::createExtension); register(new ViaVersionBukkitExtensionFactory()::createExtension, ViaVersionBukkitExtensionFactory.class);
} }
public void registerBungeeExtensions() { public void registerBungeeExtensions() {
register(new ViaVersionBungeeExtensionFactory()::createExtension); register(new ViaVersionBungeeExtensionFactory()::createExtension, ViaVersionBungeeExtensionFactory.class);
} }
private void registerEssentialsExtension(ExtensionService extensionService) { private void registerEssentialsExtension(ExtensionService extensionService) {
@ -90,16 +94,26 @@ public class ExtensionRegister {
} }
} }
private void register(Supplier<Optional<DataExtension>> extension) { private void register(Supplier<Optional<DataExtension>> extension, Class factory) {
ExtensionService extensionService = ExtensionService.getInstance(); ExtensionService extensionService = ExtensionService.getInstance();
try { try {
extension.get().ifPresent(extensionService::register); Optional<DataExtension> optional = extension.get();
} catch (IllegalStateException e) { if (!optional.isPresent()) return;
DataExtension dataExtension = optional.get();
String extensionName = ExtensionExtractor.getPluginName(dataExtension.getClass());
if (disabledExtensions.contains(extensionName)) return;
extensionService.register(dataExtension);
} catch (IllegalStateException | NoClassDefFoundError | IncompatibleClassChangeError e) {
// Places all exceptions to one exception with plugin information so that they can be reported.
if (registerException == null) { if (registerException == null) {
registerException = e; registerException = new IllegalStateException("One or more extensions failed to register:");
} else { registerException.setStackTrace(new StackTraceElement[0]);
registerException.addSuppressed(e);
} }
IllegalStateException info = new IllegalStateException(factory.getSimpleName() + " ran into exception when creating Extension", e);
info.setStackTrace(new StackTraceElement[0]);
registerException.addSuppressed(info);
} }
} }
} }