Java tutorial
/* * This file is licensed under the MIT License (MIT). * * Copyright (c) 2014 Daniel Ennis <http://aikar.co> * * 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 org.spigotmc.timings; import com.google.common.base.Function; import com.google.common.collect.Sets; import org.apache.commons.lang.StringUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.RemoteConsoleCommandSender; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemorySection; import org.bukkit.entity.EntityType; import org.bukkit.plugin.Plugin; import org.json.simple.JSONObject; import org.json.simple.JSONValue; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.URL; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.zip.GZIPOutputStream; import static org.spigotmc.timings.TimingsManager.HISTORY; import static org.spigotmc.util.JSONUtil.*; @SuppressWarnings({ "rawtypes", "SuppressionAnnotation" }) class TimingsExport extends Thread { private final CommandSender sender; private final Map out; private final TimingHistory[] history; TimingsExport(CommandSender sender, Map out, TimingHistory[] history) { super("Timings paste thread"); this.sender = sender; this.out = out; this.history = history; } /** * Builds an XML report of the timings to be uploaded for parsing. * * @param sender Who to report to */ static void reportTimings(CommandSender sender) { Map parent = createObject( // Get some basic system details about the server pair("version", Bukkit.getVersion()), pair("maxplayers", Bukkit.getMaxPlayers()), pair("start", TimingsManager.timingStart / 1000), pair("end", System.currentTimeMillis() / 1000), pair("sampletime", (System.currentTimeMillis() - TimingsManager.timingStart) / 1000)); if (!TimingsManager.privacy) { appendObjectData(parent, pair("server", Bukkit.getServerName()), pair("motd", Bukkit.getServer().getMotd()), pair("online-mode", Bukkit.getServer().getOnlineMode()), pair("icon", Bukkit.getServer().getServerIcon().getData())); } final Runtime runtime = Runtime.getRuntime(); parent.put("system", createObject(pair("timingcost", getCost()), pair("name", System.getProperty("os.name")), pair("version", System.getProperty("os.version")), pair("arch", System.getProperty("os.arch")), pair("totalmem", runtime.totalMemory()), pair("usedmem", runtime.totalMemory() - runtime.freeMemory()), pair("maxmem", runtime.maxMemory()), pair("cpu", runtime.availableProcessors()), pair("runtime", (System.currentTimeMillis() / 1000) - TimingsManager.SERVER_START))); Set<Material> tileEntityTypeSet = Sets.newHashSet(); Set<EntityType> entityTypeSet = Sets.newHashSet(); int size = HISTORY.size(); TimingHistory[] history = new TimingHistory[size + 1]; int i = 0; for (TimingHistory timingHistory : HISTORY) { tileEntityTypeSet.addAll(timingHistory.tileEntityTypeSet); entityTypeSet.addAll(timingHistory.entityTypeSet); history[i++] = timingHistory; } history[i] = new TimingHistory(); // Current snapshot tileEntityTypeSet.addAll(history[i].tileEntityTypeSet); entityTypeSet.addAll(history[i].entityTypeSet); Map handlers = createObject(); for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) { for (TimingHandler id : group.handlers) { if (!id.timed && !id.isSpecial()) { continue; } handlers.put(id.id, toArray(group.id, id.name)); } } parent.put("idmap", createObject(pair("groups", toObjectMapper(TimingIdentifier.GROUP_MAP.values(), new Function<TimingIdentifier.TimingGroup, JSONPair>() { @Override public JSONPair apply(TimingIdentifier.TimingGroup group) { return pair(group.id, group.name); } })), pair("handlers", handlers), pair("worlds", toObjectMapper(TimingHistory.worldMap.entrySet(), new Function<Map.Entry<String, Integer>, JSONPair>() { @Override public JSONPair apply(Map.Entry<String, Integer> input) { return pair(input.getValue(), input.getKey()); } })), pair("tileentity", toObjectMapper(tileEntityTypeSet, new Function<Material, JSONPair>() { @Override public JSONPair apply(Material input) { return pair(input.getId(), input.name()); } })), pair("entity", toObjectMapper(entityTypeSet, new Function<EntityType, JSONPair>() { @Override public JSONPair apply(EntityType input) { return pair(input.getTypeId(), input.name()); } })))); // Information about loaded plugins parent.put("plugins", toObjectMapper(Bukkit.getPluginManager().getPlugins(), new Function<Plugin, JSONPair>() { @Override public JSONPair apply(Plugin plugin) { return pair(plugin.getName(), createObject( pair("version", plugin.getDescription().getVersion()), pair("description", String.valueOf(plugin.getDescription().getDescription()).trim()), pair("website", plugin.getDescription().getWebsite()), pair("authors", StringUtils.join(plugin.getDescription().getAuthors(), ", ")))); } })); // Information on the users Config parent.put("config", createObject(pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)), pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)))); new TimingsExport(sender, parent, history).start(); } static long getCost() { // Benchmark the users System.nanotime() for cost basis int passes = 500000; TimingHandler SAMPLER1 = Timings.ofSafe("Timings Sampler 1"); TimingHandler SAMPLER2 = Timings.ofSafe("Timings Sampler 2"); TimingHandler SAMPLER3 = Timings.ofSafe("Timings Sampler 3"); TimingHandler SAMPLER4 = Timings.ofSafe("Timings Sampler 4"); TimingHandler SAMPLER5 = Timings.ofSafe("Timings Sampler 5"); TimingHandler SAMPLER6 = Timings.ofSafe("Timings Sampler 6"); long start = System.nanoTime(); for (int i = 0; i < passes; i++) { SAMPLER1.startTiming(); SAMPLER2.startTiming(); SAMPLER3.startTiming(); SAMPLER3.stopTiming(); SAMPLER4.startTiming(); SAMPLER5.startTiming(); SAMPLER6.startTiming(); SAMPLER6.stopTiming(); SAMPLER5.stopTiming(); SAMPLER4.stopTiming(); SAMPLER2.stopTiming(); SAMPLER1.stopTiming(); } long timingsCost = (System.nanoTime() - start) / passes / 6; SAMPLER1.reset(true); SAMPLER2.reset(true); SAMPLER3.reset(true); SAMPLER4.reset(true); SAMPLER5.reset(true); SAMPLER6.reset(true); return timingsCost; } private static JSONObject mapAsJSON(ConfigurationSection config, String parentKey) { JSONObject object = new JSONObject(); for (String key : config.getKeys(false)) { String fullKey = (parentKey != null ? parentKey + "." + key : key); if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey)) { continue; } final Object val = config.get(key); object.put(key, valAsJSON(val, fullKey)); } return object; } private static Object valAsJSON(Object val, final String parentKey) { if (!(val instanceof MemorySection)) { if (val instanceof List) { Iterable<Object> v = (Iterable<Object>) val; return toArrayMapper(v, new Function<Object, Object>() { @Override public Object apply(Object input) { return valAsJSON(input, parentKey); } }); } else { return val.toString(); } } else { return mapAsJSON((ConfigurationSection) val, parentKey); } } @SuppressWarnings("CallToThreadRun") @Override public synchronized void start() { if (sender instanceof RemoteConsoleCommandSender) { sender.sendMessage(ChatColor.RED + "Warning: Timings report done over RCON will cause lag spikes."); sender.sendMessage(ChatColor.RED + "You should use " + ChatColor.YELLOW + "/timings report" + ChatColor.RED + " in game or console."); run(); } else { super.start(); } } @Override public void run() { sender.sendMessage(ChatColor.GREEN + "Preparing Timings Report..."); out.put("data", toObjectMapper(history, new Function<TimingHistory, JSONPair>() { @Override public JSONPair apply(TimingHistory input) { return input.export(); } })); String response = null; try { HttpURLConnection con = (HttpURLConnection) new URL("http://timings.aikar.co/post").openConnection(); con.setDoOutput(true); con.setRequestProperty("User-Agent", "Spigot/" + Bukkit.getServerName() + "/" + InetAddress.getLocalHost().getHostName()); con.setRequestMethod("POST"); con.setInstanceFollowRedirects(false); OutputStream request = new GZIPOutputStream(con.getOutputStream()) { { this.def.setLevel(7); } }; request.write(JSONValue.toJSONString(out).getBytes("UTF-8")); request.close(); response = getResponse(con); if (con.getResponseCode() != 302) { sender.sendMessage( ChatColor.RED + "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage()); sender.sendMessage(ChatColor.RED + "Check your logs for more information"); if (response != null) { Bukkit.getLogger().log(Level.SEVERE, response); } return; } String location = con.getHeaderField("Location"); sender.sendMessage(ChatColor.GREEN + "View Timings Report: " + location); if (!(sender instanceof ConsoleCommandSender)) { Bukkit.getLogger().log(Level.INFO, "View Timings Report: " + location); } if (response != null && !response.isEmpty()) { Bukkit.getLogger().log(Level.INFO, "Timing Response: " + response); } } catch (IOException ex) { sender.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information"); if (response != null) { Bukkit.getLogger().log(Level.SEVERE, response); } Bukkit.getLogger().log(Level.SEVERE, "Could not paste timings", ex); } } private String getResponse(HttpURLConnection con) throws IOException { InputStream is = null; try { is = con.getInputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] b = new byte[1024]; int bytesRead; while ((bytesRead = is.read(b)) != -1) { bos.write(b, 0, bytesRead); } return bos.toString(); } catch (IOException ex) { sender.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information"); Bukkit.getLogger().log(Level.WARNING, con.getResponseMessage(), ex); return null; } finally { if (is != null) { is.close(); } } } }