From aa5e1beb7f260f41be66d556b42b43f0bf94f913 Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Sat, 1 Jun 2013 00:17:08 +0200 Subject: [PATCH] Added the ability to suppress arbitrary warnings and errors. --- .../comphenix/protocol/ProtocolConfig.java | 45 +++++ .../comphenix/protocol/ProtocolLibrary.java | 50 ++++- .../comphenix/protocol/error/ReportType.java | 181 +++++++++++------- ProtocolLib/src/main/resources/config.yml | 4 +- 4 files changed, 205 insertions(+), 75 deletions(-) diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java index 269bcb04..dc4c24fc 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolConfig.java @@ -19,6 +19,7 @@ package com.comphenix.protocol; import java.io.File; import java.io.IOException; +import java.util.List; import org.bukkit.configuration.Configuration; import org.bukkit.configuration.ConfigurationSection; @@ -26,6 +27,8 @@ import org.bukkit.plugin.Plugin; import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks; import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; import com.google.common.io.Files; /** @@ -48,6 +51,7 @@ class ProtocolConfig { private static final String INJECTION_METHOD = "injection method"; private static final String SCRIPT_ENGINE_NAME = "script engine"; + private static final String SUPPRESSED_REPORTS = "suppressed reports"; private static final String UPDATER_NOTIFY = "notify"; private static final String UPDATER_DOWNLAD = "download"; @@ -68,6 +72,9 @@ class ProtocolConfig { private boolean configChanged; private boolean valuesChanged; + // Modifications + private int modCount; + public ProtocolConfig(Plugin plugin) { this(plugin, plugin.getConfig()); } @@ -84,6 +91,7 @@ class ProtocolConfig { // Reset configChanged = false; valuesChanged = false; + modCount++; this.config = plugin.getConfig(); this.lastUpdateTime = loadLastUpdate(); @@ -199,6 +207,7 @@ class ProtocolConfig { */ public void setAutoNotify(boolean value) { setConfig(updater, UPDATER_NOTIFY, value); + modCount++; } /** @@ -215,6 +224,7 @@ class ProtocolConfig { */ public void setAutoDownload(boolean value) { setConfig(updater, UPDATER_DOWNLAD, value); + modCount++; } /** @@ -233,6 +243,24 @@ class ProtocolConfig { */ public void setDebug(boolean value) { setConfig(global, DEBUG_MODE_ENABLED, value); + modCount++; + } + + /** + * Retrieve an immutable list of every suppressed report type. + * @return Every suppressed report type. + */ + public ImmutableList getSuppressedReports() { + return ImmutableList.copyOf(global.getStringList(SUPPRESSED_REPORTS)); + } + + /** + * Set the list of suppressed report types, + * @param reports - suppressed report types. + */ + public void setSuppressedReports(List reports) { + global.set(SUPPRESSED_REPORTS, Lists.newArrayList(reports)); + modCount++; } /** @@ -255,6 +283,7 @@ class ProtocolConfig { if (delaySeconds < DEFAULT_UPDATER_DELAY) delaySeconds = DEFAULT_UPDATER_DELAY; setConfig(updater, UPDATER_DELAY, delaySeconds); + modCount++; } /** @@ -275,6 +304,7 @@ class ProtocolConfig { */ public void setIgnoreVersionCheck(String ignoreVersion) { setConfig(global, IGNORE_VERSION_CHECK, ignoreVersion); + modCount++; } /** @@ -294,6 +324,7 @@ class ProtocolConfig { */ public void setMetricsEnabled(boolean enabled) { setConfig(global, METRICS_ENABLED, enabled); + modCount++; } /** @@ -313,6 +344,7 @@ class ProtocolConfig { */ public void setBackgroundCompilerEnabled(boolean enabled) { setConfig(global, BACKGROUND_COMPILER_ENABLED, enabled); + modCount++; } /** @@ -325,6 +357,9 @@ class ProtocolConfig { /** * Set the last time we updated, in seconds since 1970.01.01 00:00. + *

+ * Note that this is not considered to modify the configuration, so the modification count + * will not be incremented. * @param lastTimeSeconds - new last update time. */ public void setAutoLastTime(long lastTimeSeconds) { @@ -348,6 +383,7 @@ class ProtocolConfig { */ public void setScriptEngineName(String name) { setConfig(global, SCRIPT_ENGINE_NAME, name); + modCount++; } /** @@ -380,6 +416,15 @@ class ProtocolConfig { */ public void setInjectionMethod(PlayerInjectHooks hook) { setConfig(global, INJECTION_METHOD, hook.name()); + modCount++; + } + + /** + * Retrieve the number of modifications made to this configuration. + * @return The number of modifications. + */ + public int getModificationCount() { + return modCount; } /** diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java index b93c662a..a9c4315f 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java @@ -19,6 +19,7 @@ package com.comphenix.protocol; import java.io.File; import java.io.IOException; +import java.util.Set; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; @@ -34,6 +35,7 @@ import org.bukkit.plugin.java.JavaPlugin; import com.comphenix.protocol.async.AsyncFilterManager; import com.comphenix.protocol.error.BasicErrorReporter; +import com.comphenix.protocol.error.DelegatedErrorReporter; import com.comphenix.protocol.error.DetailedErrorReporter; import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.Report; @@ -47,6 +49,9 @@ import com.comphenix.protocol.metrics.Updater.UpdateResult; import com.comphenix.protocol.reflect.compiler.BackgroundCompiler; import com.comphenix.protocol.utility.ChatExtensions; import com.comphenix.protocol.utility.MinecraftVersion; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; /** * The main entry point for ProtocolLib. @@ -136,12 +141,12 @@ public class ProtocolLibrary extends JavaPlugin { // Add global parameters DetailedErrorReporter detailedReporter = new DetailedErrorReporter(this); - reporter = detailedReporter; + reporter = getFilteredReporter(detailedReporter); try { config = new ProtocolConfig(this); } catch (Exception e) { - detailedReporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_LOAD_CONFIG).error(e)); + reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_LOAD_CONFIG).error(e)); // Load it again if (deleteConfig()) { @@ -168,7 +173,7 @@ public class ProtocolLibrary extends JavaPlugin { unhookTask = new DelayedSingleTask(this); protocolManager = new PacketFilterManager( - getClassLoader(), getServer(), this, version, unhookTask, detailedReporter); + getClassLoader(), getServer(), this, version, unhookTask, reporter); // Setup error reporter detailedReporter.addGlobalParameter("manager", protocolManager); @@ -183,23 +188,52 @@ public class ProtocolLibrary extends JavaPlugin { protocolManager.setPlayerHook(hook); } } catch (IllegalArgumentException e) { - detailedReporter.reportWarning(config, Report.newBuilder(REPORT_CANNOT_PARSE_INJECTION_METHOD).error(e)); + reporter.reportWarning(config, Report.newBuilder(REPORT_CANNOT_PARSE_INJECTION_METHOD).error(e)); } // Initialize command handlers - commandProtocol = new CommandProtocol(detailedReporter, this, updater, config); - commandFilter = new CommandFilter(detailedReporter, this, config); - commandPacket = new CommandPacket(detailedReporter, this, logger, commandFilter, protocolManager); + commandProtocol = new CommandProtocol(reporter, this, updater, config); + commandFilter = new CommandFilter(reporter, this, config); + commandPacket = new CommandPacket(reporter, this, logger, commandFilter, protocolManager); // Send logging information to player listeners too setupBroadcastUsers(PERMISSION_INFO); } catch (Throwable e) { - detailedReporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_LOAD_ERROR).error(e).callerParam(protocolManager)); + reporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_LOAD_ERROR).error(e).callerParam(protocolManager)); disablePlugin(); } } + /** + * Retrieve a error reporter that may be filtered by the configuration. + * @return The new default error reporter. + */ + private ErrorReporter getFilteredReporter(ErrorReporter reporter) { + return new DelegatedErrorReporter(reporter) { + private int lastModCount = -1; + private Set reports = Sets.newHashSet(); + + @Override + protected Report filterReport(Object sender, Report report, boolean detailed) { + String canonicalName = ReportType.getReportName(sender.getClass(), report.getType()); + String reportName = Iterables.getLast(Splitter.on("#").split(canonicalName)).toUpperCase(); + + if (config != null && config.getModificationCount() != lastModCount) { + // Update our cached set again + reports = Sets.newHashSet(config.getSuppressedReports()); + lastModCount = config.getModificationCount(); + } + + // Cancel reports either on the full canonical name, or just the report name + if (reports.contains(canonicalName) || reports.contains(reportName)) + return null; + else + return report; + } + }; + } + private boolean deleteConfig() { return config.getFile().delete(); } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/error/ReportType.java b/ProtocolLib/src/main/java/com/comphenix/protocol/error/ReportType.java index cd4490e0..e795677c 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/error/ReportType.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/error/ReportType.java @@ -1,66 +1,115 @@ -package com.comphenix.protocol.error; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; - -import com.comphenix.protocol.reflect.FieldAccessException; - -/** - * Represents a strongly-typed report. Subclasses should be immutable. - *

- * By convention, a report must be declared as a static field publicly accessible from the sender class. - * @author Kristian - */ -public class ReportType { - private final String errorFormat; - - /** - * Construct a new report type. - * @param errorFormat - string used to format the underlying report. - */ - public ReportType(String errorFormat) { - this.errorFormat = errorFormat; - } - - /** - * Convert the given report to a string, using the provided parameters. - * @param parameters - parameters to insert, or NULL to insert nothing. - * @return The full report in string format. - */ - public String getMessage(Object[] parameters) { - if (parameters == null || parameters.length == 0) - return toString(); - else - return String.format(errorFormat, parameters); - } - - @Override - public String toString() { - return errorFormat; - } - - /** - * Retrieve all publicly associated reports. - * @param clazz - sender class. - * @return All associated reports. - */ - public static ReportType[] getReports(Class clazz) { - if (clazz == null) - throw new IllegalArgumentException("clazz cannot be NULL."); - List result = new ArrayList(); - - for (Field field : clazz.getFields()) { - if (Modifier.isStatic(field.getModifiers()) && - ReportType.class.isAssignableFrom(field.getDeclaringClass())) { - try { - result.add((ReportType) field.get(null)); - } catch (IllegalAccessException e) { - throw new FieldAccessException("Unable to access field.", e); - } - } - } - return result.toArray(new ReportType[0]); - } -} +package com.comphenix.protocol.error; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +import com.comphenix.protocol.reflect.FieldAccessException; +import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract; + +/** + * Represents a strongly-typed report. Subclasses should be immutable. + *

+ * By convention, a report must be declared as a static field publicly accessible from the sender class. + * @author Kristian + */ +public class ReportType { + private final String errorFormat; + + // Used to store the report name + protected String reportName; + + /** + * Construct a new report type. + * @param errorFormat - string used to format the underlying report. + */ + public ReportType(String errorFormat) { + this.errorFormat = errorFormat; + } + + /** + * Convert the given report to a string, using the provided parameters. + * @param parameters - parameters to insert, or NULL to insert nothing. + * @return The full report in string format. + */ + public String getMessage(Object[] parameters) { + if (parameters == null || parameters.length == 0) + return toString(); + else + return String.format(errorFormat, parameters); + } + + @Override + public String toString() { + return errorFormat; + } + + /** + * Retrieve the full canonical name of a given report type. + *

+ * This is in the format canonical_name_of_class#report_type + * @param clazz - the sender class. + * @param type - the report instance. + * @return The full canonical name. + */ + public static String getReportName(Class sender, ReportType type) { + if (sender == null) + throw new IllegalArgumentException("sender cannot be NUll."); + + // Whether or not we need to retrieve the report name again + if (type.reportName == null) { + for (Field field : getReportFields(sender)) { + try { + field.setAccessible(true); + + if (field.get(null) == type) { + // We got the right field! + return type.reportName = field.getDeclaringClass().getCanonicalName() + "#" + field.getName(); + } + } catch (IllegalAccessException e) { + throw new FieldAccessException("Unable to read field " + field, e); + } + } + throw new IllegalArgumentException("Cannot find report name for " + type); + } + return type.reportName; + } + + /** + * Retrieve all publicly associated reports. + * @param sender - sender class. + * @return All associated reports. + */ + public static ReportType[] getReports(Class sender) { + if (sender == null) + throw new IllegalArgumentException("sender cannot be NULL."); + List result = new ArrayList(); + + // Go through all the fields + for (Field field : getReportFields(sender)) { + try { + field.setAccessible(true); + result.add((ReportType) field.get(null)); + } catch (IllegalAccessException e) { + throw new FieldAccessException("Unable to read field " + field, e); + } + } + return result.toArray(new ReportType[0]); + } + + /** + * Retrieve all publicly associated report fields. + * @param clazz - sender class. + * @return All associated report fields. + */ + private static List getReportFields(Class clazz) { + return FuzzyReflection.fromClass(clazz).getFieldList( + FuzzyFieldContract.newBuilder(). + requireModifier(Modifier.STATIC). + typeDerivedOf(ReportType.class). + build() + ); + } +} diff --git a/ProtocolLib/src/main/resources/config.yml b/ProtocolLib/src/main/resources/config.yml index 02c7dd23..2ca7f9ef 100644 --- a/ProtocolLib/src/main/resources/config.yml +++ b/ProtocolLib/src/main/resources/config.yml @@ -22,4 +22,6 @@ global: debug: false # The engine used by the filter command - script engine: JavaScript \ No newline at end of file + script engine: JavaScript + + suppressed reports: \ No newline at end of file