From 7ce052900edf3038633f4bcc1c4e55b1721ca8c7 Mon Sep 17 00:00:00 2001 From: Jerome van der Sar Date: Sat, 30 Nov 2013 20:44:08 +0100 Subject: [PATCH] Rewrote ServiceChecker, fixed NPE there Formatting --- build.xml | 28 +- buildnumber.properties | 4 +- nbproject/build-impl.xml | 122 +++---- .../Commands/Command_services.java | 8 +- .../TotalFreedomMod/TFM_ServiceChecker.java | 169 ++++++---- .../TotalFreedomMod/TotalFreedomMod.java | 4 +- src/org/mcstats/Metrics.java | 319 ++++++++++++------ 7 files changed, 393 insertions(+), 261 deletions(-) diff --git a/build.xml b/build.xml index 18d244b9..2dc5c448 100644 --- a/build.xml +++ b/build.xml @@ -2,19 +2,19 @@ Builds, tests, and runs the project TotalFreedomMod. - - - - - - - - - + + + + + + + + + - - - - - + + + + + diff --git a/buildnumber.properties b/buildnumber.properties index ec656df0..d3ffa48c 100644 --- a/buildnumber.properties +++ b/buildnumber.properties @@ -1,3 +1,3 @@ #Build Number for ANT. Do not edit! -#Sat Nov 30 16:57:41 CET 2013 -build.number=622 +#Sat Nov 30 20:40:55 CET 2013 +build.number=636 diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml index ce5b0bae..e6d516f8 100644 --- a/nbproject/build-impl.xml +++ b/nbproject/build-impl.xml @@ -18,7 +18,7 @@ is divided into following sections: - applet - cleanup - --> +--> @@ -29,10 +29,10 @@ is divided into following sections: + ====================== + INITIALIZATION SECTION + ====================== + --> @@ -645,8 +645,8 @@ is divided into following sections: + pre NB7.2 profiling section; consider it deprecated + --> @@ -693,8 +693,8 @@ is divided into following sections: Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + end of pre NB7.2 profiling section + --> @@ -854,10 +854,10 @@ is divided into following sections: + =================== + COMPILATION SECTION + =================== + --> @@ -928,10 +928,10 @@ is divided into following sections: + ==================== + JAR BUILDING SECTION + ==================== + --> @@ -1000,10 +1000,10 @@ is divided into following sections: + ================= + EXECUTION SECTION + ================= + --> @@ -1023,10 +1023,10 @@ is divided into following sections: + ================= + DEBUGGING SECTION + ================= + --> @@ -1064,13 +1064,13 @@ is divided into following sections: + ================= + PROFILING SECTION + ================= + --> + pre NB7.2 profiler integration + --> This target only works when run from inside the NetBeans IDE. @@ -1127,8 +1127,8 @@ is divided into following sections: + end of pre NB72 profiling section + --> @@ -1163,10 +1163,10 @@ is divided into following sections: + =============== + JAVADOC SECTION + =============== + --> @@ -1204,10 +1204,10 @@ is divided into following sections: + ========================= + TEST COMPILATION SECTION + ========================= + --> @@ -1243,10 +1243,10 @@ is divided into following sections: + ======================= + TEST EXECUTION SECTION + ======================= + --> @@ -1280,10 +1280,10 @@ is divided into following sections: + ======================= + TEST DEBUGGING SECTION + ======================= + --> Must select one file in the IDE or set test.class @@ -1303,10 +1303,10 @@ is divided into following sections: + ========================= + APPLET EXECUTION SECTION + ========================= + --> Must select one file in the IDE or set applet.url @@ -1316,10 +1316,10 @@ is divided into following sections: + ========================= + APPLET DEBUGGING SECTION + ========================= + --> Must select one file in the IDE or set applet.url @@ -1330,10 +1330,10 @@ is divided into following sections: + =============== + CLEANUP SECTION + =============== + --> diff --git a/src/me/StevenLawson/TotalFreedomMod/Commands/Command_services.java b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_services.java index 8e7174b5..694823e1 100644 --- a/src/me/StevenLawson/TotalFreedomMod/Commands/Command_services.java +++ b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_services.java @@ -1,7 +1,7 @@ package me.StevenLawson.TotalFreedomMod.Commands; import me.StevenLawson.TotalFreedomMod.TFM_ServiceChecker; -import me.StevenLawson.TotalFreedomMod.TFM_ServiceChecker.TFM_ServiceChecker_ServiceStatus; +import me.StevenLawson.TotalFreedomMod.TFM_ServiceChecker.ServiceStatus; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -16,12 +16,12 @@ public class Command_services extends TFM_Command { playerMsg("Mojang Services" + ChatColor.WHITE + ":", ChatColor.BLUE); - for (TFM_ServiceChecker_ServiceStatus service : TFM_ServiceChecker.getInstance().getAllStatuses()) + for (ServiceStatus service : TFM_ServiceChecker.getInstance().getAllStatuses()) { playerMsg(service.getFormattedStatus()); } - playerMsg("Version" + ChatColor.WHITE + ": " + TFM_ServiceChecker.getInstance().version, ChatColor.DARK_PURPLE); - playerMsg("Last Check" + ChatColor.WHITE + ": " + TFM_ServiceChecker.getInstance().lastCheck, ChatColor.DARK_PURPLE); + playerMsg("Version" + ChatColor.WHITE + ": " + TFM_ServiceChecker.getInstance().getVersion(), ChatColor.DARK_PURPLE); + playerMsg("Last Check" + ChatColor.WHITE + ": " + TFM_ServiceChecker.getInstance().getLastCheck(), ChatColor.DARK_PURPLE); return true; } diff --git a/src/me/StevenLawson/TotalFreedomMod/TFM_ServiceChecker.java b/src/me/StevenLawson/TotalFreedomMod/TFM_ServiceChecker.java index 3a66edf4..e7eef83b 100644 --- a/src/me/StevenLawson/TotalFreedomMod/TFM_ServiceChecker.java +++ b/src/me/StevenLawson/TotalFreedomMod/TFM_ServiceChecker.java @@ -2,8 +2,10 @@ package me.StevenLawson.TotalFreedomMod; import java.io.BufferedReader; import java.io.InputStreamReader; +import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -17,22 +19,45 @@ import org.json.simple.JSONValue; public class TFM_ServiceChecker { - public final Map services = new HashMap(); - public String lastCheck = "Unknown"; - public String version = "1.0-Mojang"; + public final Map services = new HashMap(); + private URL url; + private String lastCheck = "Unknown"; + private String version = "1.0-Mojang"; public TFM_ServiceChecker() { - services.put("minecraft.net", new TFM_ServiceChecker_ServiceStatus("Minecraft.net")); - services.put("account.mojang.com", new TFM_ServiceChecker_ServiceStatus("Mojang Account Website")); - services.put("authserver.mojang.com", new TFM_ServiceChecker_ServiceStatus("Mojang Authentication")); - services.put("skins.minecraft.net", new TFM_ServiceChecker_ServiceStatus("Minecraft Skins")); - services.put("auth.mojang.com", new TFM_ServiceChecker_ServiceStatus("Mojang Authentiation (Legacy)")); - services.put("login.minecraft.net", new TFM_ServiceChecker_ServiceStatus("Minecraft Logins (Legacy)")); - services.put("session.minecraft.net", new TFM_ServiceChecker_ServiceStatus("Minecraft Sessions (Legacy)")); + services.put("minecraft.net", new ServiceStatus("Minecraft.net")); + services.put("account.mojang.com", new ServiceStatus("Mojang Account Website")); + services.put("authserver.mojang.com", new ServiceStatus("Mojang Authentication")); + services.put("sessionserver.mojang.com", new ServiceStatus("Mojang Multiplayer sessions")); + services.put("skins.minecraft.net", new ServiceStatus("Minecraft Skins")); + services.put("auth.mojang.com", new ServiceStatus("Mojang Authentiation (Legacy)")); + services.put("login.minecraft.net", new ServiceStatus("Minecraft Logins (Legacy)")); + services.put("session.minecraft.net", new ServiceStatus("Minecraft Sessions (Legacy)")); + } + + public void start() + { + final String serviceCheckerURL = TFM_ConfigEntry.SERVICE_CHECKER_URL.getString(); + + if (serviceCheckerURL == null || serviceCheckerURL.isEmpty()) + { + return; + } + + try + { + url = new URL(serviceCheckerURL); + } + catch (MalformedURLException ex) + { + TFM_Log.severe("Invalid ServiceChecker URL, disabling service checker"); + return; + } + + getUpdateRunnable().runTaskTimerAsynchronously(TotalFreedomMod.plugin, 40L, TotalFreedomMod.SERVICE_CHECKER_RATE * 20L); } - @SuppressWarnings("unchecked") public BukkitRunnable getUpdateRunnable() { return new BukkitRunnable() @@ -40,78 +65,92 @@ public class TFM_ServiceChecker @Override public void run() { - final String serviceCheckerURL = TFM_ConfigEntry.SERVICE_CHECKER_URL.getString(); - - if (serviceCheckerURL == null || serviceCheckerURL.isEmpty()) + if (url == null) { return; } + final JSONArray statusJson; try { - URL mojangStatus = new URL(serviceCheckerURL); - BufferedReader in = new BufferedReader(new InputStreamReader(mojangStatus.openStream())); - JSONArray statusJson = (JSONArray) JSONValue.parse(in.readLine()); + final BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); + statusJson = (JSONArray) JSONValue.parse(in.readLine()); in.close(); - - TFM_ServiceChecker serviceChecker = TFM_ServiceChecker.getInstance(); - - Iterator status_it = statusJson.iterator(); - while (status_it.hasNext()) - { - JSONObject service = (JSONObject) status_it.next(); - Iterator serviceIt = service.entrySet().iterator(); - while (serviceIt.hasNext()) - { - Entry pair = (Entry) serviceIt.next(); - - if ("lastcheck".equals(pair.getKey())) - { - serviceChecker.lastCheck = pair.getValue(); - continue; - } - - if ("version".equals(pair.getKey())) - { - serviceChecker.version = pair.getValue(); - continue; - } - - if (pair.getValue().contains(":")) - { - String[] statusString = pair.getValue().split(":"); - TFM_ServiceChecker_ServiceStatus status = serviceChecker.services.get(pair.getKey()); - status.setColor(statusString[0]); - status.setMessage(statusString[1]); - status.setUptime(statusString[2]); - } - else - { - TFM_ServiceChecker_ServiceStatus status = serviceChecker.services.get(pair.getKey()); - status.setColor(pair.getValue()); - status.setMessage(("red".equals(pair.getValue()) ? "Offline" : ("yellow".equals(pair.getValue()) ? "Problem" : "Online"))); - } - } - } - } catch (Exception ex) { - TFM_Log.severe("Error updating mojang services from " + serviceCheckerURL); + TFM_Log.severe("Error updating mojang services from " + url); TFM_Log.severe(ex); + return; + } + + final Iterator status = statusJson.iterator(); + while (status.hasNext()) + { + final Iterator serviceIt = ((JSONObject) status.next()).entrySet().iterator(); + while (serviceIt.hasNext()) + { + final Entry pair = (Entry) serviceIt.next(); + + if ("lastcheck".equals(pair.getKey())) + { + lastCheck = pair.getValue(); + continue; + } + + if ("version".equals(pair.getKey())) + { + version = pair.getValue(); + continue; + } + + final ServiceStatus service = services.get(pair.getKey()); + if (service == null) + { + TFM_Log.warning("ServiceChecker found unknown service: " + pair.getKey()); + continue; + } + + if (pair.getValue().contains(":")) + { + String[] statusString = pair.getValue().split(":"); + service.setColor(statusString[0]); + service.setMessage(statusString[1]); + service.setUptime(statusString[2]); + } + else + { + service.setColor(pair.getValue()); + service.setMessage(("red".equals(pair.getValue()) ? "Offline" : ("yellow".equals(pair.getValue()) ? "Problem" : "Online"))); + } + } + } + if (lastCheck.equals("Unknown")) + { + lastCheck = TFM_Util.dateToString(new Date()); } } }; } - public List getAllStatuses() + public List getAllStatuses() { - List ServicesList = new ArrayList(); + List servicesList = new ArrayList(); for (String key : services.keySet()) { - ServicesList.add(services.get(key)); + servicesList.add(services.get(key)); } - return ServicesList; + return servicesList; + } + + public String getLastCheck() + { + return lastCheck; + } + + public String getVersion() + { + return version; } public static TFM_ServiceChecker getInstance() @@ -124,14 +163,14 @@ public class TFM_ServiceChecker private static final TFM_ServiceChecker INSTANCE = new TFM_ServiceChecker(); } - public class TFM_ServiceChecker_ServiceStatus + public static class ServiceStatus { private String name; private String uptime = "100.0"; // skins.minecraft.net, minecraft.net, etc.. private ChatColor color = ChatColor.DARK_GREEN; private String message = "Online"; // Online, Offline, Quite Slow, 404 Error, 500 Error, etc.. - public TFM_ServiceChecker_ServiceStatus(String name) + public ServiceStatus(String name) { this.name = name; } diff --git a/src/me/StevenLawson/TotalFreedomMod/TotalFreedomMod.java b/src/me/StevenLawson/TotalFreedomMod/TotalFreedomMod.java index 87a45618..f16338b6 100644 --- a/src/me/StevenLawson/TotalFreedomMod/TotalFreedomMod.java +++ b/src/me/StevenLawson/TotalFreedomMod/TotalFreedomMod.java @@ -160,10 +160,8 @@ public class TotalFreedomMod extends JavaPlugin TFM_Log.warning("Failed to submit metrics data: " + ex.getMessage()); } - TFM_ServiceChecker.getInstance().getUpdateRunnable().runTaskTimerAsynchronously(plugin, 40L, SERVICE_CHECKER_RATE * 20L); - + TFM_ServiceChecker.getInstance().start(); TFM_HTTPD_Manager.getInstance().start(); - TFM_FrontDoor.getInstance().start(); TFM_Log.info("Version " + pluginVersion + " enabled"); diff --git a/src/org/mcstats/Metrics.java b/src/org/mcstats/Metrics.java index 8fbb3acc..6cb74682 100644 --- a/src/org/mcstats/Metrics.java +++ b/src/org/mcstats/Metrics.java @@ -54,70 +54,61 @@ import java.util.UUID; import java.util.logging.Level; import java.util.zip.GZIPOutputStream; -public class Metrics { - +public class Metrics +{ /** * The current revision number */ private final static int REVISION = 7; - /** * The base url of the metrics domain */ private static final String BASE_URL = "http://report.mcstats.org"; - /** * The url used to report a server's status */ private static final String REPORT_URL = "/plugin/%s"; - /** * Interval of time to ping (in minutes) */ private static final int PING_INTERVAL = 15; - /** * The plugin this metrics submits for */ private final Plugin plugin; - /** * All of the custom graphs to submit to metrics */ private final Set graphs = Collections.synchronizedSet(new HashSet()); - /** * The plugin configuration file */ private final YamlConfiguration configuration; - /** * The plugin configuration file */ private final File configurationFile; - /** * Unique server id */ private final String guid; - /** * Debug mode */ private final boolean debug; - /** * Lock for synchronization */ private final Object optOutLock = new Object(); - /** * The scheduled task */ private volatile BukkitTask task = null; - public Metrics(final Plugin plugin) throws IOException { - if (plugin == null) { + public Metrics(final Plugin plugin) throws IOException + { + if (plugin == null) + { throw new IllegalArgumentException("Plugin cannot be null"); } @@ -133,7 +124,8 @@ public class Metrics { configuration.addDefault("debug", false); // Do we need to create the file? - if (configuration.get("guid", null) == null) { + if (configuration.get("guid", null) == null) + { configuration.options().header("http://mcstats.org").copyDefaults(true); configuration.save(configurationFile); } @@ -150,8 +142,10 @@ public class Metrics { * @param name The name of the graph * @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given */ - public Graph createGraph(final String name) { - if (name == null) { + public Graph createGraph(final String name) + { + if (name == null) + { throw new IllegalArgumentException("Graph name cannot be null"); } @@ -170,8 +164,10 @@ public class Metrics { * * @param graph The name of the graph */ - public void addGraph(final Graph graph) { - if (graph == null) { + public void addGraph(final Graph graph) + { + if (graph == null) + { throw new IllegalArgumentException("Graph cannot be null"); } @@ -185,33 +181,42 @@ public class Metrics { * * @return True if statistics measuring is running, otherwise false. */ - public boolean start() { - synchronized (optOutLock) { + public boolean start() + { + synchronized (optOutLock) + { // Did we opt out? - if (isOptOut()) { + if (isOptOut()) + { return false; } // Is metrics already running? - if (task != null) { + if (task != null) + { return true; } // Begin hitting the server with glorious data - task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() { - + task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() + { private boolean firstPost = true; - public void run() { - try { + public void run() + { + try + { // This has to be synchronized or it can collide with the disable method. - synchronized (optOutLock) { + synchronized (optOutLock) + { // Disable Task, if it is running and the server owner decided to opt-out - if (isOptOut() && task != null) { + if (isOptOut() && task != null) + { task.cancel(); task = null; // Tell all plotters to stop gathering information. - for (Graph graph : graphs) { + for (Graph graph : graphs) + { graph.onOptOut(); } } @@ -225,8 +230,11 @@ public class Metrics { // After the first post we set firstPost to false // Each post thereafter will be a ping firstPost = false; - } catch (IOException e) { - if (debug) { + } + catch (IOException e) + { + if (debug) + { Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage()); } } @@ -242,18 +250,27 @@ public class Metrics { * * @return true if metrics should be opted out of it */ - public boolean isOptOut() { - synchronized (optOutLock) { - try { + public boolean isOptOut() + { + synchronized (optOutLock) + { + try + { // Reload the metrics file configuration.load(getConfigFile()); - } catch (IOException ex) { - if (debug) { + } + catch (IOException ex) + { + if (debug) + { Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); } return true; - } catch (InvalidConfigurationException ex) { - if (debug) { + } + catch (InvalidConfigurationException ex) + { + if (debug) + { Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); } return true; @@ -267,17 +284,21 @@ public class Metrics { * * @throws java.io.IOException */ - public void enable() throws IOException { + public void enable() throws IOException + { // This has to be synchronized or it can collide with the check in the task. - synchronized (optOutLock) { + synchronized (optOutLock) + { // Check if the server owner has already set opt-out, if not, set it. - if (isOptOut()) { + if (isOptOut()) + { configuration.set("opt-out", false); configuration.save(configurationFile); } // Enable Task, if it is not running - if (task == null) { + if (task == null) + { start(); } } @@ -288,17 +309,21 @@ public class Metrics { * * @throws java.io.IOException */ - public void disable() throws IOException { + public void disable() throws IOException + { // This has to be synchronized or it can collide with the check in the task. - synchronized (optOutLock) { + synchronized (optOutLock) + { // Check if the server owner has already set opt-out, if not, set it. - if (!isOptOut()) { + if (!isOptOut()) + { configuration.set("opt-out", true); configuration.save(configurationFile); } // Disable Task, if it is running - if (task != null) { + if (task != null) + { task.cancel(); task = null; } @@ -310,7 +335,8 @@ public class Metrics { * * @return the File object for the config file */ - public File getConfigFile() { + public File getConfigFile() + { // I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use // is to abuse the plugin object we already have // plugin.getDataFolder() => base/plugins/PluginA/ @@ -325,7 +351,8 @@ public class Metrics { /** * Generic method that posts a plugin to the metrics website */ - private void postPlugin(final boolean isPing) throws IOException { + private void postPlugin(final boolean isPing) throws IOException + { // Server software specific section PluginDescriptionFile description = plugin.getDescription(); String pluginName = description.getName(); @@ -354,7 +381,8 @@ public class Metrics { int coreCount = Runtime.getRuntime().availableProcessors(); // normalize os arch .. amd64 -> x86_64 - if (osarch.equals("amd64")) { + if (osarch.equals("amd64")) + { osarch = "x86_64"; } @@ -366,12 +394,15 @@ public class Metrics { appendJSONPair(json, "java_version", java_version); // If we're pinging, append it - if (isPing) { + if (isPing) + { appendJSONPair(json, "ping", "1"); } - if (graphs.size() > 0) { - synchronized (graphs) { + if (graphs.size() > 0) + { + synchronized (graphs) + { json.append(','); json.append('"'); json.append("graphs"); @@ -383,19 +414,22 @@ public class Metrics { final Iterator iter = graphs.iterator(); - while (iter.hasNext()) { + while (iter.hasNext()) + { Graph graph = iter.next(); StringBuilder graphJson = new StringBuilder(); graphJson.append('{'); - for (Plotter plotter : graph.getPlotters()) { + for (Plotter plotter : graph.getPlotters()) + { appendJSONPair(graphJson, plotter.getColumnName(), Integer.toString(plotter.getValue())); } graphJson.append('}'); - if (!firstGraph) { + if (!firstGraph) + { json.append(','); } @@ -421,9 +455,12 @@ public class Metrics { // Mineshafter creates a socks proxy, so we can safely bypass it // It does not reroute POST requests so we need to go around it - if (isMineshafterPresent()) { + if (isMineshafterPresent()) + { connection = url.openConnection(Proxy.NO_PROXY); - } else { + } + else + { connection = url.openConnection(); } @@ -441,7 +478,8 @@ public class Metrics { connection.setDoOutput(true); - if (debug) { + if (debug) + { System.out.println("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length); } @@ -458,24 +496,34 @@ public class Metrics { os.close(); reader.close(); - if (response == null || response.startsWith("ERR") || response.startsWith("7")) { - if (response == null) { + if (response == null || response.startsWith("ERR") || response.startsWith("7")) + { + if (response == null) + { response = "null"; - } else if (response.startsWith("7")) { + } + else if (response.startsWith("7")) + { response = response.substring(response.startsWith("7,") ? 2 : 1); } throw new IOException(response); - } else { + } + else + { // Is this the first update this hour? - if (response.equals("1") || response.contains("This is your first update this hour")) { - synchronized (graphs) { + if (response.equals("1") || response.contains("This is your first update this hour")) + { + synchronized (graphs) + { final Iterator iter = graphs.iterator(); - while (iter.hasNext()) { + while (iter.hasNext()) + { final Graph graph = iter.next(); - for (Plotter plotter : graph.getPlotters()) { + for (Plotter plotter : graph.getPlotters()) + { plotter.reset(); } } @@ -490,19 +538,31 @@ public class Metrics { * @param input * @return */ - public static byte[] gzip(String input) { + public static byte[] gzip(String input) + { ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream gzos = null; - try { + try + { gzos = new GZIPOutputStream(baos); gzos.write(input.getBytes("UTF-8")); - } catch (IOException e) { + } + catch (IOException e) + { e.printStackTrace(); - } finally { - if (gzos != null) try { - gzos.close(); - } catch (IOException ignore) { + } + finally + { + if (gzos != null) + { + try + { + gzos.close(); + } + catch (IOException ignore) + { + } } } @@ -514,11 +574,15 @@ public class Metrics { * * @return true if mineshafter is installed on the server */ - private boolean isMineshafterPresent() { - try { + private boolean isMineshafterPresent() + { + try + { Class.forName("mineshafter.MineServer"); return true; - } catch (Exception e) { + } + catch (Exception e) + { return false; } } @@ -531,28 +595,37 @@ public class Metrics { * @param value * @throws UnsupportedEncodingException */ - private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException { + private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException + { boolean isValueNumeric = false; - try { - if (value.equals("0") || !value.endsWith("0")) { + try + { + if (value.equals("0") || !value.endsWith("0")) + { Double.parseDouble(value); isValueNumeric = true; } - } catch (NumberFormatException e) { + } + catch (NumberFormatException e) + { isValueNumeric = false; } - if (json.charAt(json.length() - 1) != '{') { + if (json.charAt(json.length() - 1) != '{') + { json.append(','); } json.append(escapeJSON(key)); json.append(':'); - if (isValueNumeric) { + if (isValueNumeric) + { json.append(value); - } else { + } + else + { json.append(escapeJSON(value)); } } @@ -563,14 +636,17 @@ public class Metrics { * @param text * @return */ - private static String escapeJSON(String text) { + private static String escapeJSON(String text) + { StringBuilder builder = new StringBuilder(); builder.append('"'); - for (int index = 0; index < text.length(); index++) { + for (int index = 0; index < text.length(); index++) + { char chr = text.charAt(index); - switch (chr) { + switch (chr) + { case '"': case '\\': builder.append('\\'); @@ -589,10 +665,13 @@ public class Metrics { builder.append("\\r"); break; default: - if (chr < ' ') { + if (chr < ' ') + { String t = "000" + Integer.toHexString(chr); builder.append("\\u" + t.substring(t.length() - 4)); - } else { + } + else + { builder.append(chr); } break; @@ -609,27 +688,28 @@ public class Metrics { * @param text the text to encode * @return the encoded text, as UTF-8 */ - private static String urlEncode(final String text) throws UnsupportedEncodingException { + private static String urlEncode(final String text) throws UnsupportedEncodingException + { return URLEncoder.encode(text, "UTF-8"); } /** * Represents a custom graph on the website */ - public static class Graph { - + public static class Graph + { /** * The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is * rejected */ private final String name; - /** * The set of plotters that are contained within this graph */ private final Set plotters = new LinkedHashSet(); - private Graph(final String name) { + private Graph(final String name) + { this.name = name; } @@ -638,7 +718,8 @@ public class Metrics { * * @return the Graph's name */ - public String getName() { + public String getName() + { return name; } @@ -647,7 +728,8 @@ public class Metrics { * * @param plotter the plotter to add to the graph */ - public void addPlotter(final Plotter plotter) { + public void addPlotter(final Plotter plotter) + { plotters.add(plotter); } @@ -656,7 +738,8 @@ public class Metrics { * * @param plotter the plotter to remove from the graph */ - public void removePlotter(final Plotter plotter) { + public void removePlotter(final Plotter plotter) + { plotters.remove(plotter); } @@ -665,18 +748,22 @@ public class Metrics { * * @return an unmodifiable {@link java.util.Set} of the plotter objects */ - public Set getPlotters() { + public Set getPlotters() + { return Collections.unmodifiableSet(plotters); } @Override - public int hashCode() { + public int hashCode() + { return name.hashCode(); } @Override - public boolean equals(final Object object) { - if (!(object instanceof Graph)) { + public boolean equals(final Object object) + { + if (!(object instanceof Graph)) + { return false; } @@ -687,15 +774,16 @@ public class Metrics { /** * Called when the server owner decides to opt-out of BukkitMetrics while the server is running. */ - protected void onOptOut() { + protected void onOptOut() + { } } /** * Interface used to collect custom data for a plugin */ - public static abstract class Plotter { - + public static abstract class Plotter + { /** * The plot's name */ @@ -704,7 +792,8 @@ public class Metrics { /** * Construct a plotter with the default plot name */ - public Plotter() { + public Plotter() + { this("Default"); } @@ -713,7 +802,8 @@ public class Metrics { * * @param name the name of the plotter to use, which will show up on the website */ - public Plotter(final String name) { + public Plotter(final String name) + { this.name = name; } @@ -731,24 +821,29 @@ public class Metrics { * * @return the plotted point's column name */ - public String getColumnName() { + public String getColumnName() + { return name; } /** * Called after the website graphs have been updated */ - public void reset() { + public void reset() + { } @Override - public int hashCode() { + public int hashCode() + { return getColumnName().hashCode(); } @Override - public boolean equals(final Object object) { - if (!(object instanceof Plotter)) { + public boolean equals(final Object object) + { + if (!(object instanceof Plotter)) + { return false; }