diff --git a/.gitignore b/.gitignore index 3ad3e9e5e..8c1f47591 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ Plan.iml PlanPluginBridge.iml .sonar/ +# Shell files +*.sh + # Created by https://www.gitignore.io/api/maven,eclipse,intellij,netbeans,osx,windows,notepadpp,windows,java ### Maven ### diff --git a/Plan/dependency-reduced-pom.xml b/Plan/dependency-reduced-pom.xml index ffad70814..c9091699d 100644 --- a/Plan/dependency-reduced-pom.xml +++ b/Plan/dependency-reduced-pom.xml @@ -3,22 +3,22 @@ 4.0.0 com.djrapitops Plan - 4.2.0-SNAPSHOT + 4.2.0-SNAPSHOT - ${basedir}/src - ${basedir}/test + ${basedir}/src/main/java + ${basedir}/src/test/java clean package install . ${basedir}/src/main/resources - **/*.keystore - **/*.css - **/*.yml - **/*.html - **/*.js - **/*.css + **/*.keystore + **/*.css + **/*.yml + **/*.html + **/*.js + **/*.css licence.yml @@ -47,7 +47,6 @@ - true org.powermock:* @@ -65,6 +64,10 @@ + + maven-install-plugin + 2.5.2 + maven-jar-plugin 2.6 @@ -104,206 +107,183 @@ bungeecord-repo https://oss.sonatype.org/content/repositories/snapshots - - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - - paper-repo - https://repo.destroystokyo.com/repository/maven-public/ - + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + paper-repo + https://repo.destroystokyo.com/repository/maven-public/ + com.destroystokyo.paper - paper-api - 1.12.2-R0.1-SNAPSHOT - provided - - - authlib - com.mojang - - - commons-lang - commons-lang - - - json-simple - com.googlecode.json-simple - - - jsr305 - com.google.code.findbugs - - - guava - com.google.guava - - - gson - com.google.code.gson - - - snakeyaml - org.yaml - - - bungeecord-chat - net.md-5 - - - slf4j-api - org.slf4j - - - asm-all - org.ow2.asm - - - - - org.spigotmc - spigot-api - 1.12-R0.1-SNAPSHOT + paper-api + 1.12.2-R0.1-SNAPSHOT provided - commons-lang - commons-lang + authlib + com.mojang + + + commons-lang + commons-lang + + + json-simple + com.googlecode.json-simple + + + jsr305 + com.google.code.findbugs + + + guava + com.google.guava + + + gson + com.google.code.gson + + + snakeyaml + org.yaml + + + bungeecord-chat + net.md-5 + + + slf4j-api + org.slf4j + + + asm-all + org.ow2.asm - - json-simple - com.googlecode.json-simple - - - guava - com.google.guava - - - gson - com.google.code.gson - - - snakeyaml - org.yaml - - - bungeecord-chat - net.md-5 - - - org.bukkit - bukkit - 1.12.2-R0.1-SNAPSHOT - provided - - - commons-lang - commons-lang - - - json-simple - com.googlecode.json-simple - - - guava - com.google.guava - - - gson - com.google.code.gson - - - snakeyaml - org.yaml - - - - + + org.spigotmc + spigot-api + 1.12-R0.1-SNAPSHOT + provided + + + commons-lang + commons-lang + + + json-simple + com.googlecode.json-simple + + + guava + com.google.guava + + + gson + com.google.code.gson + + + snakeyaml + org.yaml + + + bungeecord-chat net.md-5 - bungeecord-api - 1.12-SNAPSHOT - provided - - - bungeecord-config - net.md-5 - - - bungeecord-event - net.md-5 - - - bungeecord-protocol - net.md-5 - - - bungeecord-chat - net.md-5 - - - guava - com.google.guava - - - - - org.powermock - powermock - 1.6.6 - pom - compile + + - org.powermock - powermock-api-mockito - 1.6.6 - compile + org.bukkit + bukkit + 1.12.2-R0.1-SNAPSHOT + provided + + + commons-lang + commons-lang + + + json-simple + com.googlecode.json-simple + + + guava + com.google.guava + + + gson + com.google.code.gson + + + snakeyaml + org.yaml + + - org.powermock - powermock-module-junit4 - 1.6.6 - compile - - - org.powermock - powermock-module-junit4-rule - 1.6.6 - compile - - - org.powermock - powermock-classloading-xstream - 1.6.6 - compile + net.md-5 + bungeecord-api + 1.12-SNAPSHOT + provided + + + bungeecord-config + net.md-5 + + + bungeecord-event + net.md-5 + + + bungeecord-protocol + net.md-5 + + + bungeecord-chat + net.md-5 + + + guava + com.google.guava + + org.mockito mockito-core - 1.10.19 - compile + 2.13.0 + test + + + byte-buddy + net.bytebuddy + + + byte-buddy-agent + net.bytebuddy + + + objenesis + org.objenesis + + - org.powermock - powermock-api-easymock - 1.6.6 - compile - - - org.easymock - easymock - 3.4 - compile + org.xerial + sqlite-jdbc + 3.21.0 + test junit junit 4.12 - compile + test org.hamcrest diff --git a/Plan/pom.xml b/Plan/pom.xml index d75ce1638..64275bd3e 100644 --- a/Plan/pom.xml +++ b/Plan/pom.xml @@ -25,15 +25,13 @@ com.djrapitops AbstractPluginFramework - 3.0.1 - compile + 3.1.1 com.djrapitops PlanPluginBridge 4.2.0-SNAPSHOT - compile @@ -69,7 +67,6 @@ org.apache.commons commons-lang3 3.6 - compile @@ -82,69 +79,39 @@ org.apache.commons commons-dbcp2 2.1.1 - compile org.apache.commons commons-pool2 2.4.2 - compile commons-logging commons-logging 1.2 - compile - - - - org.powermock - powermock - 1.6.6 - pom - - - org.powermock - powermock-api-mockito - 1.6.6 - - - org.powermock - powermock-module-junit4 - 1.6.6 - - - org.powermock - powermock-module-junit4-rule - 1.6.6 - - - org.powermock - powermock-classloading-xstream - 1.6.6 + + org.mockito mockito-core - 1.10.19 + 2.13.0 jar + test - + + - org.powermock - powermock-api-easymock - 1.6.6 - jar - - - org.easymock - easymock - 3.4 + org.xerial + sqlite-jdbc + 3.21.0 + test junit junit 4.12 + test org.hamcrest @@ -158,7 +125,7 @@ clean package install ${project.name} ${basedir}/src/main/java - ${basedir}/test/main/java + ${basedir}/src/test/java . @@ -198,7 +165,6 @@ - true org.powermock:* diff --git a/Plan/src/main/java/com/djrapitops/plan/Plan.java b/Plan/src/main/java/com/djrapitops/plan/Plan.java index 108f80c4f..6dbac642f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/Plan.java +++ b/Plan/src/main/java/com/djrapitops/plan/Plan.java @@ -19,94 +19,31 @@ */ package com.djrapitops.plan; -import com.djrapitops.plan.api.API; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.PlanEnableException; import com.djrapitops.plan.command.PlanCommand; -import com.djrapitops.plan.data.plugin.HookHandler; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.settings.theme.PlanColorScheme; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.systems.Systems; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.cache.GeolocationCache; -import com.djrapitops.plan.systems.file.FileSystem; -import com.djrapitops.plan.systems.file.config.ConfigSystem; -import com.djrapitops.plan.systems.file.database.DBSystem; -import com.djrapitops.plan.systems.info.BukkitInformationManager; -import com.djrapitops.plan.systems.info.ImporterManager; -import com.djrapitops.plan.systems.info.InformationManager; -import com.djrapitops.plan.systems.info.server.BukkitServerInfoManager; -import com.djrapitops.plan.systems.listeners.*; -import com.djrapitops.plan.systems.processing.Processor; -import com.djrapitops.plan.systems.processing.importing.importers.OfflinePlayerImporter; -import com.djrapitops.plan.systems.queue.ProcessingQueue; -import com.djrapitops.plan.systems.tasks.TaskSystem; -import com.djrapitops.plan.systems.update.VersionCheckSystem; -import com.djrapitops.plan.systems.webserver.WebServer; -import com.djrapitops.plan.systems.webserver.WebServerSystem; -import com.djrapitops.plan.systems.webserver.pagecache.PageCache; -import com.djrapitops.plan.utilities.file.export.HtmlExport; +import com.djrapitops.plan.system.BukkitSystem; +import com.djrapitops.plan.system.processing.importing.ImporterManager; +import com.djrapitops.plan.system.processing.importing.importers.OfflinePlayerImporter; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plan.system.settings.theme.PlanColorScheme; import com.djrapitops.plan.utilities.metrics.BStats; import com.djrapitops.plugin.BukkitPlugin; import com.djrapitops.plugin.StaticHolder; import com.djrapitops.plugin.api.Benchmark; -import com.djrapitops.plugin.api.TimeAmount; -import com.djrapitops.plugin.api.config.Config; -import com.djrapitops.plugin.api.systems.TaskCenter; import com.djrapitops.plugin.api.utility.log.DebugLog; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.settings.ColorScheme; -import com.djrapitops.plugin.task.AbsRunnable; -import com.djrapitops.plugin.task.RunnableFactory; import org.bukkit.configuration.file.FileConfiguration; -import java.io.IOException; -import java.net.UnknownHostException; -import java.util.List; -import java.util.UUID; - /** * Main class for Bukkit that manages the plugin. - *

- * Everything can be accessed through this class. Use Plan.getInstance() to get - * the initialised instance of Plan. * * @author Rsl1122 * @since 1.0.0 */ -public class Plan extends BukkitPlugin implements IPlan { +public class Plan extends BukkitPlugin implements PlanPlugin { - private API api; - - private Systems systems; - - private ProcessingQueue processingQueue; - private HookHandler hookHandler; // Manages 3rd party data sources - - private BukkitInformationManager infoManager; - private BukkitServerInfoManager serverInfoManager; - - private ServerVariableHolder serverVariableHolder; - - /** - * Used to get the PlanAPI. @see API - * - * @return API of the current instance of Plan. - * @throws IllegalStateException If onEnable method has not been called on - * Plan and the instance is null. - * @throws NoClassDefFoundError If Plan is not installed. - */ - public static API getPlanAPI() throws NoClassDefFoundError { - Plan instance = getInstance(); - if (instance == null) { - throw new IllegalStateException("Plugin not enabled properly, Singleton instance is null."); - } - return instance.getApi(); - } + private BukkitSystem system; /** * Used to get the plugin-instance singleton. @@ -117,14 +54,6 @@ public class Plan extends BukkitPlugin implements IPlan { return (Plan) StaticHolder.getInstance(Plan.class); } - public static UUID getServerUUID() { - return getInstance().getServerUuid(); - } - - public UUID getServerUuid() { - return serverInfoManager.getServerUUID(); - } - /** * OnEnable method. *

@@ -134,77 +63,9 @@ public class Plan extends BukkitPlugin implements IPlan { public void onEnable() { super.onEnable(); try { - systems = new Systems(this); - FileSystem.getInstance().init(); - ConfigSystem.getInstance().init(); - - Log.setDebugMode(Settings.DEBUG.toString()); - - VersionCheckSystem.getInstance().init(); - Benchmark.start("Enable"); - - try { - GeolocationCache.checkDB(); - } catch (UnknownHostException e) { - Log.error("Plan Requires internet access on first run to download GeoLite2 Geolocation database."); - } catch (IOException e) { - throw new PlanEnableException("Something went wrong saving the downloaded GeoLite2 Geolocation database", e); - } - - new Locale().loadLocale(); - - Theme.getInstance().init(); - - Benchmark.start("Reading server variables"); - serverVariableHolder = new ServerVariableHolder(getServer()); - Benchmark.stop("Enable", "Reading server variables"); - - DBSystem.getInstance().init(); - - Benchmark.start("WebServer Initialization"); - processingQueue = new ProcessingQueue(); - - serverInfoManager = new BukkitServerInfoManager(this); - infoManager = new BukkitInformationManager(this); - WebServerSystem.getInstance().init(); - if (!WebServerSystem.isWebServerEnabled()) { - if (Settings.WEBSERVER_DISABLED.isTrue()) { - Log.warn("WebServer was not initialized. (WebServer.DisableWebServer: true)"); - } else { - Log.error("WebServer was not initialized successfully. Is the port (" + Settings.WEBSERVER_PORT.getNumber() + ") in use?"); - - } - } - serverInfoManager.updateServerInfo(); - infoManager.updateConnection(); - - Benchmark.stop("Enable", "WebServer Initialization"); - - if (!reloading) { - registerListeners(); - } - PlanPlayerListener.setCountKicks(true); - - TaskSystem.getInstance().init(); - - this.api = new API(this); - - boolean usingBungeeWebServer = infoManager.isUsingAnotherWebServer(); - boolean usingAlternativeIP = Settings.SHOW_ALTERNATIVE_IP.isTrue(); - - if (!usingAlternativeIP && serverVariableHolder.getIp().isEmpty()) { - Log.infoColor(Locale.get(Msg.ENABLE_NOTIFY_EMPTY_IP).toString()); - } - if (usingBungeeWebServer && usingAlternativeIP) { - Log.info("Make sure that the alternative IP points to the Bukkit Server: " + Settings.ALTERNATIVE_IP.toString()); - } - - registerCommand("plan", new PlanCommand(this)); - - Benchmark.start("Hook to 3rd party plugins"); - hookHandler = new HookHandler(this); - Benchmark.stop("Enable", "Hook to 3rd party plugins"); + system = new BukkitSystem(this); + system.enable(); ImporterManager.registerImporter(new OfflinePlayerImporter()); @@ -215,16 +76,12 @@ public class Plan extends BukkitPlugin implements IPlan { Benchmark.stop("Enable", "Enable"); Log.logDebug("Enable"); Log.info(Locale.get(Msg.ENABLED).toString()); - StaticHolder.saveInstance(ShutdownHook.class, this.getClass()); - new ShutdownHook(this); - if (Settings.ANALYSIS_EXPORT.isTrue()) { - RunnableFactory.createNew(new HtmlExport(this)).runTaskAsynchronously(); - } } catch (Exception e) { - Log.error("Plugin Failed to Initialize Correctly."); - Log.toLog(this.getClass().getName(), e); + Log.error("Plugin Failed to Initialize Correctly. If this issue is caused by config settings you can use /plan reload"); + Log.toLog(this.getClass(), e); onDisable(); } + registerCommand("plan", new PlanCommand(this)); } @Override @@ -237,34 +94,11 @@ public class Plan extends BukkitPlugin implements IPlan { */ @Override public void onDisable() { - //Clears the page cache - PageCache.clearCache(); - - // Processes unprocessed processors - if (processingQueue != null) { - List processors = processingQueue.stopAndReturnLeftovers(); - if (!reloading) { - Log.info("Processing unprocessed processors. (" + processors.size() + ")"); // TODO Move to Locale - for (Processor processor : processors) { - processor.process(); - } - } else { - RunnableFactory.createNew("Re-Add processors", new AbsRunnable() { - @Override - public void run() { - addToProcessQueue(processors.toArray(new Processor[processors.size()])); - cancel(); - } - }).runTaskLaterAsynchronously(TimeAmount.SECOND.ticks() * 5L); - } - } - - systems.close(); + system.disable(); Log.info(Locale.get(Msg.DISABLED).toString()); Benchmark.pluginDisabled(Plan.class); DebugLog.pluginDisabled(Plan.class); - TaskCenter.cancelAllKnownTasks(Plan.class); } @Override @@ -274,110 +108,10 @@ public class Plan extends BukkitPlugin implements IPlan { @Override public void onReload() { - ConfigSystem.reload(); - } - private void registerListeners() { - Benchmark.start("Register Listeners"); - registerListener(new PlanPlayerListener(this)); - registerListener(new PlanChatListener(this)); - registerListener(new PlanGamemodeChangeListener(this)); - registerListener(new PlanWorldChangeListener(this)); - registerListener(new PlanCommandPreprocessListener(this)); - registerListener(new PlanDeathEventListener(this)); - Benchmark.stop("Enable", "Register Listeners"); - } - - /** - * Used to access Cache. - * - * @return Current instance of the DataCache - */ - public DataCache getDataCache() { - return getInfoManager().getDataCache(); - } - - /** - * Used to access active Database. - * - * @return the Current Database - */ - @Deprecated - public Database getDB() { - return DBSystem.getInstance().getActiveDatabase(); - } - - /** - * Used to access WebServer. - * - * @return the WebServer - */ - public WebServer getWebServer() { - return WebServerSystem.getInstance().getWebServer(); - } - - /** - * Used to access HookHandler. - * - * @return HookHandler that manages Hooks to other plugins. - */ - public HookHandler getHookHandler() { - return hookHandler; - } - - /** - * Used to get the object storing server variables that are constant after - * boot. - * - * @return ServerVariableHolder - * @see ServerVariableHolder - */ - public ServerVariableHolder getVariable() { - return serverVariableHolder; - } - - /** - * Used to get the object storing server info - * - * @return BukkitServerInfoManager - * @see BukkitServerInfoManager - */ - public BukkitServerInfoManager getServerInfoManager() { - return serverInfoManager; - } - - public ProcessingQueue getProcessingQueue() { - return processingQueue; - } - - public void addToProcessQueue(Processor... processors) { - if (!reloading) { - for (Processor processor : processors) { - if (processor == null) { - continue; - } - processingQueue.addToQueue(processor); - } - } else { - RunnableFactory.createNew("Re-Add processors", new AbsRunnable() { - @Override - public void run() { - addToProcessQueue(processors); - cancel(); - } - }).runTaskLaterAsynchronously(TimeAmount.SECOND.ticks() * 5L); - } } @Override - public Config getMainConfig() { - return ConfigSystem.getInstance().getConfig(); - } - - public InformationManager getInfoManager() { - return infoManager; - } - public boolean isReloading() { return reloading; } @@ -418,21 +152,7 @@ public class Plan extends BukkitPlugin implements IPlan { throw new IllegalStateException("This method should be used on this plugin."); } - /** - * Method for getting the API. - *

- * Created due to necessity for testing, but can be used. - * For direct API getter use {@code Plan.getPlanAPI()}. - *

- * If Plan is reloaded a new API instance is created. - * - * @return Plan API instance. - */ - public API getApi() { - return api; - } - - public Systems getSystems() { - return systems; + public BukkitSystem getSystem() { + return system; } } diff --git a/Plan/src/main/java/com/djrapitops/plan/PlanBungee.java b/Plan/src/main/java/com/djrapitops/plan/PlanBungee.java index af170eb8b..5cb9a593e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/PlanBungee.java +++ b/Plan/src/main/java/com/djrapitops/plan/PlanBungee.java @@ -4,129 +4,55 @@ */ package com.djrapitops.plan; -import com.djrapitops.plan.api.IPlan; import com.djrapitops.plan.command.PlanBungeeCommand; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.settings.theme.PlanColorScheme; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.systems.Systems; -import com.djrapitops.plan.systems.file.FileSystem; -import com.djrapitops.plan.systems.file.config.ConfigSystem; -import com.djrapitops.plan.systems.file.database.DBSystem; -import com.djrapitops.plan.systems.info.BungeeInformationManager; -import com.djrapitops.plan.systems.info.InformationManager; -import com.djrapitops.plan.systems.info.server.BungeeServerInfoManager; -import com.djrapitops.plan.systems.listeners.BungeePlayerListener; -import com.djrapitops.plan.systems.processing.Processor; -import com.djrapitops.plan.systems.queue.ProcessingQueue; -import com.djrapitops.plan.systems.tasks.TaskSystem; -import com.djrapitops.plan.systems.update.VersionCheckSystem; -import com.djrapitops.plan.systems.webserver.WebServer; -import com.djrapitops.plan.systems.webserver.WebServerSystem; -import com.djrapitops.plan.utilities.file.export.HtmlExport; +import com.djrapitops.plan.system.BungeeSystem; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plan.system.settings.theme.PlanColorScheme; import com.djrapitops.plugin.BungeePlugin; import com.djrapitops.plugin.StaticHolder; import com.djrapitops.plugin.api.Benchmark; -import com.djrapitops.plugin.api.config.Config; -import com.djrapitops.plugin.api.systems.TaskCenter; import com.djrapitops.plugin.api.utility.log.DebugLog; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.settings.ColorScheme; -import com.djrapitops.plugin.task.RunnableFactory; import java.io.InputStream; -import java.util.UUID; /** * Bungee Main class. * * @author Rsl1122 */ -public class PlanBungee extends BungeePlugin implements IPlan { +public class PlanBungee extends BungeePlugin implements PlanPlugin { - private Systems systems; - - private BungeeServerInfoManager serverInfoManager; - private BungeeInformationManager infoManager; - private com.djrapitops.plan.ServerVariableHolder variableHolder; - - private ProcessingQueue processingQueue; - - private boolean setupAllowed = false; - - @Override - public void onEnable() { - super.onEnable(); - try { - systems = new Systems(this); - FileSystem.getInstance().init(); - ConfigSystem.getInstance().init(); - - Log.setDebugMode(Settings.DEBUG.toString()); - - VersionCheckSystem.getInstance().init(); - - variableHolder = new com.djrapitops.plan.ServerVariableHolder(getProxy()); - - new Locale().loadLocale(); - - Theme.getInstance().init(); - DBSystem.getInstance().init(); - - String ip = variableHolder.getIp(); - if ("0.0.0.0".equals(ip)) { - Log.error("IP setting still 0.0.0.0 - Configure AlternativeIP/IP that connects to the Proxy server."); - Log.info("Player Analytics partially enabled (Use /planbungee to reload config)"); - return; - } - - Benchmark.start("WebServer Initialization"); - - serverInfoManager = new BungeeServerInfoManager(this); - infoManager = new BungeeInformationManager(this); - - WebServerSystem.getInstance().init(); - serverInfoManager.loadServerInfo(); - - TaskSystem.getInstance().init(); - - processingQueue = new ProcessingQueue(); - - registerListener(new BungeePlayerListener(this)); - - Log.logDebug("Enable", "WebServer Initialization"); - Log.info(Locale.get(Msg.ENABLED).toString()); - if (Settings.ANALYSIS_EXPORT.isTrue()) { - RunnableFactory.createNew(new HtmlExport(this)).runTaskAsynchronously(); - } - } catch (Exception e) { - Log.error("Plugin Failed to Initialize Correctly."); - Log.toLog(this.getClass().getName(), e); - } - registerCommand("planbungee", new PlanBungeeCommand(this)); - } + private BungeeSystem system; public static PlanBungee getInstance() { return (PlanBungee) StaticHolder.getInstance(PlanBungee.class); } @Override - public void onDisable() { - if (processingQueue != null) { - try { - processingQueue.stop(); - } catch (IllegalArgumentException ignored) { - /*ignored*/ - } + public void onEnable() { + super.onEnable(); + try { + system = new BungeeSystem(this); + system.enable(); + + Log.info(Locale.get(Msg.ENABLED).toString()); + } catch (Exception e) { + Log.error("Plugin Failed to Initialize Correctly:"); + Log.toLog(this.getClass(), e); } - systems.close(); + registerCommand("planbungee", new PlanBungeeCommand(this)); + } + + @Override + public void onDisable() { + system.disable(); + Log.info(Locale.get(Msg.DISABLED).toString()); Benchmark.pluginDisabled(PlanBungee.class); DebugLog.pluginDisabled(PlanBungee.class); - TaskCenter.cancelAllKnownTasks(PlanBungee.class); } @Override @@ -136,40 +62,6 @@ public class PlanBungee extends BungeePlugin implements IPlan { @Override public void onReload() { - ConfigSystem.reload(); - } - - @Override - @Deprecated - public Database getDB() { - return DBSystem.getInstance().getActiveDatabase(); - } - - public BungeeServerInfoManager getServerInfoManager() { - return serverInfoManager; - } - - @Override - public InformationManager getInfoManager() { - return infoManager; - } - - @Override - public WebServer getWebServer() { - return WebServerSystem.getInstance().getWebServer(); - } - - - @Override - public ProcessingQueue getProcessingQueue() { - return processingQueue; - } - - @Override - public void addToProcessQueue(Processor... processors) { - for (Processor processor : processors) { - processingQueue.addToQueue(processor); - } } @Override @@ -177,39 +69,17 @@ public class PlanBungee extends BungeePlugin implements IPlan { return getResourceAsStream(resource); } - @Override - public Config getMainConfig() { - return ConfigSystem.getInstance().getConfig(); - } - @Override public ColorScheme getColorScheme() { return PlanColorScheme.create(); } - @Override - public com.djrapitops.plan.ServerVariableHolder getVariable() { - return variableHolder; - } - - public static UUID getServerUUID() { - return getInstance().getServerUuid(); - } - - public UUID getServerUuid() { - return serverInfoManager.getServerUUID(); + public BungeeSystem getSystem() { + return system; } @Override - public Systems getSystems() { - return systems; - } - - public boolean isSetupAllowed() { - return setupAllowed; - } - - public void setSetupAllowed(boolean setupAllowed) { - this.setupAllowed = setupAllowed; + public boolean isReloading() { + return reloading; } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/PlanPlugin.java b/Plan/src/main/java/com/djrapitops/plan/PlanPlugin.java new file mode 100644 index 000000000..428930c45 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/PlanPlugin.java @@ -0,0 +1,53 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan; + +import com.djrapitops.plugin.IPlugin; +import com.djrapitops.plugin.api.Check; +import com.djrapitops.plugin.settings.ColorScheme; + +import java.io.File; +import java.io.InputStream; + +/** + * Abstraction interface for both Plan and PlanBungee. + * + * @author Rsl1122 + */ +public interface PlanPlugin extends IPlugin { + static PlanPlugin getInstance() { + boolean bukkitAvailable = Check.isBukkitAvailable(); + boolean bungeeAvailable = Check.isBungeeAvailable(); + if (bukkitAvailable) { + try { + Plan instance = Plan.getInstance(); + if (instance != null) { + return instance; + } + } catch (IllegalStateException ignored) { + } + } + if (bungeeAvailable) { + try { + PlanBungee instance = PlanBungee.getInstance(); + if (instance != null) { + return instance; + } + } catch (IllegalStateException ignored) { + } + } + throw new IllegalAccessError("Plugin instance not available"); + } + + @Override + File getDataFolder(); + + InputStream getResource(String resource); + + ColorScheme getColorScheme(); + + @Override + boolean isReloading(); +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/ShutdownHook.java b/Plan/src/main/java/com/djrapitops/plan/ShutdownHook.java index f8757d6b1..6aeceddc0 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ShutdownHook.java +++ b/Plan/src/main/java/com/djrapitops/plan/ShutdownHook.java @@ -1,22 +1,22 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan; -import com.djrapitops.plan.api.exceptions.DatabaseInitException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.data.Actions; import com.djrapitops.plan.data.container.Action; import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.tables.Actions; -import com.djrapitops.plan.database.tables.SessionsTable; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.cache.SessionCache; +import com.djrapitops.plan.system.cache.CacheSystem; +import com.djrapitops.plan.system.cache.DataCache; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.databases.Database; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.StaticHolder; import com.djrapitops.plugin.api.utility.log.Log; -import java.sql.SQLException; import java.util.Map; import java.util.UUID; @@ -29,78 +29,81 @@ import java.util.UUID; */ public class ShutdownHook extends Thread { - private static boolean active = false; - private static DataCache dataCache; - private static SQLDB db; + private static boolean activated = false; - public ShutdownHook(Plan plugin) { - if (!active) { - Runtime.getRuntime().addShutdownHook(this); + private static boolean isActivated() { + return activated; + } + + private static void activate(ShutdownHook hook) { + activated = true; + Runtime.getRuntime().addShutdownHook(hook); + } + + public void register() { + if (isActivated()) { + return; } - active = true; - - db = (SQLDB) plugin.getDB(); - dataCache = plugin.getDataCache(); + activate(this); } @Override public void run() { Log.debug("Shutdown hook triggered."); + + Database db = null; try { Map activeSessions = SessionCache.getActiveSessions(); long now = MiscUtils.getTime(); - if (db == null) { - return; - } + db = Database.getActive(); if (!db.isOpen()) { db.init(); } - saveFirstSessionInformation(now); - saveActiveSessions(activeSessions, now); - } catch (DatabaseInitException e) { - Log.toLog(this.getClass().getName(), e); + saveFirstSessionInformation(db, now); + saveActiveSessions(db, activeSessions, now); + } catch (IllegalStateException ignored) { + /* Database is not initialized */ + } catch (DBInitException e) { + Log.toLog(this.getClass(), e); } finally { if (db != null) { try { db.close(); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } - db = null; - dataCache = null; StaticHolder.unRegister(Plan.class); } } - private void saveFirstSessionInformation(long now) { + private void saveFirstSessionInformation(Database db, long now) { + DataCache dataCache = CacheSystem.getInstance().getDataCache(); for (Map.Entry entry : dataCache.getFirstSessionMsgCounts().entrySet()) { try { UUID uuid = entry.getKey(); int messagesSent = entry.getValue(); - db.getActionsTable().insertAction(uuid, new Action(now, Actions.FIRST_LOGOUT, "Messages sent: " + messagesSent)); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + db.save().action(uuid, new Action(now, Actions.FIRST_LOGOUT, "Messages sent: " + messagesSent)); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } } - private void saveActiveSessions(Map activeSessions, long now) { - SessionsTable sessionsTable = db.getSessionsTable(); + private void saveActiveSessions(Database db, Map activeSessions, long now) { for (Map.Entry entry : activeSessions.entrySet()) { UUID uuid = entry.getKey(); Session session = entry.getValue(); long sessionEnd = session.getSessionEnd(); - if (sessionEnd != -1) { - continue; + if (sessionEnd == -1) { + session.endSession(now); } - session.endSession(now); try { Log.debug("Shutdown: Saving a session: " + session.getSessionStart()); - sessionsTable.saveSession(uuid, session); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + db.save().session(uuid, session); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } activeSessions.clear(); diff --git a/Plan/src/main/java/com/djrapitops/plan/api/API.java b/Plan/src/main/java/com/djrapitops/plan/api/API.java deleted file mode 100644 index 306f29e0a..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/api/API.java +++ /dev/null @@ -1,254 +0,0 @@ -package com.djrapitops.plan.api; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.ParseException; -import com.djrapitops.plan.data.AnalysisData; -import com.djrapitops.plan.data.plugin.PluginData; -import com.djrapitops.plan.systems.info.BukkitInformationManager; -import com.djrapitops.plan.utilities.uuid.UUIDUtility; -import com.djrapitops.plugin.utilities.Verify; -import org.bukkit.OfflinePlayer; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.UUID; - -import static org.bukkit.Bukkit.getOfflinePlayer; - -/** - * This class contains the API methods for Bukkit version of the plugin. - *

- * Methods can be called from Asynchronous task and are thread safe unless - * otherwise stated. - *

- * Use Plan.getPlanAPI() to get the API. - *

- * More information about API methods can be found on GitHub. - * - * @author Rsl1122 - * @see PluginData - * @see AnalysisType - * @since 4.0.0 - */ -public class API { - - private final Plan plugin; - - /** - * Creates a new API instance - not supposed to be called outside {@code Plan.onEnable}. - * - * @param plugin Current instance of Plan - */ - public API(Plan plugin) { - this.plugin = plugin; - } - - /** - * Condition whether or not the plugin enabled successfully. - * - * @return true if plugin is enabled correctly. - */ - public boolean isEnabled() { - return plugin.isEnabled(); - } - - /** - * Add a source of plugin data to the Plugins tab on Analysis and/or Inspect - * page. - *

- * Refer to documentation on GitHub or Javadoc of PluginData to set-up a - * data source that extends PluginData correctly. - * - * @param dataSource an object that extends PluginData-object, thus allowing - * Analysis and Inspect to manage the data of a plugin correctly. - * @see PluginData - */ - public void addPluginDataSource(PluginData dataSource) { - if (isEnabled()) { - plugin.getHookHandler().addPluginDataSource(dataSource); - } - } - - /** - * Used to get a relative link to InspectPage of a player. - *

- * This method is useful if you have a table and want to link to the inspect - * page. - *

- * Html.LINK.parse("Link", "PlayerName") can be used to get a link - * {@code PlayerName} - * - * @param name Name of the player - * @return {@code ../player/PlayerName} - */ - public String getPlayerInspectPageLink(String name) { - if (name == null) { - return "#"; - } - return "../player/" + name.replace(" ", "%20").replace(".", "%2E"); - } - - /** - * Condition if Players's Inspect page is cached to PageCache. - * - * @param uuid UUID of the player. - * @return true/false - * @deprecated use {@code isPlayerHtmlCached} - */ - @Deprecated - public boolean isPlayersDataInspectCached(UUID uuid) { - return isPlayerHtmlCached(uuid); - } - - /** - * Condition if Players's Inspect page is cached to PageCache of the providing WebServer. - *

- * Using BungeeCord: Will send a {@code IsCachedWebAPI} request to check if the page is in Bungee's PageCache. - * Only Bukkit: Checks PageCache for page. - * - * @param uuid UUID of the player. - * @return true/false - */ - public boolean isPlayerHtmlCached(UUID uuid) { - return plugin.getInfoManager().isCached(uuid); - } - - /** - * Cache Players's Inspect page to the PageCache of the providing WebServer. - * - * @param uuid UUID of the player. - * @deprecated use {@code cachePlayerHtml} - */ - @Deprecated - public void cacheUserDataToInspectCache(UUID uuid) { - cachePlayerHtml(uuid); - } - - /** - * Cache Players's Inspect page to the PageCache of the providing WebServer. - *

- * Using BungeeCord: Will send a {@code PostHtmlWebAPI} request after calculating the inspect page. - * Only Bukkit: Calculates inspect page and places it in the PageCache. - * - * @param uuid UUID of the player. - * @deprecated use {@code cachePlayerHtml} - */ - public void cachePlayerHtml(UUID uuid) { - plugin.getInfoManager().cachePlayer(uuid); - } - - /** - * Used to get the full Html of the Inspect page as a string. - *

- * Re-calculates the inspect html on this server. - * - * @param uuid UUID of the player. - * @return player.html with all placeholders replaced. - */ - public String getPlayerHtmlAsString(UUID uuid) throws ParseException { - return plugin.getInfoManager().getPlayerHtml(uuid); - } - - /** - * Condition if the Analysis has been run and is cached to the AnalysisCache. - * - * @return true/false - */ - public boolean isAnalysisCached() { - return plugin.getInfoManager().isAnalysisCached(Plan.getServerUUID()); - } - - /** - * Run the analysis. - */ - public void updateAnalysisCache() { - plugin.getInfoManager().refreshAnalysis(plugin.getServerUuid()); - } - - /** - * Used to get the full HTML of the Analysis page as a string. - *

- * Condition if the data is cached to AnalysisCache before calling this. - * - * @return server.html with all placeholders replaced. - * @throws NullPointerException if AnalysisData has not been cached. - */ - public String getAnalysisHtmlAsString() { - return plugin.getInfoManager().getAnalysisHtml(); - } - - /** - * Used to get the AnalysisData object. - *

- * Condition if the data is cached to AnalysisCache before calling this. - * - * @return AnalysisData object. - * @see AnalysisData - */ - public AnalysisData getAnalysisDataFromCache() { - return ((BukkitInformationManager) plugin.getInfoManager()).getAnalysisData(); - } - - /** - * Used to get the PlayerName of a player who has played on the server. - * Should be called from an Async thread. - * - * @param uuid UUID of the player. - * @return PlayerName, eg "Rsl1122" - * @throws IllegalArgumentException If uuid is null. - * @throws IllegalStateException If the player has not played on the server before. - */ - public String getPlayerName(UUID uuid) throws SQLException { - Verify.nullCheck(uuid); - String playerName = plugin.getDB().getUsersTable().getPlayerName(uuid); - if (playerName != null) { - return playerName; - } - OfflinePlayer offlinePlayer = getOfflinePlayer(uuid); - if (offlinePlayer != null) { - return offlinePlayer.getName(); - } - throw new IllegalStateException("Player has not played on this server before."); - } - - /** - * Uses UUIDUtility to turn PlayerName to UUID. - * - * @param playerName Player's name - * @return UUID of the Player - * @throws Exception if player's name is not registered at Mojang - * @deprecated Typo in method name, use playerNameToUUID instead - */ - @Deprecated - public UUID PlayerNameToUUID(String playerName) { - return playerNameToUUID(playerName); - } - - /** - * Uses UUIDUtility to turn PlayerName to UUID. - * - * @param playerName Player's name - * @return UUID of the Player - * @throws IllegalArgumentException if player's name is not registered at Mojang - */ - public UUID playerNameToUUID(String playerName) { - UUID uuid = UUIDUtility.getUUIDOf(playerName); - if (uuid == null) { - throw new IllegalArgumentException("UUID did not get a match"); - } - return uuid; - } - - /** - * Get the saved UUIDs in the database. - *

- * Should be called from async thread. - * - * @return Collection of UUIDs that can be found in the database. - * @throws SQLException If database error occurs. - * @since 3.4.2 - */ - public Collection getSavedUUIDs() throws SQLException { - return plugin.getDB().getSavedUUIDs(); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/api/BukkitAPI.java b/Plan/src/main/java/com/djrapitops/plan/api/BukkitAPI.java new file mode 100644 index 000000000..eb90022fa --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/BukkitAPI.java @@ -0,0 +1,40 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api; + +import com.djrapitops.plan.data.plugin.PluginData; +import com.djrapitops.plan.system.BukkitSystem; +import com.djrapitops.plan.system.database.databases.operation.FetchOperations; + +import java.util.UUID; + +/** + * PlanAPI extension for Bukkit + * + * @author Rsl1122 + */ +public class BukkitAPI extends CommonAPI { + + private final BukkitSystem bukkitSystem; + + public BukkitAPI(BukkitSystem bukkitSystem) { + this.bukkitSystem = bukkitSystem; + } + + @Override + public void addPluginDataSource(PluginData pluginData) { + bukkitSystem.getHookHandler().addPluginDataSource(pluginData); + } + + @Override + public String getPlayerName(UUID uuid) { + return bukkitSystem.getCacheSystem().getDataCache().getName(uuid); + } + + @Override + public FetchOperations fetchFromPlanDB() { + return bukkitSystem.getDatabaseSystem().getActiveDatabase().fetch(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/BungeeAPI.java b/Plan/src/main/java/com/djrapitops/plan/api/BungeeAPI.java new file mode 100644 index 000000000..3e3c53757 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/BungeeAPI.java @@ -0,0 +1,40 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api; + +import com.djrapitops.plan.data.plugin.PluginData; +import com.djrapitops.plan.system.BungeeSystem; +import com.djrapitops.plan.system.database.databases.operation.FetchOperations; + +import java.util.UUID; + +/** + * PlanAPI extension for Bungee. + * + * @author Rsl1122 + */ +public class BungeeAPI extends CommonAPI { + + private final BungeeSystem bungeeSystem; + + public BungeeAPI(BungeeSystem bungeeSystem) { + this.bungeeSystem = bungeeSystem; + } + + @Override + public void addPluginDataSource(PluginData pluginData) { + bungeeSystem.getHookHandler().addPluginDataSource(pluginData); + } + + @Override + public String getPlayerName(UUID uuid) { + return bungeeSystem.getCacheSystem().getDataCache().getName(uuid); + } + + @Override + public FetchOperations fetchFromPlanDB() { + return bungeeSystem.getDatabaseSystem().getActiveDatabase().fetch(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/CommonAPI.java b/Plan/src/main/java/com/djrapitops/plan/api/CommonAPI.java new file mode 100644 index 000000000..0d1d12826 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/CommonAPI.java @@ -0,0 +1,47 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.utilities.uuid.UUIDUtility; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * PlanAPI extension for all implementations. + * + * @author Rsl1122 + */ +public abstract class CommonAPI implements PlanAPI { + + @Override + public String getPlayerInspectPageLink(UUID uuid) { + return getPlayerInspectPageLink(getPlayerName(uuid)); + } + + @Override + public String getPlayerInspectPageLink(String playerName) { + return "../player/" + playerName; + } + + @Override + public UUID playerNameToUUID(String playerName) { + return UUIDUtility.getUUIDOf(playerName); + } + + @Override + public Map getKnownPlayerNames() { + try { + return fetchFromPlanDB().getPlayerNames(); + } catch (DBException e) { + Log.toLog(this.getClass(), e); + return new HashMap<>(); + } + } + +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/IPlan.java b/Plan/src/main/java/com/djrapitops/plan/api/IPlan.java deleted file mode 100644 index 53c27e9b0..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/api/IPlan.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.api; - -import com.djrapitops.plan.ServerVariableHolder; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.systems.Systems; -import com.djrapitops.plan.systems.info.InformationManager; -import com.djrapitops.plan.systems.processing.Processor; -import com.djrapitops.plan.systems.queue.ProcessingQueue; -import com.djrapitops.plan.systems.webserver.WebServer; -import com.djrapitops.plugin.IPlugin; -import com.djrapitops.plugin.api.config.Config; -import com.djrapitops.plugin.settings.ColorScheme; - -import java.io.File; -import java.io.InputStream; -import java.util.UUID; - -/** - * Abstraction interface for both Plan and PlanBungee. - * - * @author Rsl1122 - */ -public interface IPlan extends IPlugin { - Database getDB(); - - ServerVariableHolder getVariable(); - - UUID getServerUuid(); - - InformationManager getInfoManager(); - - WebServer getWebServer(); - - File getDataFolder(); - - ProcessingQueue getProcessingQueue(); - - void addToProcessQueue(Processor... processors); - - InputStream getResource(String resource); - - Config getMainConfig(); - - ColorScheme getColorScheme(); - - Systems getSystems(); -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/PlanAPI.java b/Plan/src/main/java/com/djrapitops/plan/api/PlanAPI.java new file mode 100644 index 000000000..9793049cd --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/PlanAPI.java @@ -0,0 +1,38 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api; + +import com.djrapitops.plan.data.plugin.PluginData; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.database.databases.operation.FetchOperations; + +import java.util.Map; +import java.util.UUID; + +/** + * Interface for PlanAPI methods. + * + * @author Rsl1122 + */ +public interface PlanAPI { + + static PlanAPI getInstance() { + return PlanSystem.getInstance().getPlanAPI(); + } + + void addPluginDataSource(PluginData pluginData); + + String getPlayerInspectPageLink(UUID uuid); + + String getPlayerInspectPageLink(String playerName); + + String getPlayerName(UUID uuid); + + UUID playerNameToUUID(String playerName); + + Map getKnownPlayerNames(); + + FetchOperations fetchFromPlanDB(); +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/DBCreateTableException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/DBCreateTableException.java deleted file mode 100644 index a107022f8..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/DBCreateTableException.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.api.exceptions; - -/** - * Thrown when something goes wrong with creating tables with {@code Table#createTable}. - * - * @author Rsl1122 - */ -public class DBCreateTableException extends DatabaseInitException { - - public DBCreateTableException(String tableName, String message, Throwable cause) { - super(tableName + ": " + message, cause); - } - - public DBCreateTableException(Throwable cause) { - super(cause); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/PlanEnableException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/EnableException.java similarity index 68% rename from Plan/src/main/java/com/djrapitops/plan/api/exceptions/PlanEnableException.java rename to Plan/src/main/java/com/djrapitops/plan/api/exceptions/EnableException.java index 46888e8ff..4646f49ad 100644 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/PlanEnableException.java +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/EnableException.java @@ -1,4 +1,4 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ @@ -9,13 +9,13 @@ package com.djrapitops.plan.api.exceptions; * * @author Rsl1122 */ -public class PlanEnableException extends Exception { +public class EnableException extends Exception { - public PlanEnableException(String message, Throwable cause) { + public EnableException(String message, Throwable cause) { super(message, cause); } - public PlanEnableException(String message) { + public EnableException(String message) { super(message); } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/ParseException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/ParseException.java index c72bdd4b6..b9cdd4270 100644 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/ParseException.java +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/ParseException.java @@ -1,11 +1,11 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan.api.exceptions; /** - * Exception thrown when PageParser encounters an Exception. + * Exception thrown when Page encounters an Exception. * * @author Rsl1122 */ diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/PassEncryptException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/PassEncryptException.java new file mode 100644 index 000000000..496248027 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/PassEncryptException.java @@ -0,0 +1,13 @@ +package com.djrapitops.plan.api.exceptions; + +public class PassEncryptException extends Exception { + + public PassEncryptException(String s) { + super(s); + } + + public PassEncryptException(String s, Throwable throwable) { + super(s, throwable); + } + +} diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIConnectionFailException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIConnectionFailException.java deleted file mode 100644 index 9acef6241..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIConnectionFailException.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.api.exceptions; - -/** - * Thrown when WebAPI fails to connect to an address. - * - * @author Rsl1122 - */ -public class WebAPIConnectionFailException extends WebAPIException { - - public WebAPIConnectionFailException(String message, Throwable cause) { - super(message, cause); - } - - public WebAPIConnectionFailException(Throwable cause) { - super(cause); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIException.java deleted file mode 100644 index 6cbf73b4a..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.api.exceptions; - -/** - * Thrown when WebAPI POST-request fails, general Exception. - * - * @author Rsl1122 - */ -public class WebAPIException extends Exception { - - public WebAPIException() { - } - - public WebAPIException(String message) { - super(message); - } - - public WebAPIException(String message, Throwable cause) { - super(message, cause); - } - - public WebAPIException(Throwable cause) { - super(cause); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIFailException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIFailException.java deleted file mode 100644 index 354db876b..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIFailException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.api.exceptions; - -/** - * Group of WebAPIExceptions that can be considered a failed connection state on some occasions. - * - * @author Rsl1122 - */ -public class WebAPIFailException extends WebAPIException { - - public WebAPIFailException() { - } - - public WebAPIFailException(String message) { - super(message); - } - - public WebAPIFailException(String message, Throwable cause) { - super(message, cause); - } - - public WebAPIFailException(Throwable cause) { - super(cause); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIInternalErrorException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIInternalErrorException.java deleted file mode 100644 index 1c44dc6c9..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIInternalErrorException.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.api.exceptions; - -/** - * Thrown when WebAPI returns 404, usually when response is supposed to be false. - * - * @author Rsl1122 - */ -public class WebAPIInternalErrorException extends WebAPIFailException { - public WebAPIInternalErrorException() { - super("Internal Error occurred on receiving server"); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPINotFoundException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPINotFoundException.java deleted file mode 100644 index e2eb5c632..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPINotFoundException.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.api.exceptions; - -/** - * Thrown when WebAPI returns 404, usually when response is supposed to be false. - * - * @author Rsl1122 - */ -public class WebAPINotFoundException extends WebAPIFailException { - public WebAPINotFoundException() { - super("Not Found"); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebUserAuthException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebUserAuthException.java index 892bc4681..06fbd90a4 100644 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebUserAuthException.java +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebUserAuthException.java @@ -1,27 +1,37 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan.api.exceptions; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.webserver.auth.FailReason; + /** * Thrown when WebUser can not be authorized (WebServer). * * @author Rsl1122 */ -public class WebUserAuthException extends Exception { - public WebUserAuthException() { +public class WebUserAuthException extends WebException { + + private final FailReason failReason; + + public WebUserAuthException(FailReason failReason) { + super(failReason.getReason()); + this.failReason = failReason; } - public WebUserAuthException(String message) { - super(message); - } - - public WebUserAuthException(String message, Throwable cause) { - super(message, cause); + public WebUserAuthException(FailReason failReason, String additionalInfo) { + super(failReason.getReason() + ": " + additionalInfo); + this.failReason = failReason; } public WebUserAuthException(Throwable cause) { - super(cause); + super(FailReason.ERROR.getReason(), cause); + this.failReason = FailReason.ERROR; + } + + public FailReason getFailReason() { + return failReason; } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/BadRequestException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/BadRequestException.java new file mode 100644 index 000000000..858734d0d --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/BadRequestException.java @@ -0,0 +1,17 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api.exceptions.connection; + +/** + * Thrown when connection is returned 401 Bad Request. + * + * @author Rsl1122 + */ +public class BadRequestException extends WebException { + + public BadRequestException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/ConnectionFailException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/ConnectionFailException.java new file mode 100644 index 000000000..575fb3080 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/ConnectionFailException.java @@ -0,0 +1,21 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api.exceptions.connection; + +/** + * Thrown when Connection fails to connect to an address. + * + * @author Rsl1122 + */ +public class ConnectionFailException extends WebException { + + public ConnectionFailException(String message, Throwable cause) { + super(message, cause); + } + + public ConnectionFailException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIForbiddenException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/ForbiddenException.java similarity index 53% rename from Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIForbiddenException.java rename to Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/ForbiddenException.java index 8aa2a587e..1e06b5844 100644 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/WebAPIForbiddenException.java +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/ForbiddenException.java @@ -1,16 +1,16 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.api.exceptions; +package com.djrapitops.plan.api.exceptions.connection; /** - * Thrown when WebAPI gets a 403 response. + * Thrown when Connection gets a 403 response. * * @author Rsl1122 */ -public class WebAPIForbiddenException extends WebAPIFailException { - public WebAPIForbiddenException(String url) { +public class ForbiddenException extends WebFailException { + public ForbiddenException(String url) { super("Forbidden: " + url); } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/InternalErrorException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/InternalErrorException.java new file mode 100644 index 000000000..ddac58c62 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/InternalErrorException.java @@ -0,0 +1,20 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api.exceptions.connection; + +/** + * Thrown when Connection returns 500. + * + * @author Rsl1122 + */ +public class InternalErrorException extends WebFailException { + public InternalErrorException() { + super("Internal Error occurred on receiving server"); + } + + public InternalErrorException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/NoServersException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/NoServersException.java new file mode 100644 index 000000000..3f57119b4 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/NoServersException.java @@ -0,0 +1,25 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api.exceptions.connection; + +/** + * Thrown when ConnectionSystem can not find any servers to send request to. + * + * @author Rsl1122 + */ +public class NoServersException extends WebException { + + public NoServersException(String message) { + super(message); + } + + public NoServersException(String message, Throwable cause) { + super(message, cause); + } + + public NoServersException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/NotFoundException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/NotFoundException.java new file mode 100644 index 000000000..2c817ef8f --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/NotFoundException.java @@ -0,0 +1,16 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api.exceptions.connection; + +/** + * Thrown when Connection returns 404, when page is not found. + * + * @author Rsl1122 + */ +public class NotFoundException extends WebFailException { + public NotFoundException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/TransferDatabaseException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/TransferDatabaseException.java new file mode 100644 index 000000000..68fae09d6 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/TransferDatabaseException.java @@ -0,0 +1,19 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api.exceptions.connection; + +import com.djrapitops.plan.api.exceptions.database.DBException; + +/** + * Thrown when DBException occurs during InfoRequest#placeIntoDatabase. + * + * @author Rsl1122 + */ +public class TransferDatabaseException extends WebException { + + public TransferDatabaseException(DBException cause) { + super(cause); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/UnauthorizedServerException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/UnauthorizedServerException.java new file mode 100644 index 000000000..2e6db01b9 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/UnauthorizedServerException.java @@ -0,0 +1,25 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api.exceptions.connection; + +/** + * Thrown when Connection gets a 412 response due to ServerUUID not being in the database. + * + * @author Rsl1122 + */ +public class UnauthorizedServerException extends WebFailException { + + public UnauthorizedServerException(String message) { + super(message); + } + + public UnauthorizedServerException(String message, Throwable cause) { + super(message, cause); + } + + public UnauthorizedServerException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/UnsupportedTransferDatabaseException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/UnsupportedTransferDatabaseException.java new file mode 100644 index 000000000..5ce6cdb08 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/UnsupportedTransferDatabaseException.java @@ -0,0 +1,19 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api.exceptions.connection; + +import com.djrapitops.plan.system.database.databases.Database; + +/** + * Exception thrown when calling Database#transfer and Database implementation doesn't support it. + * + * @author Rsl1122 + */ +public class UnsupportedTransferDatabaseException extends WebException { + + public UnsupportedTransferDatabaseException(Database db) { + super(db.getName() + " does not support Transfer operations!"); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/WebException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/WebException.java new file mode 100644 index 000000000..5b5866f89 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/WebException.java @@ -0,0 +1,28 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api.exceptions.connection; + +/** + * Thrown when Connection POST-request fails, general Exception. + * + * @author Rsl1122 + */ +public class WebException extends Exception { + + public WebException() { + } + + public WebException(String message) { + super(message); + } + + public WebException(String message, Throwable cause) { + super(message, cause); + } + + public WebException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/WebFailException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/WebFailException.java new file mode 100644 index 000000000..4d1145e3e --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/connection/WebFailException.java @@ -0,0 +1,28 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.api.exceptions.connection; + +/** + * Group of WebExceptions that can be considered a failed connection state on some occasions. + * + * @author Rsl1122 + */ +public class WebFailException extends WebException { + + public WebFailException() { + } + + public WebFailException(String message) { + super(message); + } + + public WebFailException(String message, Throwable cause) { + super(message, cause); + } + + public WebFailException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/DatabaseException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/DBException.java similarity index 58% rename from Plan/src/main/java/com/djrapitops/plan/api/exceptions/DatabaseException.java rename to Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/DBException.java index 5804614aa..d275f598b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/DatabaseException.java +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/DBException.java @@ -1,25 +1,25 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.api.exceptions; +package com.djrapitops.plan.api.exceptions.database; /** * Thrown when something goes wrong with the Database, generic exception. * * @author Rsl1122 */ -public class DatabaseException extends Exception { +public class DBException extends Exception { - public DatabaseException(String message, Throwable cause) { + public DBException(String message, Throwable cause) { super(message, cause); } - public DatabaseException(Throwable cause) { + public DBException(Throwable cause) { super(cause); } - public DatabaseException(String message) { + public DBException(String message) { super(message); } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/DatabaseInitException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/DBInitException.java similarity index 55% rename from Plan/src/main/java/com/djrapitops/plan/api/exceptions/DatabaseInitException.java rename to Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/DBInitException.java index 73628a3b0..a70acf1b5 100644 --- a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/DatabaseInitException.java +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/DBInitException.java @@ -1,25 +1,25 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.api.exceptions; +package com.djrapitops.plan.api.exceptions.database; /** * Thrown when something goes wrong with {@code Database#init}. * * @author Rsl1122 */ -public class DatabaseInitException extends DatabaseException { +public class DBInitException extends FatalDBException { - public DatabaseInitException(String message, Throwable cause) { + public DBInitException(String message, Throwable cause) { super(message, cause); } - public DatabaseInitException(Throwable cause) { + public DBInitException(Throwable cause) { super(cause); } - public DatabaseInitException(String message) { + public DBInitException(String message) { super(message); } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/DBNoDataException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/DBNoDataException.java new file mode 100644 index 000000000..71effcbe4 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/DBNoDataException.java @@ -0,0 +1,16 @@ +package com.djrapitops.plan.api.exceptions.database; + +public class DBNoDataException extends DBException { + + public DBNoDataException(String message, Throwable cause) { + super(message, cause); + } + + public DBNoDataException(Throwable cause) { + super(cause); + } + + public DBNoDataException(String message) { + super(message); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/FatalDBException.java b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/FatalDBException.java new file mode 100644 index 000000000..c0ec4bcd0 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/api/exceptions/database/FatalDBException.java @@ -0,0 +1,16 @@ +package com.djrapitops.plan.api.exceptions.database; + +public class FatalDBException extends DBException { + + public FatalDBException(String message, Throwable cause) { + super(message, cause); + } + + public FatalDBException(Throwable cause) { + super(cause); + } + + public FatalDBException(String message) { + super(message); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/command/ConditionUtils.java b/Plan/src/main/java/com/djrapitops/plan/command/ConditionUtils.java deleted file mode 100644 index d5bd2dcab..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/command/ConditionUtils.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.djrapitops.plan.command; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plugin.api.Check; -import com.djrapitops.plugin.utilities.Verify; - -import java.util.UUID; - -/** - * This class contains methods used by commands - * - * @author Rsl1122 - * @since 3.5.0 - */ -public class ConditionUtils { - - /** - * Constructor used to hide the public constructor - */ - private ConditionUtils() { - throw new IllegalStateException("Utility class"); - } - - /** - * Condition if the player has played. - * - * @param uuid UUID of player - * @return has the player played before, false if uuid is null. - */ - public static boolean playerHasPlayed(UUID uuid) { - if ( Verify.containsNull(uuid)) { - return false; - } - boolean hasPlayed; - if (Check.isBukkitAvailable()) { - hasPlayed = Plan.getInstance().getServer().getOfflinePlayer(uuid).hasPlayedBefore(); - } else { - hasPlayed = PlanBungee.getInstance().getDB().wasSeenBefore(uuid); - } - return hasPlayed; - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/command/PlanBungeeCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/PlanBungeeCommand.java index b2907fd3a..102b51cd4 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/PlanBungeeCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/PlanBungeeCommand.java @@ -2,9 +2,9 @@ package com.djrapitops.plan.command; import com.djrapitops.plan.PlanBungee; import com.djrapitops.plan.command.commands.*; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.TreeCommand; import com.djrapitops.plugin.command.defaultcmds.StatusCommand; @@ -43,13 +43,13 @@ public class PlanBungeeCommand extends TreeCommand { new ReloadCommand(plugin), new StatusCommand<>(plugin, Permissions.MANAGE.getPermission(), plugin.getColorScheme()), new ListCommand(), - new BungeeSetupToggleCommand(plugin) + new BungeeSetupToggleCommand() ); - RegisterCommand registerCommand = new RegisterCommand(plugin); + RegisterCommand registerCommand = new RegisterCommand(); add( registerCommand, new WebUserCommand(plugin, registerCommand), - new NetworkCommand(plugin), + new NetworkCommand(), new ListServersCommand(plugin) ); } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/PlanCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/PlanCommand.java index 1247c9ca7..e76518554 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/PlanCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/PlanCommand.java @@ -2,16 +2,16 @@ package com.djrapitops.plan.command; import com.djrapitops.plan.Plan; import com.djrapitops.plan.command.commands.*; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.TreeCommand; import com.djrapitops.plugin.command.defaultcmds.StatusCommand; /** - * TreeCommand for the /plan command, and all subcommands. + * TreeCommand for the /plan command, and all SubCommands. *

* Uses the Abstract Plugin Framework for easier command management. * @@ -20,13 +20,6 @@ import com.djrapitops.plugin.command.defaultcmds.StatusCommand; */ public class PlanCommand extends TreeCommand { - /** - * CommandExecutor class Constructor. - *

- * Initializes Subcommands - * - * @param plugin Current instance of Plan - */ public PlanCommand(Plan plugin) { super(plugin, "plan", CommandType.CONSOLE, "", "", "plan"); super.setDefaultCommand("inspect"); @@ -41,25 +34,25 @@ public class PlanCommand extends TreeCommand { @Override public void addCommands() { add( - new InspectCommand(plugin), + new InspectCommand(), new QInspectCommand(plugin), - new AnalyzeCommand(plugin), - new SearchCommand(plugin), + new AnalyzeCommand(), + new SearchCommand(), new InfoCommand(plugin), new ReloadCommand(plugin), new ManageCommand(plugin), new StatusCommand<>(plugin, Permissions.MANAGE.getPermission(), plugin.getColorScheme()), new ListCommand() ); - RegisterCommand registerCommand = new RegisterCommand(plugin); + RegisterCommand registerCommand = new RegisterCommand(); add( registerCommand, new WebUserCommand(plugin, registerCommand), - new NetworkCommand(plugin), + new NetworkCommand(), new ListServersCommand(plugin)); if (Settings.DEV_MODE.isTrue()) { - add(new DevCommand(plugin)); + add(new DevCommand()); } } } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/AnalyzeCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/AnalyzeCommand.java index 493ddd68e..dad3e1746 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/AnalyzeCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/AnalyzeCommand.java @@ -1,77 +1,43 @@ package com.djrapitops.plan.command.commands; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.info.InformationManager; -import com.djrapitops.plan.systems.info.server.ServerInfo; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plan.system.webserver.WebServerSystem; +import com.djrapitops.plan.utilities.analysis.Analysis; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.CommandUtils; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; -import com.djrapitops.plugin.task.AbsRunnable; -import com.djrapitops.plugin.task.RunnableFactory; -import com.djrapitops.plugin.utilities.Verify; import org.bukkit.ChatColor; -import java.sql.SQLException; -import java.util.Collection; -import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.UUID; /** - * This subcommand is used to run the analysis and access the /server link. + * This SubCommand is used to run the analysis and access the /server link. * * @author Rsl1122 * @since 2.0.0 */ public class AnalyzeCommand extends SubCommand { - private final Plan plugin; - private final InformationManager infoManager; - - /** - * Subcommand Constructor. - * - * @param plugin Current instance of Plan - */ - public AnalyzeCommand(Plan plugin) { + public AnalyzeCommand() { super("analyze, analyse, analysis, a", CommandType.CONSOLE, Permissions.ANALYZE.getPermission(), Locale.get(Msg.CMD_USG_ANALYZE).parse(), "[ServerName or ID]"); - this.plugin = plugin; - infoManager = plugin.getInfoManager(); - } - - public static void sendAnalysisMessage(Collection senders, UUID serverUUID) throws SQLException { - if (Verify.isEmpty(senders)) { - return; - } - Plan plugin = Plan.getInstance(); - Optional serverName = plugin.getDB().getServerTable().getServerName(serverUUID); - serverName.ifPresent(name -> { - String target = "/server/" + name; - String url = plugin.getInfoManager().getLinkTo(target); - String message = Locale.get(Msg.CMD_INFO_LINK).toString(); - - for (ISender sender : senders) { - sender.sendMessage(Locale.get(Msg.CMD_HEADER_ANALYZE).toString()); - // Link - boolean console = !CommandUtils.isPlayer(sender); - if (console) { - sender.sendMessage(message + url); - } else { - sender.sendMessage(message); - sender.sendLink(" ", Locale.get(Msg.CMD_INFO_CLICK_ME).toString(), url); - } - sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).toString()); - } - }); } @Override @@ -81,57 +47,75 @@ public class AnalyzeCommand extends SubCommand { @Override public boolean onCommand(ISender sender, String commandLabel, String[] args) { - - // TODO Write a command for listing servers. - - UUID serverUUID = Plan.getServerUUID(); - if (args.length >= 1 && plugin.getInfoManager().isUsingAnotherWebServer()) { - try { - List bukkitServers = plugin.getDB().getServerTable().getBukkitServers(); - Optional server = bukkitServers.stream().filter(info -> { - StringBuilder idBuilder = new StringBuilder(args[0]); - if (args.length > 1) { - for (int i = 1; i < args.length; i++) { - idBuilder.append(" ").append(args[i]); - } - } - String serverIdentifier = idBuilder.toString(); - return Integer.toString(info.getId()).equals(serverIdentifier) || info.getName().equalsIgnoreCase(serverIdentifier); - }).findFirst(); - if (server.isPresent()) { - serverUUID = server.get().getUuid(); - } - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - return true; - } - } - - updateCache(sender, serverUUID); - sender.sendMessage(Locale.get(Msg.CMD_INFO_FETCH_DATA).toString()); - if (plugin.getInfoManager().isAuthRequired() && CommandUtils.isPlayer(sender)) { - RunnableFactory.createNew(new AbsRunnable("WebUser exist check task") { - @Override - public void run() { - try { - boolean senderHasWebUser = plugin.getDB().getSecurityTable().userExists(sender.getName()); - if (!senderHasWebUser) { - sender.sendMessage(ChatColor.YELLOW + "[Plan] You might not have a web user, use /plan register "); - } - } catch (Exception e) { - Log.toLog(this.getClass().getName() + getName(), e); - } finally { - this.cancel(); - } + + Processor.queue(() -> { + try { + Server server = getServer(args).orElseGet(ServerInfo::getServer); + UUID serverUUID = server.getUuid(); + if (!ServerInfo.getServerUUID().equals(serverUUID) || !Analysis.isAnalysisBeingRun()) { + InfoSystem.getInstance().generateAnalysisPage(serverUUID); } - }).runTaskAsynchronously(); - } + sendWebUserNotificationIfNecessary(sender); + sendLink(server, sender); + } catch (DBException | WebException e) { + // TODO Exception handling + sender.sendMessage(ChatColor.RED + " Error occurred: " + e.toString()); + Log.toLog(this.getClass(), e); + } + }); return true; } - private void updateCache(ISender sender, UUID serverUUID) { - infoManager.addAnalysisNotification(sender, serverUUID); - infoManager.refreshAnalysis(serverUUID); + private void sendLink(Server server, ISender sender) { + String target = "/server/" + server.getName(); + String url = ConnectionSystem.getAddress() + target; + String message = Locale.get(Msg.CMD_INFO_LINK).toString(); + sender.sendMessage(Locale.get(Msg.CMD_HEADER_ANALYZE).toString()); + // Link + boolean console = !CommandUtils.isPlayer(sender); + if (console) { + sender.sendMessage(message + url); + } else { + sender.sendMessage(message); + sender.sendLink(" ", Locale.get(Msg.CMD_INFO_CLICK_ME).toString(), url); + } + sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).toString()); + } + + private void sendWebUserNotificationIfNecessary(ISender sender) throws DBException { + if (WebServerSystem.getInstance().getWebServer().isAuthRequired() && CommandUtils.isPlayer(sender)) { + + boolean senderHasWebUser = Database.getActive().check().doesWebUserExists(sender.getName()); + if (!senderHasWebUser) { + sender.sendMessage(ChatColor.YELLOW + "[Plan] You might not have a web user, use /plan register "); + } + } + } + + private Optional getServer(String[] args) throws DBException { + if (args.length >= 1 && ConnectionSystem.getInstance().isServerAvailable()) { + Map bukkitServers = Database.getActive().fetch().getBukkitServers(); + String serverIdentifier = getGivenIdentifier(args); + for (Map.Entry entry : bukkitServers.entrySet()) { + Server server = entry.getValue(); + + if (Integer.toString(server.getId()).equals(serverIdentifier) + || server.getName().equalsIgnoreCase(serverIdentifier)) { + return Optional.of(server); + } + } + } + return Optional.empty(); + } + + private String getGivenIdentifier(String[] args) { + StringBuilder idBuilder = new StringBuilder(args[0]); + if (args.length > 1) { + for (int i = 1; i < args.length; i++) { + idBuilder.append(" ").append(args[i]); + } + } + return idBuilder.toString(); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/BungeeSetupToggleCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/BungeeSetupToggleCommand.java index 25db2b3be..f4e3b7482 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/BungeeSetupToggleCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/BungeeSetupToggleCommand.java @@ -4,33 +4,34 @@ */ package com.djrapitops.plan.command.commands; -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.settings.Permissions; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.settings.Permissions; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; /** - * //TODO Class Javadoc Comment + * Command for Toggling whether or not BungeeCord accepts set up requests. + * + * This was added as a security measure against unwanted MySQL snooping. * * @author Rsl1122 */ public class BungeeSetupToggleCommand extends SubCommand { - private final PlanBungee plugin; - - public BungeeSetupToggleCommand(PlanBungee plugin) { + public BungeeSetupToggleCommand() { super("setup", CommandType.ALL, Permissions.MANAGE.getPermission(), "Toggle Setup mode for Bungee"); - this.plugin = plugin; } @Override public boolean onCommand(ISender sender, String s, String[] strings) { - boolean setupAllowed = plugin.isSetupAllowed(); + boolean setupAllowed = ConnectionSystem.isSetupAllowed(); + ConnectionSystem connectionSystem = ConnectionSystem.getInstance(); + if (setupAllowed) { - plugin.setSetupAllowed(false); + connectionSystem.setSetupAllowed(false); } else { - plugin.setSetupAllowed(true); + connectionSystem.setSetupAllowed(true); } String msg = !setupAllowed ? "§aSet-up is now Allowed" : "§cSet-up is now Forbidden"; sender.sendMessage(msg); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/DevCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/DevCommand.java index a56ae6a5b..7021b997e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/DevCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/DevCommand.java @@ -1,23 +1,17 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan.command.commands; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; -import com.djrapitops.plan.systems.webserver.webapi.bukkit.InspectWebAPI; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; -import java.util.Optional; -import java.util.UUID; - /** * Command used for testing functions that are too difficult to unit test. * @@ -25,11 +19,8 @@ import java.util.UUID; */ public class DevCommand extends SubCommand { - private final Plan plugin; - - public DevCommand(Plan plugin) { + public DevCommand() { super("dev", CommandType.PLAYER_OR_ARGS, "plan.*", "Test Plugin functions not testable with unit tests.", ""); - this.plugin = plugin; } @Override @@ -39,48 +30,21 @@ public class DevCommand extends SubCommand { } String feature = args[0]; switch (feature) { - case "webapi": + case "connection": if (!Condition.isTrue(args.length >= 2, Locale.get(Msg.CMD_FAIL_REQ_ONE_ARG).toString(), sender)) { break; } - if (!webapi(args[1] + "webapi", args.length >= 3)) { - sender.sendMessage("[Plan] No such API / Exception occurred."); - } + sender.sendMessage("[Plan] No implementation."); break; case "web": - Optional bungeeConnectionAddress = plugin.getServerInfoManager().getBungeeConnectionAddress(); - String accessAddress = plugin.getWebServer().getAccessAddress(); - sender.sendMessage((plugin.getInfoManager().isUsingAnotherWebServer() && bungeeConnectionAddress.isPresent()) - ? "Bungee: " + bungeeConnectionAddress.get() : "Local: " + accessAddress); + ConnectionSystem connectionSystem = ConnectionSystem.getInstance(); + String accessAddress = connectionSystem.getMainAddress(); + sender.sendMessage((connectionSystem.isServerAvailable()) + ? "Bungee: " + accessAddress : "Local: " + accessAddress); break; default: break; } return true; } - - private boolean webapi(String method, boolean connectToBungee) { - WebAPI api = plugin.getWebServer().getWebAPI().getAPI(method); - if (api == null) { - return false; - } - try { - String address = plugin.getWebServer().getAccessAddress(); - if (connectToBungee) { - Optional bungeeConnectionAddress = plugin.getServerInfoManager().getBungeeConnectionAddress(); - if (bungeeConnectionAddress.isPresent()) { - address = bungeeConnectionAddress.get(); - } - } - if (api instanceof InspectWebAPI) { - ((InspectWebAPI) api).sendRequest(address, UUID.randomUUID()); - } else { - api.sendRequest(address); - } - return true; - } catch (WebAPIException e) { - e.printStackTrace(); - } - return false; - } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java index a5221fa00..801ef88d4 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/InfoCommand.java @@ -1,16 +1,18 @@ package com.djrapitops.plan.command.commands; import com.djrapitops.plan.Plan; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plan.system.update.VersionCheckSystem; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; import com.djrapitops.plugin.settings.ColorScheme; /** - * This subcommand is used to view the version and the database type in use. + * This SubCommand is used to view the version and the database type in use. * * @author Rsl1122 * @since 2.0.0 @@ -19,11 +21,6 @@ public class InfoCommand extends SubCommand { private final Plan plugin; - /** - * Subcommand Constructor. - * - * @param plugin Current instance of Plan - */ public InfoCommand(Plan plugin) { super("info", CommandType.CONSOLE, @@ -40,10 +37,13 @@ public class InfoCommand extends SubCommand { String sColor = cs.getSecondaryColor(); String tColor = cs.getTertiaryColor(); String ball = Locale.get(Msg.CMD_CONSTANT_LIST_BALL).toString(); + + String upToDate = VersionCheckSystem.isNewVersionAvailable() ? "Update Available" : "Up to date"; String[] messages = { Locale.get(Msg.CMD_HEADER_INFO).toString(), ball + mColor + " Version: " + sColor + plugin.getDescription().getVersion(), - ball + mColor + " Active Database: " + tColor + plugin.getDB().getConfigName(), + ball + mColor + " Up to date: " + sColor + upToDate, + ball + mColor + " Active Database: " + tColor + Database.getActive().getConfigName(), Locale.get(Msg.CMD_CONSTANT_FOOTER).toString() }; sender.sendMessage(messages); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/InspectCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/InspectCommand.java index 24efbe4e7..b1039dc81 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/InspectCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/InspectCommand.java @@ -1,11 +1,13 @@ package com.djrapitops.plan.command.commands; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.command.ConditionUtils; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.processing.info.InspectCacheRequestProcessor; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.api.exceptions.database.FatalDBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.processing.processors.info.InspectCacheRequestProcessor; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plan.system.webserver.WebServer; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plan.utilities.uuid.UUIDUtility; @@ -19,33 +21,22 @@ import com.djrapitops.plugin.task.RunnableFactory; import com.djrapitops.plugin.utilities.Verify; import org.bukkit.ChatColor; -import java.sql.SQLException; import java.util.UUID; /** - * This command is used to cache UserInfo to InspectCache and display the link. + * This command is used to refresh Inspect page and display link. * * @author Rsl1122 * @since 1.0.0 */ public class InspectCommand extends SubCommand { - private final Plan plugin; - - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public InspectCommand(Plan plugin) { + public InspectCommand() { super("inspect", CommandType.PLAYER_OR_ARGS, Permissions.INSPECT.getPermission(), Locale.get(Msg.CMD_USG_INSPECT).toString(), ""); - - this.plugin = plugin; - } @Override @@ -66,26 +57,28 @@ public class InspectCommand extends SubCommand { @Override public void run() { try { + Database activeDB = Database.getActive(); UUID uuid = UUIDUtility.getUUIDOf(playerName); if (!Condition.isTrue(Verify.notNull(uuid), Locale.get(Msg.CMD_FAIL_USERNAME_NOT_VALID).toString(), sender)) { return; } - if (!Condition.isTrue(ConditionUtils.playerHasPlayed(uuid), Locale.get(Msg.CMD_FAIL_USERNAME_NOT_SEEN).toString(), sender)) { + if (!Condition.isTrue(activeDB.check().isPlayerRegistered(uuid), Locale.get(Msg.CMD_FAIL_USERNAME_NOT_KNOWN).toString(), sender)) { return; } - if (!Condition.isTrue(plugin.getDB().wasSeenBefore(uuid), Locale.get(Msg.CMD_FAIL_USERNAME_NOT_KNOWN).toString(), sender)) { - return; - } - if (CommandUtils.isPlayer(sender) && plugin.getWebServer().isAuthRequired()) { - boolean senderHasWebUser = plugin.getDB().getSecurityTable().userExists(sender.getName()); + if (CommandUtils.isPlayer(sender) && WebServer.getInstance().isAuthRequired()) { + boolean senderHasWebUser = activeDB.check().doesWebUserExists(sender.getName()); + if (!senderHasWebUser) { sender.sendMessage(ChatColor.YELLOW + "[Plan] You might not have a web user, use /plan register "); } } - - plugin.addToProcessQueue(new InspectCacheRequestProcessor(uuid, sender, playerName)); - } catch (SQLException ex) { - Log.toLog(this.getClass().getName(), ex); + new InspectCacheRequestProcessor(uuid, sender, playerName).queue(); + } catch (FatalDBException ex) { + Log.toLog(this.getClass(), ex); + sender.sendMessage(ChatColor.RED + "Fatal database exception occurred: " + ex.getMessage()); + } catch (DBException ex) { + Log.toLog(this.getClass(), ex); + sender.sendMessage(ChatColor.YELLOW + "Non-Fatal database exception occurred: " + ex.getMessage()); } finally { this.cancel(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/ListCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/ListCommand.java index f385c96c7..db06e1f0d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/ListCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/ListCommand.java @@ -1,30 +1,24 @@ package com.djrapitops.plan.command.commands; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.CommandUtils; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; /** - * Command used to display link to the player list webpage. - *

- * Subcommand is not registered if Webserver is not enabled. + * Command used to display url to the player list page. * * @author Rsl1122 * @since 3.5.2 */ public class ListCommand extends SubCommand { - /** - * Class Constructor. - */ public ListCommand() { - super("list, pl", CommandType.CONSOLE, Permissions.INSPECT_OTHER.getPermission(), Locale.get(Msg.CMD_USG_LIST).toString(), ""); - + super("list, pl, playerlist, players", CommandType.CONSOLE, Permissions.INSPECT_OTHER.getPermission(), Locale.get(Msg.CMD_USG_LIST).toString(), ""); } @Override @@ -43,7 +37,7 @@ public class ListCommand extends SubCommand { sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).parse()); // Link - String url = MiscUtils.getIPlan().getInfoManager().getLinkTo("/players/"); + String url = ConnectionSystem.getAddress() + "/players/"; String message = Locale.get(Msg.CMD_INFO_LINK).toString(); boolean console = !CommandUtils.isPlayer(sender); if (console) { diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/ListServersCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/ListServersCommand.java index 6efc95d4e..2837d8b3f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/ListServersCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/ListServersCommand.java @@ -1,34 +1,30 @@ package com.djrapitops.plan.command.commands; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; import com.djrapitops.plugin.settings.ColorScheme; -import java.sql.SQLException; -import java.util.Map; +import java.util.List; /** - * This subcommand is used to reload the plugin. + * This SubCommand is used to list all servers found in the database. * * @author Rsl1122 - * @since 2.0.0 */ public class ListServersCommand extends SubCommand { - private final IPlan plugin; + private final PlanPlugin plugin; - /** - * Subcommand constructor. - * - * @param plugin Current instance of Plan - */ - public ListServersCommand(IPlan plugin) { + public ListServersCommand(PlanPlugin plugin) { super("servers, serverlist, listservers, sl", CommandType.CONSOLE, Permissions.MANAGE.getPermission(), @@ -45,14 +41,14 @@ public class ListServersCommand extends SubCommand { String tCol = colorScheme.getTertiaryColor(); try { sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).toString() + mCol + " Servers"); - Map serverNames = plugin.getDB().getServerTable().getServerNamesByID(); - for (Map.Entry entry : serverNames.entrySet()) { - sender.sendMessage(" " + tCol + entry.getKey() + sCol + " : " + entry.getValue()); + List servers = Database.getActive().fetch().getServers(); + for (Server server : servers) { + sender.sendMessage(" " + tCol + server.getId() + sCol + " : " + server.getName() + " : " + server.getWebAddress()); } sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).toString()); - } catch (SQLException e) { - sender.sendMessage("§cSQLException occurred."); - Log.toLog(this.getClass().getName(), e); + } catch (DBException e) { + sender.sendMessage("§cDatabase Exception occurred."); + Log.toLog(this.getClass(), e); } return true; } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/ManageCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/ManageCommand.java index 28fe8f3f7..d0a5c86dd 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/ManageCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/ManageCommand.java @@ -2,27 +2,20 @@ package com.djrapitops.plan.command.commands; import com.djrapitops.plan.Plan; import com.djrapitops.plan.command.commands.manage.*; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.TreeCommand; /** - * This command is used to manage the database of the plugin. - *

- * No arguments will run ManageHelpCommand. Contains subcommands. + * This SubCommand is used to manage the the plugin's database and components. * * @author Rsl1122 * @since 2.3.0 */ public class ManageCommand extends TreeCommand { - /** - * Subcommand Constructor. - * - * @param plugin Current instance of Plan - */ public ManageCommand(Plan plugin) { super(plugin, "manage,m", CommandType.CONSOLE, Permissions.MANAGE.getPermission(), Locale.get(Msg.CMD_USG_MANAGE).toString(), "plan m"); super.setColorScheme(plugin.getColorScheme()); @@ -36,14 +29,14 @@ public class ManageCommand extends TreeCommand { @Override public void addCommands() { add( - new ManageMoveCommand(plugin), + new ManageMoveCommand(), new ManageHotswapCommand(plugin), - new ManageBackupCommand(plugin), + new ManageBackupCommand(), new ManageRestoreCommand(plugin), - new ManageImportCommand(plugin), - new ManageRemoveCommand(plugin), + new ManageImportCommand(), + new ManageRemoveCommand(), new ManageClearCommand(plugin), - new ManageSetupCommand(plugin), + new ManageSetupCommand(), new ManageDisableCommand() ); } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/NetworkCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/NetworkCommand.java index 1b473e9d3..d9bd4fc87 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/NetworkCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/NetworkCommand.java @@ -1,35 +1,26 @@ package com.djrapitops.plan.command.commands; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.CommandUtils; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; /** - * Command used to display link to the player list webpage. - *

- * Subcommand is not registered if Webserver is not enabled. + * Command used to display url to the network page. * * @author Rsl1122 - * @since 3.5.2 */ public class NetworkCommand extends SubCommand { - private final IPlan plugin; - - /** - * Class Constructor. - */ - public NetworkCommand(IPlan plugin) { + public NetworkCommand() { super("network, n, netw", CommandType.CONSOLE, Permissions.ANALYZE.getPermission(), "Get the link to the network page"); - this.plugin = plugin; } @Override @@ -42,7 +33,7 @@ public class NetworkCommand extends SubCommand { sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).parse()); // Link - String url = plugin.getInfoManager().getLinkTo("/network/"); + String url = ConnectionSystem.getAddress() + "/network/"; String message = Locale.get(Msg.CMD_INFO_LINK).toString(); boolean console = !CommandUtils.isPlayer(sender); if (console) { diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/QInspectCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/QInspectCommand.java index 0af0d9348..f209a1455 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/QInspectCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/QInspectCommand.java @@ -1,10 +1,13 @@ package com.djrapitops.plan.command.commands; -import com.djrapitops.plan.api.IPlan; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.api.exceptions.database.DBException; import com.djrapitops.plan.data.PlayerProfile; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.data.calculation.ActivityIndex; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.MiscUtils; @@ -19,7 +22,6 @@ import com.djrapitops.plugin.task.AbsRunnable; import com.djrapitops.plugin.task.RunnableFactory; import com.djrapitops.plugin.utilities.Verify; -import java.sql.SQLException; import java.util.UUID; /** @@ -30,14 +32,14 @@ import java.util.UUID; */ public class QInspectCommand extends SubCommand { - private final IPlan plugin; + private final PlanPlugin plugin; /** * Class Constructor. * * @param plugin Current instance of Plan */ - public QInspectCommand(IPlan plugin) { + public QInspectCommand(PlanPlugin plugin) { super("qinspect", CommandType.PLAYER_OR_ARGS, Permissions.QUICK_INSPECT.getPermission(), @@ -70,16 +72,17 @@ public class QInspectCommand extends SubCommand { if (!Condition.isTrue(Verify.notNull(uuid), Locale.get(Msg.CMD_FAIL_USERNAME_NOT_VALID).toString(), sender)) { return; } - if (!Condition.isTrue(plugin.getDB().wasSeenBefore(uuid), Locale.get(Msg.CMD_FAIL_USERNAME_NOT_KNOWN).toString(), sender)) { + Database database = Database.getActive(); + if (!Condition.isTrue(database.check().isPlayerRegistered(uuid), Locale.get(Msg.CMD_FAIL_USERNAME_NOT_KNOWN).toString(), sender)) { return; } - PlayerProfile playerProfile = plugin.getDB().getPlayerProfile(uuid); + PlayerProfile playerProfile = database.fetch().getPlayerProfile(uuid); sendMsgs(sender, playerProfile); - } catch (SQLException ex) { - Log.toLog(this.getClass().getName(), ex); + } catch (DBException ex) { + Log.toLog(this.getClass(), ex); } finally { this.cancel(); } @@ -100,9 +103,9 @@ public class QInspectCommand extends SubCommand { sender.sendMessage(Locale.get(Msg.CMD_HEADER_INSPECT).toString() + ": " + colT + profile.getName()); - double activityIndex = profile.getActivityIndex(now); + ActivityIndex activityIndex = profile.getActivityIndex(now); - sender.sendMessage(colT + ball + " " + colM + " Activity Index: " + colS + FormatUtils.cutDecimals(activityIndex) + " | " + FormatUtils.readableActivityIndex(activityIndex)[1]); + sender.sendMessage(colT + ball + " " + colM + " Activity Index: " + colS + activityIndex.getFormattedValue() + " | " + activityIndex.getColor()); sender.sendMessage(colT + ball + " " + colM + " Registered: " + colS + FormatUtils.formatTimeStampYear(profile.getRegistered())); sender.sendMessage(colT + ball + " " + colM + " Last Seen: " + colS + FormatUtils.formatTimeStampYear(profile.getLastSeen())); sender.sendMessage(colT + ball + " " + colM + " Logged in from: " + colS + profile.getMostRecentGeoInfo().getGeolocation()); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommand.java index 97e17055a..12280ec51 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/RegisterCommand.java @@ -1,11 +1,10 @@ package com.djrapitops.plan.command.commands; -import com.djrapitops.plan.api.IPlan; import com.djrapitops.plan.data.WebUser; -import com.djrapitops.plan.database.tables.SecurityTable; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plan.utilities.PassEncryptUtil; import com.djrapitops.plugin.api.Check; @@ -20,26 +19,22 @@ import com.djrapitops.plugin.task.RunnableFactory; /** * Command for registering web users. *

- * Registers a new webuser to the database. + * Registers a new WebUser to the database. *

- * No permission required for self registration. (Constructor string is empty) - *

- * plan.webmanage required for registering other users. + * No permission required for self registration. (Super constructor string is empty). + * {@code Permissions.MANAGE_WEB} required for registering other users. * * @author Rsl1122 * @since 3.5.2 */ public class RegisterCommand extends SubCommand { - private final IPlan plugin; - - public RegisterCommand(IPlan plugin) { + public RegisterCommand() { super("register", CommandType.PLAYER_OR_ARGS, "", // No Permission Requirement Locale.get(Msg.CMD_USG_WEB_REGISTER).toString(), " [name] [access lvl]"); - this.plugin = plugin; if (Check.isBukkitAvailable()) { setupFilter(); } @@ -121,16 +116,16 @@ public class RegisterCommand extends SubCommand { final String userName = webUser.getName(); final String successMsg = "§aAdded a new user (" + userName + ") successfully!"; try { - SecurityTable securityTable = plugin.getDB().getSecurityTable(); - boolean userExists = securityTable.userExists(userName); + Database database = Database.getActive(); + boolean userExists = database.check().doesWebUserExists(userName); if (!Condition.isTrue(!userExists, existsMsg, sender)) { return; } - securityTable.addNewUser(webUser); + database.save().webUser(webUser); sender.sendMessage(successMsg); Log.info("Registered new user: " + userName + " Perm level: " + webUser.getPermLevel()); } catch (Exception e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } finally { this.cancel(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/ReloadCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/ReloadCommand.java index 0ed5dc405..839a3cd4c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/ReloadCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/ReloadCommand.java @@ -1,30 +1,25 @@ package com.djrapitops.plan.command.commands; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; /** - * This subcommand is used to reload the plugin. + * This SubCommand is used to reload the plugin. * * @author Rsl1122 * @since 2.0.0 */ public class ReloadCommand extends SubCommand { - private final IPlan plugin; + private final PlanPlugin plugin; - /** - * Subcommand constructor. - * - * @param plugin Current instance of Plan - */ - public ReloadCommand(IPlan plugin) { + public ReloadCommand(PlanPlugin plugin) { super("reload", CommandType.CONSOLE, Permissions.MANAGE.getPermission(), @@ -38,7 +33,7 @@ public class ReloadCommand extends SubCommand { try { plugin.reloadPlugin(true); } catch (Exception e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); sender.sendMessage("§cSomething went wrong during reload of the plugin, a restart is recommended."); } sender.sendMessage(Locale.get(Msg.CMD_INFO_RELOAD_COMPLETE).toString()); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/SearchCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/SearchCommand.java index 15bdf3760..72441ad8d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/SearchCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/SearchCommand.java @@ -1,9 +1,8 @@ package com.djrapitops.plan.command.commands; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.command.CommandType; @@ -18,19 +17,14 @@ import java.util.Arrays; import java.util.List; /** - * This subcommand is used to search for a user, and to view all matches' data. + * This SubCommand is used to search for a user. * * @author Rsl1122 * @since 2.0.0 */ public class SearchCommand extends SubCommand { - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public SearchCommand(Plan plugin) { + public SearchCommand() { super("search", CommandType.PLAYER_OR_ARGS, Permissions.SEARCH.getPermission(), diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/WebUserCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/WebUserCommand.java index 72540429a..5119c40d1 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/WebUserCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/WebUserCommand.java @@ -2,14 +2,14 @@ package com.djrapitops.plan.command.commands; import com.djrapitops.plan.Plan; import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.api.IPlan; +import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.command.commands.webuser.WebCheckCommand; import com.djrapitops.plan.command.commands.webuser.WebDeleteCommand; import com.djrapitops.plan.command.commands.webuser.WebLevelCommand; import com.djrapitops.plan.command.commands.webuser.WebListUsersCommand; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.TreeCommand; @@ -19,7 +19,7 @@ import com.djrapitops.plugin.command.TreeCommand; * @author Rsl1122 * @since 3.5.2 */ -public class WebUserCommand extends TreeCommand { +public class WebUserCommand extends TreeCommand { public WebUserCommand(Plan plugin, RegisterCommand register) { super(plugin, "webuser, web", @@ -50,8 +50,8 @@ public class WebUserCommand extends TreeCommand { add( new WebLevelCommand(plugin), new WebListUsersCommand(plugin), - new WebCheckCommand(plugin), - new WebDeleteCommand(plugin) + new WebCheckCommand(), + new WebDeleteCommand() ); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageBackupCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageBackupCommand.java index 5c05d1ef7..7362b103d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageBackupCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageBackupCommand.java @@ -1,11 +1,11 @@ package com.djrapitops.plan.command.commands.manage; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.DatabaseInitException; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plan.utilities.ManageUtils; import com.djrapitops.plugin.api.utility.log.Log; @@ -24,21 +24,13 @@ import com.djrapitops.plugin.utilities.Verify; */ public class ManageBackupCommand extends SubCommand { - private final Plan plugin; - - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public ManageBackupCommand(Plan plugin) { + public ManageBackupCommand() { super("backup", CommandType.CONSOLE, Permissions.MANAGE.getPermission(), Locale.get(Msg.CMD_USG_MANAGE_BACKUP).toString(), ""); - this.plugin = plugin; } @Override @@ -54,7 +46,7 @@ public class ManageBackupCommand extends SubCommand { return true; } - final Database database = ManageUtils.getDB(dbName); + final Database database = DBSystem.getActiveDatabaseByName(dbName); // If DB is null return if (!Condition.isTrue(Verify.notNull(database), Locale.get(Msg.MANAGE_FAIL_FAULTY_DB).toString(), sender)) { @@ -63,7 +55,7 @@ public class ManageBackupCommand extends SubCommand { } Log.debug("Backup", "Start"); runBackupTask(sender, args, database); - } catch (DatabaseInitException | NullPointerException e) { + } catch (DBInitException | NullPointerException e) { sender.sendMessage(Locale.get(Msg.MANAGE_FAIL_FAULTY_DB).toString()); } finally { Log.logDebug("Backup"); @@ -80,7 +72,7 @@ public class ManageBackupCommand extends SubCommand { ManageUtils.backup(args[0], database); sender.sendMessage(Locale.get(Msg.MANAGE_INFO_COPY_SUCCESS).toString()); } catch (Exception e) { - Log.toLog(this.getClass().getName() + " " + getTaskName(), e); + Log.toLog(this.getClass(), e); sender.sendMessage(Locale.get(Msg.MANAGE_INFO_FAIL).toString()); } finally { this.cancel(); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageClearCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageClearCommand.java index 3df462979..4ada4101f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageClearCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageClearCommand.java @@ -1,16 +1,17 @@ package com.djrapitops.plan.command.commands.manage; import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.DatabaseInitException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.api.exceptions.database.FatalDBException; import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.cache.SessionCache; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; -import com.djrapitops.plan.utilities.ManageUtils; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.command.CommandType; @@ -20,10 +21,8 @@ import com.djrapitops.plugin.task.AbsRunnable; import com.djrapitops.plugin.task.RunnableFactory; import com.djrapitops.plugin.utilities.Verify; -import java.sql.SQLException; - /** - * This manage subcommand is used to clear a database of all data. + * This manage SubCommand is used to clear a database of all data. * * @author Rsl1122 * @since 2.3.0 @@ -32,11 +31,6 @@ public class ManageClearCommand extends SubCommand { private final Plan plugin; - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ public ManageClearCommand(Plan plugin) { super("clear", CommandType.PLAYER_OR_ARGS, @@ -71,9 +65,9 @@ public class ManageClearCommand extends SubCommand { } try { - Database database = ManageUtils.getDB(dbName); + Database database = DBSystem.getActiveDatabaseByName(dbName); runClearTask(sender, database); - } catch (DatabaseInitException e) { + } catch (DBInitException e) { sender.sendMessage(Locale.get(Msg.MANAGE_FAIL_FAULTY_DB).toString()); } return true; @@ -86,19 +80,22 @@ public class ManageClearCommand extends SubCommand { try { sender.sendMessage(Locale.get(Msg.MANAGE_INFO_START).parse()); - database.removeAllData(); + database.remove().everything(); - DataCache dataCache = plugin.getDataCache(); long now = MiscUtils.getTime(); SessionCache.clear(); plugin.getServer().getOnlinePlayers().forEach( - player -> dataCache.cacheSession(player.getUniqueId(), + player -> SessionCache.getInstance().cacheSession(player.getUniqueId(), new Session(now, player.getWorld().getName(), player.getGameMode().name())) ); sender.sendMessage(Locale.get(Msg.MANAGE_INFO_CLEAR_SUCCESS).toString()); - } catch (SQLException e) { + } catch (FatalDBException e) { + sender.sendMessage(Locale.get(Msg.MANAGE_INFO_FAIL).toString() + + " Error was fatal, so all information may not have been removed."); + Log.toLog(this.getClass(), e); + } catch (DBException e) { sender.sendMessage(Locale.get(Msg.MANAGE_INFO_FAIL).toString()); - Log.toLog(this.getClass().getSimpleName() + "/" + this.getTaskName(), e); + Log.toLog(this.getClass(), e); } finally { this.cancel(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageDisableCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageDisableCommand.java index b73515bb0..cf00f566f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageDisableCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageDisableCommand.java @@ -1,9 +1,9 @@ package com.djrapitops.plan.command.commands.manage; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.listeners.PlanPlayerListener; +import com.djrapitops.plan.system.listeners.bukkit.PlayerOnlineListener; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; @@ -34,7 +34,7 @@ public class ManageDisableCommand extends SubCommand { } switch (args[0].toLowerCase()) { case "kickcount": - PlanPlayerListener.setCountKicks(false); + PlayerOnlineListener.setCountKicks(false); sender.sendMessage("§aDisabled Kick Counting temporarily until next plugin reload."); break; default: diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageHotswapCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageHotswapCommand.java index 6c8263f40..a77a9b8b9 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageHotswapCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageHotswapCommand.java @@ -1,24 +1,21 @@ package com.djrapitops.plan.command.commands.manage; import com.djrapitops.plan.Plan; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; -import com.djrapitops.plan.utilities.ManageUtils; -import com.djrapitops.plugin.api.config.Config; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; import com.djrapitops.plugin.utilities.Verify; -import java.io.IOException; - /** - * This manage subcommand is used to swap to a different database and reload the + * This manage SubCommand is used to swap to a different database and reload the * plugin if the connection to the new database can be established. * * @author Rsl1122 @@ -28,11 +25,6 @@ public class ManageHotswapCommand extends SubCommand { private final Plan plugin; - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ public ManageHotswapCommand(Plan plugin) { super("hotswap", CommandType.PLAYER_OR_ARGS, @@ -61,12 +53,12 @@ public class ManageHotswapCommand extends SubCommand { return true; } - if (Condition.isTrue(dbName.equals(plugin.getDB().getConfigName()), Locale.get(Msg.MANAGE_FAIL_SAME_DB).toString(), sender)) { + if (Condition.isTrue(dbName.equals(Database.getActive().getConfigName()), Locale.get(Msg.MANAGE_FAIL_SAME_DB).toString(), sender)) { return true; } try { - final Database database = ManageUtils.getDB(dbName); + final Database database = DBSystem.getActiveDatabaseByName(dbName); // If DB is null return if (!Condition.isTrue(Verify.notNull(database), Locale.get(Msg.MANAGE_FAIL_FAULTY_DB).toString(), sender)) { @@ -74,24 +66,19 @@ public class ManageHotswapCommand extends SubCommand { return true; } - assert database != null; - - - database.getVersion(); //Test db connection + if (!database.isOpen()) { + return true; + } } catch (Exception e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); sender.sendMessage(Locale.get(Msg.MANAGE_FAIL_FAULTY_DB).toString()); return true; } - Config config = plugin.getMainConfig(); - config.set(Settings.DB_TYPE.getPath(), dbName); - try { - config.save(); - plugin.reloadPlugin(true); - } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); - } + Settings.DB_TYPE.set(dbName); + + Settings.save(); + plugin.reloadPlugin(true); return true; } } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageImportCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageImportCommand.java index 68fee6e8b..5029a2043 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageImportCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageImportCommand.java @@ -1,10 +1,9 @@ package com.djrapitops.plan.command.commands.manage; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.info.ImporterManager; +import com.djrapitops.plan.system.processing.importing.ImporterManager; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; @@ -13,21 +12,14 @@ import com.djrapitops.plugin.task.AbsRunnable; import com.djrapitops.plugin.task.RunnableFactory; /** - * This manage subcommand is used to import data from 3rd party plugins. - *

- * Supported plugins (v3.0.0) : OnTime + * This manage SubCommand is used to import data from 3rd party plugins. * * @author Rsl1122 * @since 2.3.0 */ public class ManageImportCommand extends SubCommand { - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public ManageImportCommand(Plan plugin) { + public ManageImportCommand() { super("import", CommandType.CONSOLE, Permissions.MANAGE.getPermission(), diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageMoveCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageMoveCommand.java index c09667007..f6ff42b13 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageMoveCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageMoveCommand.java @@ -1,10 +1,10 @@ package com.djrapitops.plan.command.commands.manage; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plan.utilities.ManageUtils; import com.djrapitops.plugin.api.utility.log.Log; @@ -16,7 +16,7 @@ import com.djrapitops.plugin.task.RunnableFactory; import com.djrapitops.plugin.utilities.Verify; /** - * This manage subcommand is used to move all data from one database to another. + * This manage SubCommand is used to move all data from one database to another. *

* Destination database will be cleared. * @@ -25,21 +25,12 @@ import com.djrapitops.plugin.utilities.Verify; */ public class ManageMoveCommand extends SubCommand { - private final Plan plugin; - - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public ManageMoveCommand(Plan plugin) { + public ManageMoveCommand() { super("move", CommandType.PLAYER_OR_ARGS, Permissions.MANAGE.getPermission(), Locale.get(Msg.CMD_USG_MANAGE_MOVE).toString(), " [-a]"); - - this.plugin = plugin; } @Override @@ -71,8 +62,8 @@ public class ManageMoveCommand extends SubCommand { } try { - final Database fromDatabase = ManageUtils.getDB(fromDB); - final Database toDatabase = ManageUtils.getDB(toDB); + final Database fromDatabase = DBSystem.getActiveDatabaseByName(fromDB); + final Database toDatabase = DBSystem.getActiveDatabaseByName(toDB); runMoveTask(fromDatabase, toDatabase, sender); } catch (Exception e) { @@ -90,10 +81,10 @@ public class ManageMoveCommand extends SubCommand { ManageUtils.clearAndCopy(toDatabase, fromDatabase); sender.sendMessage(Locale.get(Msg.MANAGE_INFO_MOVE_SUCCESS).toString()); - boolean movedToCurrentDatabase = Verify.equalsIgnoreCase(toDatabase.getConfigName(), plugin.getDB().getConfigName()); + boolean movedToCurrentDatabase = Verify.equalsIgnoreCase(toDatabase.getConfigName(), Database.getActive().getConfigName()); Condition.isTrue(!movedToCurrentDatabase, Locale.get(Msg.MANAGE_INFO_CONFIG_REMINDER).toString(), sender); } catch (Exception e) { - Log.toLog(this.getClass().getName() + " " + getTaskName(), e); + Log.toLog(this.getClass(), e); sender.sendMessage(Locale.get(Msg.MANAGE_INFO_FAIL).toString()); } finally { this.cancel(); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRemoveCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRemoveCommand.java index 4823bd0a3..2dc0d9ef0 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRemoveCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRemoveCommand.java @@ -1,12 +1,12 @@ package com.djrapitops.plan.command.commands.manage; -import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.database.DBException; import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.cache.SessionCache; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plan.utilities.uuid.UUIDUtility; @@ -19,7 +19,6 @@ import com.djrapitops.plugin.task.RunnableFactory; import com.djrapitops.plugin.utilities.Verify; import org.bukkit.entity.Player; -import java.sql.SQLException; import java.util.UUID; import static org.bukkit.Bukkit.getPlayer; @@ -32,22 +31,12 @@ import static org.bukkit.Bukkit.getPlayer; */ public class ManageRemoveCommand extends SubCommand { - private final Plan plugin; - - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public ManageRemoveCommand(Plan plugin) { + public ManageRemoveCommand() { super("remove", CommandType.PLAYER_OR_ARGS, Permissions.MANAGE.getPermission(), Locale.get(Msg.CMD_USG_MANAGE_REMOVE).toString(), " [-a]"); - - this.plugin = plugin; - } @Override @@ -80,30 +69,29 @@ public class ManageRemoveCommand extends SubCommand { } message = Locale.get(Msg.CMD_FAIL_USERNAME_NOT_KNOWN).toString(); - if (!Condition.isTrue(plugin.getDB().wasSeenBefore(uuid), message, sender)) { + Database database = Database.getActive(); + if (!Condition.isTrue(database.check().isPlayerRegistered(uuid), message, sender)) { return; } - message = Locale.get(Msg.MANAGE_FAIL_CONFIRM).parse(Locale.get(Msg.MANAGE_NOTIFY_REMOVE).parse(plugin.getDB().getConfigName())); + message = Locale.get(Msg.MANAGE_FAIL_CONFIRM).parse(Locale.get(Msg.MANAGE_NOTIFY_REMOVE).parse(Database.getActive().getConfigName())); if (!Condition.isTrue(Verify.contains("-a", args), message, sender)) { return; } sender.sendMessage(Locale.get(Msg.MANAGE_INFO_START).parse()); - try { - plugin.getDB().removeAccount(uuid); - DataCache dataCache = plugin.getDataCache(); - Player player = getPlayer(uuid); - if (player != null) { - SessionCache.getActiveSessions().remove(uuid); - dataCache.cacheSession(uuid, new Session(MiscUtils.getTime(), player.getWorld().getName(), player.getGameMode().name())); - } - sender.sendMessage(Locale.get(Msg.MANAGE_INFO_REMOVE_SUCCESS).parse(playerName, plugin.getDB().getConfigName())); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - sender.sendMessage(Locale.get(Msg.MANAGE_INFO_FAIL).toString()); + database.remove().player(uuid); + + Player player = getPlayer(uuid); + if (player != null) { + SessionCache.getActiveSessions().remove(uuid); + SessionCache.getInstance().cacheSession(uuid, new Session(MiscUtils.getTime(), player.getWorld().getName(), player.getGameMode().name())); } + sender.sendMessage(Locale.get(Msg.MANAGE_INFO_REMOVE_SUCCESS).parse(playerName, Database.getActive().getConfigName())); + } catch (DBException e) { + Log.toLog(this.getClass(), e); + sender.sendMessage(Locale.get(Msg.MANAGE_INFO_FAIL).toString()); } finally { this.cancel(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRestoreCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRestoreCommand.java index b5857ade3..06e2e1485 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRestoreCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageRestoreCommand.java @@ -1,11 +1,12 @@ package com.djrapitops.plan.command.commands.manage; import com.djrapitops.plan.Plan; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.database.databases.SQLiteDB; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.database.databases.sql.SQLiteDB; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plan.utilities.ManageUtils; import com.djrapitops.plugin.api.utility.log.Log; @@ -19,7 +20,7 @@ import com.djrapitops.plugin.utilities.Verify; import java.io.File; /** - * This manage subcommand is used to restore a backup.db file in the + * This manage SubCommand is used to restore a backup.db file in the * /plugins/Plan folder. * * @author Rsl1122 @@ -28,11 +29,6 @@ public class ManageRestoreCommand extends SubCommand { private final Plan plugin; - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ public ManageRestoreCommand(Plan plugin) { super("restore", CommandType.CONSOLE, @@ -61,7 +57,7 @@ public class ManageRestoreCommand extends SubCommand { } try { - final Database database = ManageUtils.getDB(db); + final Database database = DBSystem.getActiveDatabaseByName(db); runRestoreTask(args, sender, database); } catch (Exception e) { @@ -93,13 +89,10 @@ public class ManageRestoreCommand extends SubCommand { sender.sendMessage(Locale.get(Msg.MANAGE_INFO_START).parse()); ManageUtils.clearAndCopy(database, backupDB); - if (database.getConfigName().equals(plugin.getDB().getConfigName())) { -// plugin.getDataCache().getCommandUseFromDb(); - } sender.sendMessage(Locale.get(Msg.MANAGE_INFO_COPY_SUCCESS).toString()); } catch (Exception e) { - Log.toLog(this.getClass().getName() + " " + getTaskName(), e); + Log.toLog(this.getClass(), e); sender.sendMessage(Locale.get(Msg.MANAGE_INFO_FAIL).toString()); } finally { this.cancel(); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageSetupCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageSetupCommand.java index 73931ea71..f1622ff9b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageSetupCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/manage/ManageSetupCommand.java @@ -1,45 +1,33 @@ package com.djrapitops.plan.command.commands.manage; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.api.exceptions.WebAPIForbiddenException; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.webserver.webapi.bungee.RequestSetupWebAPI; +import com.djrapitops.plan.api.exceptions.connection.*; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plan.system.webserver.WebServerSystem; import com.djrapitops.plan.utilities.Condition; -import com.djrapitops.plugin.api.config.Config; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; /** - * This manage subcommand is used to swap to a different database and reload the - * plugin if the connection to the new database can be established. + * This manage SubCommand is used to request settings from Bungee so that connection can be established. * * @author Rsl1122 * @since 2.3.0 */ public class ManageSetupCommand extends SubCommand { - private final Plan plugin; - - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public ManageSetupCommand(Plan plugin) { + public ManageSetupCommand() { super("setup", CommandType.PLAYER_OR_ARGS, Permissions.MANAGE.getPermission(), "Set-Up Bungee WebServer connection", ""); - - this.plugin = plugin; - } @Override @@ -52,31 +40,47 @@ public class ManageSetupCommand extends SubCommand { if (!Condition.isTrue(args.length >= 1, Locale.get(Msg.CMD_FAIL_REQ_ONE_ARG).toString(), sender)) { return true; } - if (!plugin.getWebServer().isEnabled()) { + if (!WebServerSystem.isWebServerEnabled()) { sender.sendMessage("§cWebServer is not enabled on this server! Make sure it enables on boot!"); return true; } String address = args[0].toLowerCase(); - if (!address.startsWith("http")) { + if (!address.startsWith("http") || address.endsWith("://")) { sender.sendMessage("§cMake sure you're using the full address (Starts with http:// or https://) - Check Bungee enable log for the full address."); return true; } if (address.endsWith("/")) { address = address.substring(0, address.length() - 1); } - try { - Config config = plugin.getMainConfig(); - config.set(Settings.BUNGEE_OVERRIDE_STANDALONE_MODE.getPath(), false); - config.set(Settings.BUNGEE_COPY_CONFIG.getPath(), true); -// plugin.getWebServer().getWebAPI().getAPI(PingWebAPI.class).sendRequest(address); - plugin.getWebServer().getWebAPI().getAPI(RequestSetupWebAPI.class).sendRequest(address); - sender.sendMessage("§eConnection successful, Plan may restart in a few seconds, if it doesn't something has gone wrong."); - } catch (WebAPIForbiddenException e) { - sender.sendMessage("§eConnection succeeded, but Bungee has set-up mode disabled - use '/planbungee setup' to enable it."); - } catch (WebAPIException e) { - Log.toLog(this.getClass().getName(), e); - sender.sendMessage("§cConnection to Bungee WebServer failed: More info on console"); - } + + requestSetup(sender, address); + return true; } + + private void requestSetup(ISender sender, String address) { + Processor.queue(() -> { + try { + Settings.BUNGEE_OVERRIDE_STANDALONE_MODE.set(false); + Settings.BUNGEE_COPY_CONFIG.set(true); + + InfoSystem.getInstance().requestSetUp(address); + + sender.sendMessage("§aConnection successful, Plan may restart in a few seconds.."); + } catch (ForbiddenException e) { + sender.sendMessage("§eConnection succeeded, but Bungee has set-up mode disabled - use '/planbungee setup' to enable it."); + } catch (BadRequestException e) { + sender.sendMessage("§eConnection succeeded, but Receiving server was a Bukkit server. Use Bungee address instead."); + } catch (UnauthorizedServerException e) { + sender.sendMessage("§eConnection succeeded, but Receiving server didn't authorize this server. Contact Discord for support"); + } catch (ConnectionFailException e) { + sender.sendMessage("§eConnection failed: " + e.getMessage()); + } catch (InternalErrorException e) { + sender.sendMessage("§eConnection succeeded. " + e.getMessage() + ", check possible ErrorLog on receiving server's debug page."); + } catch (WebException e) { + Log.toLog(this.getClass(), e); + sender.sendMessage("§cConnection to Bungee WebServer failed: More info in the error log."); + } + }); + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebCheckCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebCheckCommand.java index c5864cb86..4723e8a4f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebCheckCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebCheckCommand.java @@ -1,11 +1,10 @@ package com.djrapitops.plan.command.commands.webuser; -import com.djrapitops.plan.api.IPlan; import com.djrapitops.plan.data.WebUser; -import com.djrapitops.plan.database.tables.SecurityTable; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.command.CommandType; @@ -23,15 +22,12 @@ import org.bukkit.ChatColor; */ public class WebCheckCommand extends SubCommand { - private final IPlan plugin; - - public WebCheckCommand(IPlan plugin) { + public WebCheckCommand() { super("check", CommandType.PLAYER_OR_ARGS, Permissions.MANAGE_WEB.getPerm(), Locale.get(Msg.CMD_USG_WEB_CHECK).toString(), ""); - this.plugin = plugin; } @Override @@ -39,20 +35,20 @@ public class WebCheckCommand extends SubCommand { if (!Condition.isTrue(args.length >= 1, Locale.get(Msg.CMD_FAIL_REQ_ONE_ARG).parse() + " ", sender)) { return true; } - SecurityTable table = plugin.getDB().getSecurityTable(); + Database database = Database.getActive(); String user = args[0]; RunnableFactory.createNew(new AbsRunnable("Webuser Check Task: " + user) { @Override public void run() { try { - if (!Condition.isTrue(table.userExists(user), ChatColor.RED + "[Plan] User Doesn't exist.", sender)) { + if (!Condition.isTrue(database.check().doesWebUserExists(user), ChatColor.RED + "[Plan] User Doesn't exist.", sender)) { return; } - WebUser info = table.getWebUser(user); + WebUser info = database.fetch().getWebUser(user); sender.sendMessage(info.getName() + ": Permission level: " + info.getPermLevel()); } catch (Exception ex) { - Log.toLog(this.getClass().getName(), ex); + Log.toLog(this.getClass(), ex); sender.sendMessage(Locale.get(Msg.MANAGE_INFO_FAIL).parse()); } finally { this.cancel(); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebDeleteCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebDeleteCommand.java index 2262b267d..cd383a4be 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebDeleteCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebDeleteCommand.java @@ -1,10 +1,9 @@ package com.djrapitops.plan.command.commands.webuser; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.database.tables.SecurityTable; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.Condition; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.command.CommandType; @@ -22,15 +21,12 @@ import net.md_5.bungee.api.ChatColor; */ public class WebDeleteCommand extends SubCommand { - private final IPlan plugin; - - public WebDeleteCommand(IPlan plugin) { + public WebDeleteCommand() { super("delete, remove", CommandType.PLAYER_OR_ARGS, Permissions.MANAGE_WEB.getPerm(), Locale.get(Msg.CMD_USG_WEB_DELETE).toString(), ""); - this.plugin = plugin; } @Override @@ -38,20 +34,20 @@ public class WebDeleteCommand extends SubCommand { if (!Condition.isTrue(args.length >= 1, Locale.get(Msg.CMD_FAIL_REQ_ONE_ARG).parse() + " ", sender)) { return true; } - SecurityTable table = plugin.getDB().getSecurityTable(); + Database database = Database.getActive(); String user = args[0]; RunnableFactory.createNew(new AbsRunnable("Webuser Delete Task: " + user) { @Override public void run() { try { - if (!Condition.isTrue(table.userExists(user), ChatColor.RED + "[Plan] User Doesn't exist.", sender)) { + if (!Condition.isTrue(database.check().doesWebUserExists(user), ChatColor.RED + "[Plan] User Doesn't exist.", sender)) { return; } - table.removeUser(user); + database.remove().webUser(user); sender.sendMessage(Locale.get(Msg.MANAGE_INFO_SUCCESS).parse()); } catch (Exception ex) { - Log.toLog(this.getClass().getName(), ex); + Log.toLog(this.getClass(), ex); sender.sendMessage(Locale.get(Msg.MANAGE_INFO_FAIL).parse()); } finally { this.cancel(); diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebLevelCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebLevelCommand.java index 879b66476..033f436ac 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebLevelCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebLevelCommand.java @@ -1,9 +1,9 @@ package com.djrapitops.plan.command.commands.webuser; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plugin.command.CommandType; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.SubCommand; @@ -17,9 +17,9 @@ import com.djrapitops.plugin.settings.ColorScheme; */ public class WebLevelCommand extends SubCommand { - private final IPlan plugin; + private final PlanPlugin plugin; - public WebLevelCommand(IPlan plugin) { + public WebLevelCommand(PlanPlugin plugin) { super("level", CommandType.CONSOLE, Permissions.MANAGE_WEB.getPerm(), diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebListUsersCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebListUsersCommand.java index 689b61fe7..ba3ecd59a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebListUsersCommand.java +++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/webuser/WebListUsersCommand.java @@ -1,10 +1,11 @@ package com.djrapitops.plan.command.commands.webuser; -import com.djrapitops.plan.api.IPlan; +import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.data.WebUser; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.comparators.WebUserComparator; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.command.CommandType; @@ -24,9 +25,9 @@ import java.util.List; */ public class WebListUsersCommand extends SubCommand { - private final IPlan plugin; + private final PlanPlugin plugin; - public WebListUsersCommand(IPlan plugin) { + public WebListUsersCommand(PlanPlugin plugin) { super("list", CommandType.CONSOLE, Permissions.MANAGE_WEB.getPerm(), "List registered web users & permission levels."); this.plugin = plugin; } @@ -39,7 +40,7 @@ public class WebListUsersCommand extends SubCommand { try { ColorScheme cs = plugin.getColorScheme(); String mCol = cs.getMainColor(); - List users = plugin.getDB().getSecurityTable().getUsers(); + List users = Database.getActive().fetch().getWebUsers(); users.sort(new WebUserComparator()); sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).parse() + mCol + " WebUsers (" + users.size() + ")"); for (WebUser user : users) { @@ -47,7 +48,7 @@ public class WebListUsersCommand extends SubCommand { } sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).parse()); } catch (Exception ex) { - Log.toLog(this.getClass().getName(), ex); + Log.toLog(this.getClass(), ex); sender.sendMessage(Locale.get(Msg.MANAGE_INFO_FAIL).parse()); } finally { this.cancel(); diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/Actions.java b/Plan/src/main/java/com/djrapitops/plan/data/Actions.java similarity index 94% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/Actions.java rename to Plan/src/main/java/com/djrapitops/plan/data/Actions.java index e243276cf..f7784fe22 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/Actions.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/Actions.java @@ -1,8 +1,8 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.data; import org.apache.commons.lang3.text.WordUtils; diff --git a/Plan/src/main/java/com/djrapitops/plan/data/PlayerProfile.java b/Plan/src/main/java/com/djrapitops/plan/data/PlayerProfile.java index fd75a5773..ba2b84f4d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/PlayerProfile.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/PlayerProfile.java @@ -1,19 +1,19 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan.data; +import com.djrapitops.plan.data.calculation.ActivityIndex; import com.djrapitops.plan.data.container.Action; import com.djrapitops.plan.data.container.GeoInfo; import com.djrapitops.plan.data.container.PlayerKill; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.settings.Settings; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plan.utilities.comparators.ActionComparator; import com.djrapitops.plan.utilities.comparators.GeoInfoComparator; -import com.djrapitops.plugin.api.TimeAmount; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; @@ -57,7 +57,7 @@ public class PlayerProfile implements OfflinePlayer { private Map pluginReplaceMap; // Value that requires lot of processing - private Map activityIndex; + private Map activityIndexCache; public PlayerProfile(UUID uuid, String name, long registered) { this.uuid = uuid; @@ -76,88 +76,59 @@ public class PlayerProfile implements OfflinePlayer { geoInformation = new ArrayList<>(); pluginReplaceMap = new HashMap<>(); - activityIndex = new HashMap<>(); + activityIndexCache = new HashMap<>(); + } + + public static long getPlaytime(Stream s) { + return s.mapToLong(Session::getLength).sum(); + } + + public static long getLongestSession(Stream s) { + OptionalLong longestSession = s.mapToLong(Session::getLength).max(); + if (longestSession.isPresent()) { + return longestSession.getAsLong(); + } + return -1; + } + + public static long getSessionMedian(Stream s) { + List sessionLenghts = s.map(Session::getLength) + .sorted() + .collect(Collectors.toList()); + if (sessionLenghts.isEmpty()) { + return 0; + } + return sessionLenghts.get(sessionLenghts.size() / 2); + } + + public static long getSessionAverage(Stream s) { + OptionalDouble average = s.map(Session::getLength) + .mapToLong(i -> i) + .average(); + if (average.isPresent()) { + return (long) average.getAsDouble(); + } + return 0L; + } + + public static Stream getPlayerKills(Stream s) { + return s.map(Session::getPlayerKills) + .flatMap(Collection::stream); + } + + public static long getDeathCount(Stream s) { + return s.mapToLong(Session::getDeaths) + .sum(); + } + + public static long getMobKillCount(Stream s) { + return s.mapToLong(Session::getMobKills) + .sum(); } // Calculating Getters - public double getActivityIndex(long date) { - Double activityIndx = activityIndex.get(date); - if (activityIndx != null) { - return activityIndx; - } - - long week = TimeAmount.WEEK.ms(); - long weekAgo = date - week; - long twoWeeksAgo = date - 2L * week; - long threeWeeksAgo = date - 3L * week; - - long activePlayThreshold = Settings.ACTIVE_PLAY_THRESHOLD.getNumber() * TimeAmount.MINUTE.ms(); - if (activePlayThreshold <= 0) { - activePlayThreshold = 1; - } - int activeLoginThreshold = Settings.ACTIVE_LOGIN_THRESHOLD.getNumber(); - if (activeLoginThreshold <= 0) { - activeLoginThreshold = 1; - } - - List sessionsWeek = getSessions(weekAgo, date).collect(Collectors.toList()); - List sessionsWeek2 = getSessions(twoWeeksAgo, weekAgo).collect(Collectors.toList()); - List sessionsWeek3 = getSessions(threeWeeksAgo, twoWeeksAgo).collect(Collectors.toList()); - - // Playtime per week multipliers, max out to avoid too high values. - double max = 4.0; - - long playtimeWeek = PlayerProfile.getPlaytime(sessionsWeek.stream()); - double weekPlay = (playtimeWeek * 1.0 / activePlayThreshold); - if (weekPlay > max) { - weekPlay = max; - } - long playtimeWeek2 = PlayerProfile.getPlaytime(sessionsWeek2.stream()); - double week2Play = (playtimeWeek2 * 1.0 / activePlayThreshold); - if (week2Play > max) { - week2Play = max; - } - long playtimeWeek3 = PlayerProfile.getPlaytime(sessionsWeek3.stream()); - double week3Play = (playtimeWeek3 * 1.0 / activePlayThreshold); - if (week3Play > max) { - week3Play = max; - } - - double playtimeMultiplier = 1.0; - if (playtimeWeek + playtimeWeek2 + playtimeWeek3 > activeLoginThreshold * 3.0) { - playtimeMultiplier = 1.25; - } - - // Reduce the harshness for new players and players who have had a vacation - if (weekPlay > 1 && week3Play > 1 && week2Play == 0.0) { - week2Play = 0.5; - } - if (weekPlay > 1 && week2Play == 0.0) { - week2Play = 0.6; - } - if (weekPlay > 1 && week3Play == 0.0) { - week3Play = 0.75; - } - - double playAvg = (weekPlay + week2Play + week3Play) / 3.0; - - double weekLogin = sessionsWeek.size() >= activeLoginThreshold ? 1.0 : 0.5; - double week2Login = sessionsWeek2.size() >= activeLoginThreshold ? 1.0 : 0.5; - double week3Login = sessionsWeek3.size() >= activeLoginThreshold ? 1.0 : 0.5; - - double loginMultiplier = 1.0; - double loginTotal = weekLogin + week2Login + week3Login; - double loginAvg = loginTotal / 3.0; - - if (loginTotal <= 2.0) { - // Reduce index for players that have not logged in the threshold amount for 2 weeks - loginMultiplier = 0.75; - } - - activityIndx = playAvg * loginAvg * loginMultiplier * playtimeMultiplier; - activityIndex.put(date, activityIndx); - - return activityIndx; + public ActivityIndex getActivityIndex(long date) { + return activityIndexCache.computeIfAbsent(date, dateValue -> new ActivityIndex(this, dateValue)); } /** @@ -169,6 +140,10 @@ public class PlayerProfile implements OfflinePlayer { return worldTimesMap.getOrDefault(null, new WorldTimes(new HashMap<>())); } + public void setWorldTimes(Map worldTimes) { + worldTimesMap.putAll(worldTimes); + } + /** * Get world times per server for this player. * @@ -202,8 +177,7 @@ public class PlayerProfile implements OfflinePlayer { } public long getLastSeen(Stream s) { - OptionalLong max = s.mapToLong(Session::getSessionEnd) - .max(); + OptionalLong max = s.mapToLong(session -> Math.max(session.getSessionStart(), session.getSessionEnd())).max(); if (max.isPresent()) { return max.getAsLong(); } @@ -222,12 +196,6 @@ public class PlayerProfile implements OfflinePlayer { return getPlaytime(getSessions(serverUUID).stream()); } - public static long getPlaytime(Stream s) { - return s.map(Session::getLength) - .mapToLong(i -> i) - .sum(); - } - public long getLongestSession() { return getLongestSession(-1, MiscUtils.getTime() + 1L); } @@ -240,16 +208,6 @@ public class PlayerProfile implements OfflinePlayer { return getLongestSession(getSessions(serverUUID).stream()); } - public static long getLongestSession(Stream s) { - OptionalLong longestSession = s.map(Session::getLength) - .mapToLong(i -> i) - .max(); - if (longestSession.isPresent()) { - return longestSession.getAsLong(); - } - return -1; - } - public long getSessionMedian() { return getSessionMedian(-1, MiscUtils.getTime() + 1L); } @@ -262,15 +220,7 @@ public class PlayerProfile implements OfflinePlayer { return getSessionMedian(getSessions(serverUUID).stream()); } - public static long getSessionMedian(Stream s) { - List sessionLenghts = s.map(Session::getLength) - .sorted() - .collect(Collectors.toList()); - if (sessionLenghts.isEmpty()) { - return 0; - } - return sessionLenghts.get(sessionLenghts.size() / 2); - } + // Special Getters public long getSessionAverage() { return getSessionAverage(-1, MiscUtils.getTime() + 1L); @@ -284,22 +234,10 @@ public class PlayerProfile implements OfflinePlayer { return getSessionAverage(getSessions(serverUUID).stream()); } - public static long getSessionAverage(Stream s) { - OptionalDouble average = s.map(Session::getLength) - .mapToLong(i -> i) - .average(); - if (average.isPresent()) { - return (long) average.getAsDouble(); - } - return 0L; - } - public boolean playedBetween(long after, long before) { return getSessions(after, before).findFirst().isPresent(); } - // Special Getters - public Stream getAllSessions() { return sessions.values().stream().flatMap(Collection::stream); } @@ -332,11 +270,6 @@ public class PlayerProfile implements OfflinePlayer { return getPlayerKills(getSessions(serverUUID).stream()); } - public static Stream getPlayerKills(Stream s) { - return s.map(Session::getPlayerKills) - .flatMap(Collection::stream); - } - public long getPlayerKillCount() { return getPlayerKills().count(); } @@ -353,11 +286,6 @@ public class PlayerProfile implements OfflinePlayer { return getDeathCount(getSessions(serverUUID).stream()); } - public static long getDeathCount(Stream s) { - return s.mapToLong(Session::getDeaths) - .sum(); - } - public long getMobKillCount() { return getMobKillCount(getAllSessions()); } @@ -366,11 +294,6 @@ public class PlayerProfile implements OfflinePlayer { return getMobKillCount(getSessions(serverUUID).stream()); } - public static long getMobKillCount(Stream s) { - return s.mapToLong(Session::getMobKills) - .sum(); - } - public long getSessionCount() { return getAllSessions().count(); } @@ -379,12 +302,12 @@ public class PlayerProfile implements OfflinePlayer { return getSessions(serverUUID).size(); } + // Setters & Adders + public long getRegistered(UUID serverUUID) { return registeredMap.getOrDefault(serverUUID, -1L); } - // Setters & Adders - public void bannedOnServer(UUID serverUUID) { bannedOnServers.add(serverUUID); } @@ -405,12 +328,8 @@ public class PlayerProfile implements OfflinePlayer { this.sessions.put(serverUUID, sessions); } - public void setSessions(Map> sessions) { - this.sessions.putAll(sessions); - } - public void addActiveSession(Session activeSession) { - UUID serverUUID = MiscUtils.getIPlan().getServerUuid(); + UUID serverUUID = ServerInfo.getServerUUID(); List sessions = getSessions(serverUUID); sessions.add(activeSession); this.sessions.put(serverUUID, sessions); @@ -428,10 +347,6 @@ public class PlayerProfile implements OfflinePlayer { worldTimesMap.put(serverUUID, worldTimes); } - public void setWorldTimes(Map worldTimes) { - worldTimesMap.putAll(worldTimes); - } - public void setTotalWorldTimes(WorldTimes worldTimes) { worldTimesMap.put(null, worldTimes); } @@ -440,42 +355,39 @@ public class PlayerProfile implements OfflinePlayer { registeredMap.put(serverUUID, registered); } + public int getTimesKicked() { + return timesKicked; + } + // Default Setters - public void setActions(List actions) { - this.actions = actions; - } - - public void setNicknames(Map> nicknames) { - this.nicknames = nicknames; - } - - public void setGeoInformation(List geoInformation) { - this.geoInformation = geoInformation; - } - public void setTimesKicked(int timesKicked) { this.timesKicked = timesKicked; } - // Default Getters - - public int getTimesKicked() { - return timesKicked; - } - public Map> getNicknames() { return nicknames; } + public void setNicknames(Map> nicknames) { + this.nicknames = nicknames; + } + public List getGeoInformation() { return geoInformation; } + // Default Getters + + public void setGeoInformation(List geoInformation) { + this.geoInformation = geoInformation; + } + public UUID getUuid() { return uuid; } + @Override public String getName() { return name; } @@ -496,10 +408,18 @@ public class PlayerProfile implements OfflinePlayer { return sessions; } + public void setSessions(Map> sessions) { + this.sessions.putAll(sessions); + } + public List getActions() { return actions; } + public void setActions(List actions) { + this.actions = actions; + } + public Map getPluginReplaceMap() { return pluginReplaceMap; } @@ -553,7 +473,7 @@ public class PlayerProfile implements OfflinePlayer { @Override public long getLastPlayed() { - return getLastSeen(MiscUtils.getIPlan().getServerUuid()); + return getLastSeen(ServerInfo.getServerUUID()); } @Override @@ -573,7 +493,7 @@ public class PlayerProfile implements OfflinePlayer { @Override public boolean isOp() { - return oppedOnServers.contains(MiscUtils.getIPlan().getServerUuid()); + return oppedOnServers.contains(ServerInfo.getServerUUID()); } @Override @@ -582,7 +502,7 @@ public class PlayerProfile implements OfflinePlayer { } public void calculateWorldTimesPerServer() { - if (worldTimesMap.containsKey(MiscUtils.getIPlan().getServerUuid())) { + if (worldTimesMap.containsKey(ServerInfo.getServerUUID())) { return; } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/ServerProfile.java b/Plan/src/main/java/com/djrapitops/plan/data/ServerProfile.java index 09fde3939..b0144671e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/ServerProfile.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/ServerProfile.java @@ -1,24 +1,20 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan.data; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.PlanBungee; import com.djrapitops.plan.data.container.GeoInfo; import com.djrapitops.plan.data.container.PlayerKill; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.container.TPS; import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.system.settings.Settings; import com.djrapitops.plan.utilities.analysis.AnalysisUtils; import com.djrapitops.plan.utilities.analysis.MathUtils; import com.djrapitops.plan.utilities.comparators.PlayerProfileLastPlayedComparator; import com.djrapitops.plan.utilities.comparators.TPSComparator; import com.djrapitops.plan.utilities.html.tables.PlayersTableCreator; -import com.djrapitops.plugin.api.Check; import com.djrapitops.plugin.api.TimeAmount; import java.util.*; @@ -64,6 +60,113 @@ public class ServerProfile { lastPeakPlayers = -1; } + public static long getLowSpikeCount(List tpsData) { + int mediumThreshold = Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber(); + + boolean wasLow = false; + long spikeCount = 0L; + + for (TPS tpsObj : tpsData) { + double tps = tpsObj.getTicksPerSecond(); + if (tps < mediumThreshold) { + if (!wasLow) { + spikeCount++; + wasLow = true; + } + } else { + wasLow = false; + } + } + + return spikeCount; + } + + public static List getPlayerKills(List s) { + List kills = new ArrayList<>(); + for (Session session : s) { + kills.addAll(session.getPlayerKills()); + } + return kills; + } + + public static long getMobKillCount(List s) { + long total = 0; + for (Session session : s) { + total += session.getMobKills(); + } + return total; + } + + public static long getDeathCount(List s) { + long total = 0; + for (Session session : s) { + total += session.getDeaths(); + } + return total; + } + + public static long serverDownTime(List tpsData) { + long lastDate = -1; + long downTime = 0; + for (TPS tps : tpsData) { + long date = tps.getDate(); + if (lastDate == -1) { + lastDate = date; + continue; + } + + long diff = date - lastDate; + if (diff > TimeAmount.MINUTE.ms() * 3L) { + downTime += diff; + } + lastDate = date; + } + + return downTime; + } + + public static long serverIdleTime(List tpsData) { + long lastDate = -1; + int lastPlayers = 0; + long idleTime = 0; + for (TPS tps : tpsData) { + long date = tps.getDate(); + int players = tps.getPlayers(); + if (lastDate == -1) { + lastDate = date; + lastPlayers = players; + continue; + } + + long diff = date - lastDate; + if (lastPlayers == 0 && players == 0) { + idleTime += diff; + } + + lastDate = date; + lastPlayers = players; + } + + return idleTime; + } + + public static double aboveLowThreshold(List tpsData) { + if (tpsData.isEmpty()) { + return 1; + } + + int threshold = Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber(); + + long count = 0; + for (TPS tps : tpsData) { + if (tps.getTicksPerSecond() >= threshold) { + count++; + } + } + + return count * 1.0 / tpsData.size(); + } + public List getPlayers() { return players; } @@ -88,27 +191,6 @@ public class ServerProfile { this.commandUsage = commandUsage; } - public static long getLowSpikeCount(List tpsData) { - int mediumThreshold = Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber(); - - boolean wasLow = false; - long spikeCount = 0L; - - for (TPS tpsObj : tpsData) { - double tps = tpsObj.getTicksPerSecond(); - if (tps < mediumThreshold) { - if (!wasLow) { - spikeCount++; - wasLow = true; - } - } else { - wasLow = false; - } - } - - return spikeCount; - } - public double getAverageTPS(long after, long before) { OptionalDouble average = getTPSData(after, before) .mapToDouble(TPS::getTicksPerSecond) @@ -200,6 +282,8 @@ public class ServerProfile { .collect(Collectors.toList()); } + // Default setters & getters + public long getTotalPlaytime() { return serverWorldtimes.getTotal(); } @@ -220,32 +304,6 @@ public class ServerProfile { return players.stream().map(p -> p.getSessions(serverUUID)).flatMap(Collection::stream).collect(Collectors.toList()); } - public static List getPlayerKills(List s) { - List kills = new ArrayList<>(); - for (Session session : s) { - kills.addAll(session.getPlayerKills()); - } - return kills; - } - - public static long getMobKillCount(List s) { - long total = 0; - for (Session session : s) { - total += session.getMobKills(); - } - return total; - } - - public static long getDeathCount(List s) { - long total = 0; - for (Session session : s) { - total += session.getDeaths(); - } - return total; - } - - // Default setters & getters - public WorldTimes getServerWorldtimes() { return serverWorldtimes; } @@ -286,18 +344,6 @@ public class ServerProfile { this.allTimePeakPlayers = allTimePeakPlayers; } - public static int getPlayersOnline() { - if (Check.isBungeeAvailable()) { - return PlanBungee.getInstance().getProxy().getOnlineCount(); - } else { - return Plan.getInstance().getServer().getOnlinePlayers().size(); - } - } - - public static int getPlayersMax() { - return MiscUtils.getIPlan().getVariable().getMaxPlayers(); - } - public Stream getOps() { return players.stream().filter(PlayerProfile::isOp); } @@ -316,74 +362,12 @@ public class ServerProfile { .collect(Collectors.toList())); } - public static long serverDownTime(List tpsData) { - long lastDate = -1; - long downTime = 0; - for (TPS tps : tpsData) { - long date = tps.getDate(); - if (lastDate == -1) { - lastDate = date; - continue; - } - - long diff = date - lastDate; - if (diff > TimeAmount.MINUTE.ms() * 3L) { - downTime += diff; - } - lastDate = date; - } - - return downTime; - } - public long serverIdleTime(long after, long before) { return serverIdleTime(getTPSData(after, before) .sorted(new TPSComparator()) .collect(Collectors.toList())); } - public static long serverIdleTime(List tpsData) { - long lastDate = -1; - int lastPlayers = 0; - long idleTime = 0; - for (TPS tps : tpsData) { - long date = tps.getDate(); - int players = tps.getPlayers(); - if (lastDate == -1) { - lastDate = date; - lastPlayers = players; - continue; - } - - long diff = date - lastDate; - if (lastPlayers == 0 && players == 0) { - idleTime += diff; - } - - lastDate = date; - lastPlayers = players; - } - - return idleTime; - } - - public static double aboveLowThreshold(List tpsData) { - if (tpsData.isEmpty()) { - return 1; - } - - int threshold = Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber(); - - long count = 0; - for (TPS tps : tpsData) { - if (tps.getTicksPerSecond() >= threshold) { - count++; - } - } - - return count * 1.0 / tpsData.size(); - } - public PlayerProfile getPlayer(UUID uuid) { if (playerMap == null) { playerMap = players.stream().collect(Collectors.toMap(PlayerProfile::getUuid, Function.identity())); diff --git a/Plan/src/main/java/com/djrapitops/plan/data/calculation/ActivityIndex.java b/Plan/src/main/java/com/djrapitops/plan/data/calculation/ActivityIndex.java new file mode 100644 index 000000000..9b26a6ce8 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/calculation/ActivityIndex.java @@ -0,0 +1,133 @@ +package com.djrapitops.plan.data.calculation; + +import com.djrapitops.plan.data.PlayerProfile; +import com.djrapitops.plan.data.container.Session; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.utilities.FormatUtils; +import com.djrapitops.plugin.api.TimeAmount; + +import java.util.List; +import java.util.stream.Collectors; + +public class ActivityIndex { + + private final double value; + + public ActivityIndex(PlayerProfile player, long date) { + value = calculate(player, date); + } + + public static String[] getGroups() { + return new String[]{"Very Active", "Active", "Regular", "Irregular", "Inactive"}; + } + + private long loadSetting(long value) { + return value <= 0 ? 1 : value; + } + + private int loadSetting(int value) { + return value <= 0 ? 1 : value; + } + + private double calculate(PlayerProfile player, long date) { + long week = TimeAmount.WEEK.ms(); + long weekAgo = date - week; + long twoWeeksAgo = date - 2L * week; + long threeWeeksAgo = date - 3L * week; + + long activePlayThreshold = loadSetting(Settings.ACTIVE_PLAY_THRESHOLD.getNumber() * TimeAmount.MINUTE.ms()); + int activeLoginThreshold = loadSetting(Settings.ACTIVE_LOGIN_THRESHOLD.getNumber()); + + List sessionsWeek = player.getSessions(weekAgo, date).collect(Collectors.toList()); + List sessionsWeek2 = player.getSessions(twoWeeksAgo, weekAgo).collect(Collectors.toList()); + List sessionsWeek3 = player.getSessions(threeWeeksAgo, twoWeeksAgo).collect(Collectors.toList()); + + // Playtime per week multipliers, max out to avoid too high values. + double max = 4.0; + + long playtimeWeek = PlayerProfile.getPlaytime(sessionsWeek.stream()); + double weekPlay = (playtimeWeek * 1.0 / activePlayThreshold); + if (weekPlay > max) { + weekPlay = max; + } + long playtimeWeek2 = PlayerProfile.getPlaytime(sessionsWeek2.stream()); + double week2Play = (playtimeWeek2 * 1.0 / activePlayThreshold); + if (week2Play > max) { + week2Play = max; + } + long playtimeWeek3 = PlayerProfile.getPlaytime(sessionsWeek3.stream()); + double week3Play = (playtimeWeek3 * 1.0 / activePlayThreshold); + if (week3Play > max) { + week3Play = max; + } + + double playtimeMultiplier = 1.0; + if (playtimeWeek + playtimeWeek2 + playtimeWeek3 > activePlayThreshold * 3.0) { + playtimeMultiplier = 1.25; + } + + // Reduce the harshness for new players and players who have had a vacation + if (weekPlay > 1 && week3Play > 1 && week2Play == 0.0) { + week2Play = 0.5; + } + if (weekPlay > 1 && week2Play == 0.0) { + week2Play = 0.6; + } + if (weekPlay > 1 && week3Play == 0.0) { + week3Play = 0.75; + } + + double playAvg = (weekPlay + week2Play + week3Play) / 3.0; + + double weekLogin = sessionsWeek.size() >= activeLoginThreshold ? 1.0 : 0.5; + double week2Login = sessionsWeek2.size() >= activeLoginThreshold ? 1.0 : 0.5; + double week3Login = sessionsWeek3.size() >= activeLoginThreshold ? 1.0 : 0.5; + + double loginMultiplier = 1.0; + double loginTotal = weekLogin + week2Login + week3Login; + double loginAvg = loginTotal / 3.0; + + if (loginTotal <= 2.0) { + // Reduce index for players that have not logged in the threshold amount for 2 weeks + loginMultiplier = 0.75; + } + + return playAvg * loginAvg * loginMultiplier * playtimeMultiplier; + } + + public double getValue() { + return value; + } + + public String getFormattedValue() { + return FormatUtils.cutDecimals(value); + } + + public String getGroup() { + if (value >= 3.5) { + return "Very Active"; + } else if (value >= 1.75) { + return "Active"; + } else if (value >= 1.0) { + return "Regular"; + } else if (value >= 0.5) { + return "Irregular"; + } else { + return "Inactive"; + } + } + + public String getColor() { + if (value >= 3.5) { + return "green"; + } else if (value >= 1.75) { + return "green"; + } else if (value >= 1.0) { + return "lime"; + } else if (value >= 0.5) { + return "amber"; + } else { + return "blue-gray"; + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/data/AnalysisData.java b/Plan/src/main/java/com/djrapitops/plan/data/calculation/AnalysisData.java similarity index 89% rename from Plan/src/main/java/com/djrapitops/plan/data/AnalysisData.java rename to Plan/src/main/java/com/djrapitops/plan/data/calculation/AnalysisData.java index 3aee89fa3..d5f2ed561 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/AnalysisData.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/calculation/AnalysisData.java @@ -1,22 +1,25 @@ -package com.djrapitops.plan.data; +package com.djrapitops.plan.data.calculation; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.data.PlayerProfile; +import com.djrapitops.plan.data.ServerProfile; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.container.StickyData; import com.djrapitops.plan.data.container.TPS; import com.djrapitops.plan.data.element.AnalysisContainer; -import com.djrapitops.plan.data.element.HealthNotes; import com.djrapitops.plan.data.plugin.PluginData; import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.settings.theme.ThemeVal; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.info.server.ServerProperties; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.ThemeVal; import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plan.utilities.analysis.AnalysisUtils; import com.djrapitops.plan.utilities.analysis.MathUtils; import com.djrapitops.plan.utilities.comparators.SessionStartComparator; import com.djrapitops.plan.utilities.html.Html; -import com.djrapitops.plan.utilities.html.HtmlUtils; import com.djrapitops.plan.utilities.html.graphs.ActivityStackGraph; import com.djrapitops.plan.utilities.html.graphs.PunchCardGraph; import com.djrapitops.plan.utilities.html.graphs.WorldMap; @@ -25,7 +28,7 @@ import com.djrapitops.plan.utilities.html.graphs.pie.ActivityPie; import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie; import com.djrapitops.plan.utilities.html.structure.AnalysisPluginsTabContentCreator; import com.djrapitops.plan.utilities.html.structure.SessionTabStructureCreator; -import com.djrapitops.plan.utilities.html.tables.CommandUseTableCreator; +import com.djrapitops.plan.utilities.html.tables.CommandUseTable; import com.djrapitops.plan.utilities.html.tables.SessionsTableCreator; import com.djrapitops.plugin.api.TimeAmount; @@ -66,12 +69,12 @@ public class AnalysisData extends RawData { } private void addConstants() { - addValue("version", MiscUtils.getIPlan().getVersion()); + addValue("version", PlanPlugin.getInstance().getVersion()); addValue("worldPieColors", Theme.getValue(ThemeVal.GRAPH_WORLD_PIE)); addValue("gmPieColors", Theme.getValue(ThemeVal.GRAPH_GM_PIE)); addValue("serverName", Settings.SERVER_NAME.toString().replaceAll("[^a-zA-Z0-9_\\s]", "_")); addValue("timeZone", MiscUtils.getTimeZoneOffsetHours()); - addValue("refresh", FormatUtils.formatTimeStamp(refreshDate)); + addValue("refresh", FormatUtils.formatTimeStampClock(refreshDate)); addValue("activityPieColors", Theme.getValue(ThemeVal.GRAPH_ACTIVITY_PIE)); addValue("playersGraphColor", Theme.getValue(ThemeVal.GRAPH_PLAYERS_ONLINE)); @@ -83,12 +86,9 @@ public class AnalysisData extends RawData { addValue("tpsMedium", Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber()); addValue("tpsHigh", Settings.THEME_GRAPH_TPS_THRESHOLD_HIGH.getNumber()); - addValue("playersMax", ServerProfile.getPlayersMax()); - addValue("playersOnline", ServerProfile.getPlayersOnline()); - } - - public long getRefreshDate() { - return refreshDate; + ServerProperties serverProperties = ServerInfo.getServerProperties(); + addValue("playersMax", serverProperties.getMaxPlayers()); + addValue("playersOnline", serverProperties.getOnlinePlayers()); } public void analyze(ServerProfile profile) { @@ -143,11 +143,11 @@ public class AnalysisData extends RawData { Map> activityNow = activityData.getOrDefault(now, new HashMap<>()); - String[] activityStackSeries = ActivityStackGraph.createSeries(activityData); - String activityPieSeries = ActivityPie.createSeries(activityNow); + ActivityStackGraph activityStackGraph = new ActivityStackGraph(activityData); + String activityPieSeries = new ActivityPie(activityNow).toHighChartsSeries(); - addValue("activityStackCategories", activityStackSeries[0]); - addValue("activityStackSeries", activityStackSeries[1]); + addValue("activityStackCategories", activityStackGraph.toHighChartsLabels()); + addValue("activityStackSeries", activityStackGraph.toHighChartsSeries()); addValue("activityPieSeries", activityPieSeries); Set veryActiveNow = activityNow.getOrDefault("Very Active", new HashSet<>()); @@ -166,11 +166,11 @@ public class AnalysisData extends RawData { private void commandUsage(Map commandUsage) { addValue("commandUniqueCount", String.valueOf(commandUsage.size())); addValue("commandCount", MathUtils.sumInt(commandUsage.values().stream().map(i -> (int) i))); - addValue("tableBodyCommands", HtmlUtils.removeXSS(CommandUseTableCreator.createTable(commandUsage))); + addValue("tableBodyCommands", new CommandUseTable(commandUsage).parseBody()); } private void geolocationsTab(List geoLocations) { - addValue("geoMapSeries", WorldMap.createSeries(geoLocations)); + addValue("geoMapSeries", new WorldMap(geoLocations).toHighChartsSeries()); } private void onlineActivityNumbers(ServerProfile profile, Map> sessions, List players) { @@ -285,7 +285,7 @@ public class AnalysisData extends RawData { addValue("tableBodySessions", tables[0]); addValue("listRecentLogins", tables[1]); addValue("sessionAverage", FormatUtils.formatTimeAmount(MathUtils.averageLong(allSessions.stream().map(Session::getLength)))); - addValue("punchCardSeries", PunchCardGraph.createSeries(sessionsMonth)); + addValue("punchCardSeries", new PunchCardGraph(sessionsMonth).toHighChartsSeries()); addValue("deaths", ServerProfile.getDeathCount(allSessions)); addValue("mobKillCount", ServerProfile.getMobKillCount(allSessions)); @@ -302,9 +302,9 @@ public class AnalysisData extends RawData { Html.TABLE_PLAYERS_FOOTER.parse(playersTableBody) : Html.TABLE_PLAYERS.parse(playersTableBody)); addValue("worldTotal", FormatUtils.formatTimeAmount(worldTimes.getTotal())); - String[] seriesData = WorldPie.createSeries(worldTimes); - addValue("worldSeries", seriesData[0]); - addValue("gmSeries", seriesData[1]); + WorldPie worldPie = new WorldPie(worldTimes); + addValue("worldSeries", worldPie.toHighChartsSeries()); + addValue("gmSeries", worldPie.toHighChartsDrilldown()); addValue("lastPeakTime", lastPeak != -1 ? FormatUtils.formatTimeStampYear(lastPeak) : "No Data"); addValue("playersLastPeak", lastPeak != -1 ? profile.getLastPeakPlayers() : "-"); addValue("bestPeakTime", allTimePeak != -1 ? FormatUtils.formatTimeStampYear(allTimePeak) : "No Data"); @@ -319,12 +319,12 @@ public class AnalysisData extends RawData { addValue("tpsSpikeWeek", value("tpsSpikeWeek")); addValue("tpsSpikeDay", value("tpsSpikeDay")); - addValue("playersOnlineSeries", PlayerActivityGraph.createSeries(tpsData)); - addValue("tpsSeries", TPSGraph.createSeries(tpsData)); - addValue("cpuSeries", CPUGraph.createSeries(tpsData)); - addValue("ramSeries", RamGraph.createSeries(tpsData)); - addValue("entitySeries", WorldLoadGraph.createSeriesEntities(tpsData)); - addValue("chunkSeries", WorldLoadGraph.createSeriesChunks(tpsData)); + addValue("playersOnlineSeries", new OnlineActivityGraph(tpsData).toHighChartsSeries()); + addValue("tpsSeries", new TPSGraph(tpsData).toHighChartsSeries()); + addValue("cpuSeries", new CPUGraph(tpsData).toHighChartsSeries()); + addValue("ramSeries", new RamGraph(tpsData).toHighChartsSeries()); + addValue("entitySeries", new EntityGraph(tpsData).toHighChartsSeries()); + addValue("chunkSeries", new ChunkGraph(tpsData).toHighChartsSeries()); double averageCPUMonth = MathUtils.averageDouble(tpsDataMonth.stream().map(TPS::getCPUUsage).filter(i -> i != 0)); double averageCPUWeek = MathUtils.averageDouble(tpsDataWeek.stream().map(TPS::getCPUUsage).filter(i -> i != 0)); diff --git a/Plan/src/main/java/com/djrapitops/plan/data/element/HealthNotes.java b/Plan/src/main/java/com/djrapitops/plan/data/calculation/HealthNotes.java similarity index 83% rename from Plan/src/main/java/com/djrapitops/plan/data/element/HealthNotes.java rename to Plan/src/main/java/com/djrapitops/plan/data/calculation/HealthNotes.java index 968596494..b42027db3 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/element/HealthNotes.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/calculation/HealthNotes.java @@ -2,14 +2,13 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.data.element; +package com.djrapitops.plan.data.calculation; -import com.djrapitops.plan.data.AnalysisData; import com.djrapitops.plan.data.PlayerProfile; import com.djrapitops.plan.data.ServerProfile; import com.djrapitops.plan.data.container.StickyData; import com.djrapitops.plan.data.container.TPS; -import com.djrapitops.plan.settings.Settings; +import com.djrapitops.plan.system.settings.Settings; import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.analysis.MathUtils; import com.djrapitops.plan.utilities.html.Html; @@ -25,17 +24,16 @@ import java.util.stream.Collectors; */ public class HealthNotes { - private final List healthNotes; - private double serverHealth; - + private final List notes; private final AnalysisData analysisData; - private final TreeMap>> activityData; + private final SortedMap>> activityData; private final List tpsDataMonth; private final long now; private final long fourWeeksAgo; + private double serverHealth; - public HealthNotes(AnalysisData analysisData, TreeMap>> activityData, List tpsDataMonth, long now) { - this.healthNotes = new ArrayList<>(); + public HealthNotes(AnalysisData analysisData, SortedMap>> activityData, List tpsDataMonth, long now) { + this.notes = new ArrayList<>(); serverHealth = 100.0; this.analysisData = analysisData; @@ -54,7 +52,7 @@ public class HealthNotes { public String parse() { StringBuilder healthNoteBuilder = new StringBuilder(); - for (String healthNote : healthNotes) { + for (String healthNote : notes) { healthNoteBuilder.append(healthNote); } return healthNoteBuilder.toString(); @@ -107,20 +105,20 @@ public class HealthNotes { + remain + "/" + activeFWAGNum + ")"; } if (change > 0) { - healthNotes.add( + notes.add( "

" + Html.GREEN_THUMB.parse() + " Number of regular players has increased (+" + change + ")
" + remainNote + "

"); } else if (change == 0) { - healthNotes.add( + notes.add( "

" + Html.GREEN_THUMB.parse() + " Number of regular players has stayed the same (+" + change + ")
" + remainNote + "

"); } else if (change > -20) { - healthNotes.add( + notes.add( "

" + Html.YELLOW_FLAG.parse() + " Number of regular players has decreased (" + change + ")
" + remainNote + "

"); serverHealth -= 5; } else { - healthNotes.add( + notes.add( "

" + Html.RED_WARN.parse() + " Number of regular players has decreased (" + change + ")
" + remainNote + "

"); serverHealth -= 10; @@ -130,10 +128,10 @@ public class HealthNotes { private void newPlayerNote() { double avgOnlineOnRegister = MathUtils.averageInt(analysisData.getStickyMonthData().stream().map(StickyData::getOnlineOnJoin)); if (avgOnlineOnRegister >= 1) { - healthNotes.add("

" + Html.GREEN_THUMB.parse() + " New Players have players to play with when they join (" + notes.add("

" + Html.GREEN_THUMB.parse() + " New Players have players to play with when they join (" + FormatUtils.cutDecimals(avgOnlineOnRegister) + " on average)

"); } else { - healthNotes.add("

" + Html.YELLOW_FLAG.parse() + " New Players may not have players to play with when they join (" + notes.add("

" + Html.YELLOW_FLAG.parse() + " New Players may not have players to play with when they join (" + FormatUtils.cutDecimals(avgOnlineOnRegister) + " on average)

"); serverHealth -= 5; } @@ -144,10 +142,10 @@ public class HealthNotes { if (newM != 0) { double stuckPerc = MathUtils.averageDouble(stuckPerM, newM) * 100; if (stuckPerc >= 25) { - healthNotes.add("

" + Html.GREEN_THUMB.parse() + " " + FormatUtils.cutDecimals(stuckPerc) + notes.add("

" + Html.GREEN_THUMB.parse() + " " + FormatUtils.cutDecimals(stuckPerc) + "% of new players have stuck around (" + stuckPerM + "/" + newM + ")

"); } else { - healthNotes.add("

" + Html.YELLOW_FLAG.parse() + " " + FormatUtils.cutDecimals(stuckPerc) + notes.add("

" + Html.YELLOW_FLAG.parse() + " " + FormatUtils.cutDecimals(stuckPerc) + "% of new players have stuck around (" + stuckPerM + "/" + newM + ")

"); } } @@ -155,7 +153,7 @@ public class HealthNotes { private void activePlayerPlaytimeChange() { List currentActivePlayers = analysisData.getPlayers().stream() - .filter(player -> player.getActivityIndex(now) >= 1.75) + .filter(player -> player.getActivityIndex(now).getValue() >= 1.75) .collect(Collectors.toList()); long twoWeeksAgo = now - TimeAmount.WEEK.ms() * 2L; @@ -173,16 +171,16 @@ public class HealthNotes { String avgLastTwoWeeksString = FormatUtils.formatTimeAmount(avgLastTwoWeeks); String avgFourToTwoWeeksString = FormatUtils.formatTimeAmount(avgFourToTwoWeeks); if (avgFourToTwoWeeks >= avgLastTwoWeeks) { - healthNotes.add("

" + Html.GREEN_THUMB.parse() + " Active players seem to have things to do (Played " + notes.add("

" + Html.GREEN_THUMB.parse() + " Active players seem to have things to do (Played " + avgLastTwoWeeksString + " vs " + avgFourToTwoWeeksString + ", last two weeks vs weeks 2-4)

"); } else if (avgFourToTwoWeeks - avgLastTwoWeeks > TimeAmount.HOUR.ms() * 2L) { - healthNotes.add("

" + Html.RED_WARN.parse() + " Active players might be running out of things to do (Played " + notes.add("

" + Html.RED_WARN.parse() + " Active players might be running out of things to do (Played " + avgLastTwoWeeksString + " vs " + avgFourToTwoWeeksString + ", last two weeks vs weeks 2-4)

"); serverHealth -= 5; } else { - healthNotes.add("

" + Html.YELLOW_FLAG.parse() + " Active players might be running out of things to do (Played " + notes.add("

" + Html.YELLOW_FLAG.parse() + " Active players might be running out of things to do (Played " + avgLastTwoWeeksString + " vs " + avgFourToTwoWeeksString + ", last two weeks vs weeks 2-4)

"); } @@ -208,18 +206,18 @@ public class HealthNotes { + FormatUtils.cutDecimals(aboveThreshold * 100.0) + "% of the time"; if (tpsSpikeMonth <= 5) { - healthNotes.add("

" + Html.GREEN_THUMB.parse() + notes.add("

" + Html.GREEN_THUMB.parse() + " Average TPS dropped below Low Threshold (" + Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber() + ")" + " " + tpsSpikeMonth + " times
" + avgLowThresholdString + "

"); } else if (tpsSpikeMonth <= 25) { - healthNotes.add("

" + Html.YELLOW_FLAG.parse() + notes.add("

" + Html.YELLOW_FLAG.parse() + " Average TPS dropped below Low Threshold (" + Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber() + ")" + " " + tpsSpikeMonth + " times
" + avgLowThresholdString + "

"); serverHealth *= 0.95; } else { - healthNotes.add("

" + Html.RED_WARN.parse() + notes.add("

" + Html.RED_WARN.parse() + " Average TPS dropped below Low Threshold (" + Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber() + ")" + " " + tpsSpikeMonth + " times
" + avgLowThresholdString + "

"); @@ -227,14 +225,14 @@ public class HealthNotes { } if (serverDownTime <= TimeAmount.DAY.ms()) { - healthNotes.add("

" + Html.GREEN_THUMB.parse() + " Total Server downtime (No Data) was " + notes.add("

" + Html.GREEN_THUMB.parse() + " Total Server downtime (No Data) was " + FormatUtils.formatTimeAmount(serverDownTime) + "

"); } else if (serverDownTime <= TimeAmount.WEEK.ms()) { - healthNotes.add("

" + Html.YELLOW_FLAG.parse() + " Total Server downtime (No Data) was " + notes.add("

" + Html.YELLOW_FLAG.parse() + " Total Server downtime (No Data) was " + FormatUtils.formatTimeAmount(serverDownTime) + "

"); serverHealth *= (TimeAmount.WEEK.ms() - serverDownTime) * 1.0 / TimeAmount.WEEK.ms(); } else { - healthNotes.add("

" + Html.RED_WARN.parse() + " Total Server downtime (No Data) was " + notes.add("

" + Html.RED_WARN.parse() + " Total Server downtime (No Data) was " + FormatUtils.formatTimeAmount(serverDownTime) + "

"); serverHealth *= (TimeAmount.MONTH.ms() - serverDownTime) * 1.0 / TimeAmount.MONTH.ms(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/RawData.java b/Plan/src/main/java/com/djrapitops/plan/data/calculation/RawData.java similarity index 97% rename from Plan/src/main/java/com/djrapitops/plan/data/RawData.java rename to Plan/src/main/java/com/djrapitops/plan/data/calculation/RawData.java index 5f2f7cd69..03c57bcd8 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/RawData.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/calculation/RawData.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.data; +package com.djrapitops.plan.data.calculation; import com.djrapitops.plugin.utilities.Verify; diff --git a/Plan/src/main/java/com/djrapitops/plan/data/container/Action.java b/Plan/src/main/java/com/djrapitops/plan/data/container/Action.java index b7c067b50..ba81aba45 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/container/Action.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/container/Action.java @@ -1,11 +1,10 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan.data.container; -import com.djrapitops.plan.data.HasDate; -import com.djrapitops.plan.database.tables.Actions; +import com.djrapitops.plan.data.Actions; import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.html.Html; @@ -16,7 +15,7 @@ import java.util.Objects; * * @author Rsl1122 */ -public class Action implements HasDate { +public class Action { private final long date; private final Actions doneAction; private final String additionalInfo; diff --git a/Plan/src/main/java/com/djrapitops/plan/data/container/GeoInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/container/GeoInfo.java index c9fa363c5..f34bf5f21 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/container/GeoInfo.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/container/GeoInfo.java @@ -1,10 +1,9 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan.data.container; -import com.djrapitops.plan.data.HasDate; import com.google.common.base.Objects; /** @@ -12,7 +11,7 @@ import com.google.common.base.Objects; * * @author Rsl1122 */ -public class GeoInfo implements HasDate { +public class GeoInfo { private final String ip; private final String geolocation; @@ -36,11 +35,6 @@ public class GeoInfo implements HasDate { return lastUsed; } - @Override - public long getDate() { - return getLastUsed(); - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/Plan/src/main/java/com/djrapitops/plan/data/container/PlayerKill.java b/Plan/src/main/java/com/djrapitops/plan/data/container/PlayerKill.java index 18f4aead3..1c8fb39eb 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/container/PlayerKill.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/container/PlayerKill.java @@ -1,9 +1,7 @@ package com.djrapitops.plan.data.container; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.data.HasDate; -import com.djrapitops.plan.database.tables.Actions; -import org.apache.commons.lang3.builder.ToStringBuilder; +import com.djrapitops.plan.data.Actions; +import com.djrapitops.plan.system.cache.DataCache; import java.util.Objects; import java.util.UUID; @@ -14,7 +12,7 @@ import java.util.UUID; * * @author Rsl1122 */ -public class PlayerKill implements HasDate { +public class PlayerKill { private final UUID victim; private final long time; @@ -51,11 +49,6 @@ public class PlayerKill implements HasDate { return time; } - @Override - public long getDate() { - return getTime(); - } - /** * Get the Weapon used as string. * @@ -66,7 +59,7 @@ public class PlayerKill implements HasDate { } public Action convertToAction() { - String name = Plan.getInstance().getDataCache().getName(victim); + String name = DataCache.getInstance().getName(victim); return new Action(time, Actions.KILLED, name + " with " + weapon); } @@ -87,10 +80,9 @@ public class PlayerKill implements HasDate { @Override public String toString() { - return new ToStringBuilder(this) - .append("victim", victim) - .append("time", time) - .append("weapon", weapon) - .toString(); + return "PlayerKill{" + + "victim=" + victim + ", " + + "time=" + time + ", " + + "weapon='" + weapon + "'}"; } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/container/Session.java b/Plan/src/main/java/com/djrapitops/plan/data/container/Session.java index 7a802d477..22f4d0cd7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/container/Session.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/container/Session.java @@ -1,9 +1,7 @@ package com.djrapitops.plan.data.container; -import com.djrapitops.plan.data.HasDate; import com.djrapitops.plan.data.time.WorldTimes; import com.djrapitops.plan.utilities.MiscUtils; -import org.apache.commons.lang3.builder.ToStringBuilder; import java.util.ArrayList; import java.util.HashMap; @@ -28,7 +26,7 @@ import java.util.Objects; * * @author Rsl1122 */ -public class Session implements HasDate { +public class Session { private final long sessionStart; private Integer sessionID; @@ -68,18 +66,6 @@ public class Session implements HasDate { this.deaths = deaths; } - /** - * Starts a new Session. - * - * @param time Time the session started. - * @param world World the session started in. - * @param gm GameMode the session started in. - * @return a new Session object. - */ - public static Session start(long time, String world, String gm) { - return new Session(time, world, gm); - } - /** * Ends the session with given end point. *

@@ -207,19 +193,13 @@ public class Session implements HasDate { @Override public String toString() { - return new ToStringBuilder(this) - .append("sessionStart", sessionStart) - .append("sessionID", sessionID) - .append("worldTimes", worldTimes) - .append("sessionEnd", sessionEnd) - .append("playerKills", playerKills) - .append("mobKills", mobKills) - .append("deaths", deaths) - .toString(); - } - - @Override - public long getDate() { - return getSessionStart(); + return "Session{" + + "sessionStart=" + sessionStart + ", " + + "sessionID=" + sessionID + ", " + + "worldTimes=" + worldTimes + ", " + + "sessionEnd=" + sessionEnd + ", " + + "playerKills=" + playerKills + ", " + + "mobKills=" + mobKills + ", " + + "deaths=" + deaths + '}'; } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/container/StickyData.java b/Plan/src/main/java/com/djrapitops/plan/data/container/StickyData.java index d5cdaa928..58d4176c4 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/container/StickyData.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/container/StickyData.java @@ -4,40 +4,40 @@ */ package com.djrapitops.plan.data.container; +import com.djrapitops.plan.data.Actions; import com.djrapitops.plan.data.PlayerProfile; -import com.djrapitops.plan.database.tables.Actions; import com.djrapitops.plugin.api.TimeAmount; import com.google.common.base.Objects; +import java.util.List; + public class StickyData { private final double activityIndex; private Integer messagesSent; private Integer onlineOnJoin; public StickyData(PlayerProfile player) { - activityIndex = player.getActivityIndex(player.getRegistered() + TimeAmount.DAY.ms()); - for (Action action : player.getActions()) { - if (messagesSent == null && action.getDoneAction() == Actions.FIRST_LOGOUT) { - String additionalInfo = action.getAdditionalInfo(); - String[] split = additionalInfo.split(": "); - if (split.length == 2) { - try { - messagesSent = Integer.parseInt(split[1]); - } catch (NumberFormatException ignored) { - } + activityIndex = player.getActivityIndex(player.getRegistered() + TimeAmount.DAY.ms()).getValue(); + loadActionVariables(player.getActions()); + } + + private void loadActionVariables(List actions) { + for (Action action : actions) { + try { + if (messagesSent == null && action.getDoneAction() == Actions.FIRST_LOGOUT) { + messagesSent = loadSentMessages(action); } - } - if (onlineOnJoin == null && action.getDoneAction() == Actions.FIRST_SESSION) { - String additionalInfo = action.getAdditionalInfo(); - String[] split = additionalInfo.split(" "); - if (split.length == 3) { - try { - onlineOnJoin = Integer.parseInt(split[1]); - } catch (NumberFormatException ignored) { - } + if (onlineOnJoin == null && action.getDoneAction() == Actions.FIRST_SESSION) { + onlineOnJoin = loadOnlineOnJoin(action); } + } catch (IllegalArgumentException ignore) { + /* continue */ } } + setDefaultValuesIfNull(); + } + + private void setDefaultValuesIfNull() { if (messagesSent == null) { messagesSent = 0; } @@ -46,6 +46,24 @@ public class StickyData { } } + private int loadOnlineOnJoin(Action action) { + String additionalInfo = action.getAdditionalInfo(); + String[] split = additionalInfo.split(" "); + if (split.length == 3) { + return Integer.parseInt(split[1]); + } + throw new IllegalArgumentException("Improper Action"); + } + + private int loadSentMessages(Action action) { + String additionalInfo = action.getAdditionalInfo(); + String[] split = additionalInfo.split(": "); + if (split.length == 2) { + return Integer.parseInt(split[1]); + } + throw new IllegalArgumentException("Improper Action"); + } + public double distance(StickyData data) { double num = 0; num += Math.abs(data.activityIndex - activityIndex) * 2.0; diff --git a/Plan/src/main/java/com/djrapitops/plan/data/container/TPS.java b/Plan/src/main/java/com/djrapitops/plan/data/container/TPS.java index 753e94712..0b683ba99 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/container/TPS.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/container/TPS.java @@ -5,9 +5,6 @@ */ package com.djrapitops.plan.data.container; -import com.djrapitops.plan.data.HasDate; -import org.apache.commons.lang3.builder.ToStringBuilder; - import java.util.Objects; /** @@ -16,7 +13,7 @@ import java.util.Objects; * @author Rsl1122 * @since 3.5.0 */ -public class TPS implements HasDate { +public class TPS { private final long date; private final double ticksPerSecond; @@ -131,14 +128,13 @@ public class TPS implements HasDate { @Override public String toString() { - return new ToStringBuilder(this) - .append("date", date) - .append("ticksPerSecond", ticksPerSecond) - .append("players", players) - .append("cpuUsage", cpuUsage) - .append("usedMemory", usedMemory) - .append("entityCount", entityCount) - .append("chunksLoaded", chunksLoaded) - .toString(); + return "TPS{" + + "date=" + date + ", " + + "ticksPerSecond=" + ticksPerSecond + ", " + + "players=" + players + ", " + + "cpuUsage=" + cpuUsage + ", " + + "usedMemory=" + usedMemory + ", " + + "entityCount=" + entityCount + ", " + + "chunksLoaded=" + chunksLoaded + '}'; } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/container/UserInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/container/UserInfo.java index 6c99b9c74..35cb71034 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/container/UserInfo.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/container/UserInfo.java @@ -38,18 +38,10 @@ public class UserInfo { return name; } - public void setName(String name) { - this.name = name; - } - public long getRegistered() { return registered; } - public void setRegistered(long registered) { - this.registered = registered; - } - public long getLastSeen() { return lastSeen; } @@ -62,10 +54,6 @@ public class UserInfo { return banned; } - public void setBanned(boolean banned) { - this.banned = banned; - } - public boolean isOpped() { return opped; } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/container/builders/TPSBuilder.java b/Plan/src/main/java/com/djrapitops/plan/data/container/builders/TPSBuilder.java new file mode 100644 index 000000000..8614eeae2 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/container/builders/TPSBuilder.java @@ -0,0 +1,97 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.data.container.builders; + +import com.djrapitops.plan.data.container.TPS; + +/** + * Builder for TPS to make it easier to manage. + * + * @author Rsl1122 + */ +public class TPSBuilder { + + protected long date = 0; + protected double ticksPerSecond = -1; + protected int players = -1; + protected double cpuUsage = -1; + protected long usedMemory = -1; + protected int entityCount = -1; + protected int chunksLoaded = -1; + + /** + * Hides constructor. + */ + private TPSBuilder() { + } + + public static TPSBuilder.Date get() { + return new TPSBuilder.Chunks(); + } + + public TPS toTPS() { + return new TPS(date, ticksPerSecond, players, cpuUsage, usedMemory, entityCount, chunksLoaded); + } + + public static class Date extends TPSBuilder { + + public Ticks date(long date) { + this.date = date; + return (Ticks) this; + } + } + + public static class Ticks extends Date { + + public Players tps(double tps) { + ticksPerSecond = tps; + return (Players) this; + } + + public Players skipTPS() { + return (Players) this; + } + } + + public static class Players extends Ticks { + + public CPU playersOnline(int online) { + players = online; + return (CPU) this; + } + } + + public static class CPU extends Players { + + public Memory usedCPU(double cpu) { + cpuUsage = cpu; + return (Memory) this; + } + } + + public static class Memory extends CPU { + + public Entities usedMemory(long ram) { + usedMemory = ram; + return (Entities) this; + } + } + + public static class Entities extends Memory { + + public Chunks entities(int count) { + entityCount = count; + return (Chunks) this; + } + } + + public static class Chunks extends Entities { + + public TPSBuilder chunksLoaded(int chunksLoaded) { + this.chunksLoaded = chunksLoaded; + return this; + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/data/element/AnalysisContainer.java b/Plan/src/main/java/com/djrapitops/plan/data/element/AnalysisContainer.java index c97a89547..2efb126ef 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/element/AnalysisContainer.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/element/AnalysisContainer.java @@ -1,4 +1,4 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ diff --git a/Plan/src/main/java/com/djrapitops/plan/data/element/InspectContainer.java b/Plan/src/main/java/com/djrapitops/plan/data/element/InspectContainer.java index e52ea0c8a..f99dfa0b6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/element/InspectContainer.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/element/InspectContainer.java @@ -1,4 +1,4 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ @@ -69,6 +69,11 @@ public class InspectContainer { return html.toString(); } + /** + * Check if InspectContainer has only values, and not HTML or Tables. + * + * @return true/false + */ public final boolean hasOnlyValues() { return html.isEmpty() && tables.isEmpty(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/element/TableContainer.java b/Plan/src/main/java/com/djrapitops/plan/data/element/TableContainer.java index 64e754208..9a6be1dec 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/element/TableContainer.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/element/TableContainer.java @@ -1,4 +1,4 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ @@ -16,11 +16,13 @@ import java.util.List; * * @author Rsl1122 */ -public final class TableContainer { +public class TableContainer { private final String[] header; private List values; + private boolean jqueryDatatable; + private String color; /** @@ -38,18 +40,18 @@ public final class TableContainer { values = new ArrayList<>(); } - public void addRow(Serializable... values) { + public final void addRow(Serializable... values) { this.values.add(values); } - public String parseHtml() { - return Html.TABLE_SCROLL.parse() + + public final String parseHtml() { + return getTableHeader() + parseHeader() + parseBody() + ""; } - private String parseBody() { + public final String parseBody() { StringBuilder body = new StringBuilder(); if (values.isEmpty()) { @@ -73,11 +75,11 @@ public final class TableContainer { return Html.TABLE_BODY.parse(body.toString()); } - public void setColor(String color) { + public final void setColor(String color) { this.color = color; } - public String parseHeader() { + public final String parseHeader() { StringBuilder header = new StringBuilder(""); for (String title : this.header) { header.append("").append(title).append(""); @@ -85,4 +87,21 @@ public final class TableContainer { header.append(""); return header.toString(); } + + /** + * Make use of JQuery Datatables plugin. + *

+ * If this is called, result of {@code parseHtml()} should be wrapped with {@code Html.PANEL.parse(Html.PANEL_BODY.parse(result))} + */ + public void useJqueryDataTables() { + this.jqueryDatatable = true; + } + + private String getTableHeader() { + if (jqueryDatatable) { + return "

" + Html.TABLE_JQUERY.parse() + "
"; + } else { + return Html.TABLE_SCROLL.parse(); + } + } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/data/plugin/BanData.java b/Plan/src/main/java/com/djrapitops/plan/data/plugin/BanData.java index 3f3b035c8..a2097562a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/plugin/BanData.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/plugin/BanData.java @@ -1,4 +1,4 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ diff --git a/Plan/src/main/java/com/djrapitops/plan/data/plugin/ContainerSize.java b/Plan/src/main/java/com/djrapitops/plan/data/plugin/ContainerSize.java index 87dd725a2..3dae7883d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/plugin/ContainerSize.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/plugin/ContainerSize.java @@ -1,4 +1,4 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ diff --git a/Plan/src/main/java/com/djrapitops/plan/data/plugin/HookHandler.java b/Plan/src/main/java/com/djrapitops/plan/data/plugin/HookHandler.java index 915821f5c..6654bcdf6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/plugin/HookHandler.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/plugin/HookHandler.java @@ -1,12 +1,15 @@ package com.djrapitops.plan.data.plugin; import com.djrapitops.plan.Plan; +import com.djrapitops.plan.data.element.InspectContainer; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; import com.djrapitops.plugin.StaticHolder; import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; import com.djrapitops.pluginbridge.plan.Bridge; -import java.util.ArrayList; -import java.util.List; +import java.util.*; /** * Class responsible for hooking to other plugins and managing the %plugins% @@ -15,27 +18,37 @@ import java.util.List; * @author Rsl1122 * @since 2.6.0 */ -public class HookHandler { +public class HookHandler implements SubSystem { private final List additionalDataSources; - private final PluginsConfigSection configHandler; + private PluginsConfigSection configHandler; - /** - * Class constructor, hooks to plugins. - * - * @param plugin Current instance of plan. - */ - public HookHandler(Plan plugin) { + public HookHandler() { additionalDataSources = new ArrayList<>(); + } + + public static HookHandler getInstance() { + HookHandler hookHandler = PlanSystem.getInstance().getHookHandler(); + Verify.nullCheck(hookHandler, () -> new IllegalStateException("Plugin Hooks were not initialized.")); + return hookHandler; + } + + @Override + public void enable() { configHandler = new PluginsConfigSection(); try { Bridge.hook(this); } catch (Exception e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); Log.error("Plan Plugin Bridge not included in the plugin jar."); } } + @Override + public void disable() { + + } + /** * Adds a new PluginData source to the list. *

@@ -60,7 +73,7 @@ public class HookHandler { additionalDataSources.add(dataSource); } } catch (Exception e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); Log.error("Attempting to register PluginDataSource caused an exception."); } } @@ -73,4 +86,23 @@ public class HookHandler { public List getAdditionalDataSources() { return additionalDataSources; } + + public Map getInspectContainersFor(UUID uuid) { + List plugins = getAdditionalDataSources(); + Map containers = new HashMap<>(); + for (PluginData pluginData : plugins) { + InspectContainer inspectContainer = new InspectContainer(); + try { + InspectContainer container = pluginData.getPlayerData(uuid, inspectContainer); + if (container != null && !container.isEmpty()) { + containers.put(pluginData, container); + } + } catch (Exception | NoClassDefFoundError | NoSuchFieldError | NoSuchMethodError e) { + String sourcePlugin = pluginData.getSourcePlugin(); + Log.error("PluginData caused exception: " + sourcePlugin); + Log.toLog(this.getClass().getName() + " " + sourcePlugin, e); + } + } + return containers; + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/plugin/PluginsConfigSection.java b/Plan/src/main/java/com/djrapitops/plan/data/plugin/PluginsConfigSection.java index aa00b0310..efcd64f4a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/plugin/PluginsConfigSection.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/plugin/PluginsConfigSection.java @@ -1,6 +1,6 @@ package com.djrapitops.plan.data.plugin; -import com.djrapitops.plan.systems.file.config.ConfigSystem; +import com.djrapitops.plan.system.settings.config.ConfigSystem; import com.djrapitops.plugin.api.config.ConfigNode; import com.djrapitops.plugin.api.utility.log.Log; @@ -23,7 +23,7 @@ public class PluginsConfigSection { } private ConfigNode getPluginsSection() { - return ConfigSystem.getInstance().getConfig().getConfigNode("Plugins"); + return ConfigSystem.getConfig().getConfigNode("Plugins"); } public void createSection(PluginData dataSource) { @@ -35,7 +35,7 @@ public class PluginsConfigSection { section.sort(); section.save(); } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/time/TimeKeeper.java b/Plan/src/main/java/com/djrapitops/plan/data/time/TimeKeeper.java index 4b4645350..8fdd617e7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/time/TimeKeeper.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/time/TimeKeeper.java @@ -1,7 +1,6 @@ package com.djrapitops.plan.data.time; import com.djrapitops.plugin.utilities.Verify; -import org.apache.commons.lang3.builder.ToStringBuilder; import java.util.HashMap; import java.util.Map; @@ -155,10 +154,7 @@ public abstract class TimeKeeper { @Override public String toString() { - return new ToStringBuilder(this) - .append("times", times) - .append("state", state) - .append("lastStateChange", lastStateChange) - .toString(); + return "TimeKeeper{" + "times=" + times + + ", state='" + state + "', lastStateChange=" + lastStateChange + '}'; } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/database/Container.java b/Plan/src/main/java/com/djrapitops/plan/database/Container.java deleted file mode 100644 index 8e1885f72..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/database/Container.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.djrapitops.plan.database; - -/** - * Class to contain objects in the batches. - * - * @param Object stored. - * @author Rsl1122 - * @since 3.4.3 - */ -public class Container { - - private final T object; - private final int id; - - /** - * Constructor for the object. - * - * @param object Object to place inside the container. - * @param id UserID related to the object. - */ - public Container(T object, int id) { - this.object = object; - this.id = id; - } - - /** - * Get the object in the container. - * - * @return object. - */ - public T getObject() { - return object; - } - - /** - * Get the UserID related to the object. - * - * @return userID - */ - public int getId() { - return id; - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/database/DBUtils.java b/Plan/src/main/java/com/djrapitops/plan/database/DBUtils.java deleted file mode 100644 index c01a9d36b..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/database/DBUtils.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.djrapitops.plan.database; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** - * Class containing static utility methods used by the Database classes. - * - * @author Rsl1122 - * @since 3.4.3 - */ -public class DBUtils { - - private static final int BATCH_SIZE = 10192; - - /** - * Constructor used to hide the public constructor - */ - private DBUtils() { - throw new IllegalStateException("Utility class"); - } - - /** - * Splits a collection of objects into lists with the size defined by - * BATCH_SIZE. - * - * @param Object type - * @param objects Collection of the objects - * @return Lists with max size of BATCH_SIZE - */ - public static List> splitIntoBatches(Collection objects) { - List> batches = new ArrayList<>(); - - int i = 0; - int j = 0; - - for (T obj : objects) { - if (batches.size() <= j) { - batches.add(new ArrayList<>()); - } - batches.get(j).add(obj); - i++; - if (i % BATCH_SIZE == 0) { - j++; - } - } - return batches; - } - - /** - * @param Object type - * @param objects Collection of the objects - * @return Lists with max size of BATCH_SIZE - */ - public static List>> splitIntoBatchesId(Map> objects) { - List>> wrappedBatches = new ArrayList<>(); - - int i = 0; - int j = 0; - - for (Entry> entry : objects.entrySet()) { - for (T object : entry.getValue()) { - if (wrappedBatches.size() <= j) { - wrappedBatches.add(new ArrayList<>()); - } - - wrappedBatches.get(j).add(new Container<>(object, entry.getKey())); - i++; - if (i % BATCH_SIZE == 0) { - j++; - } - } - } - return wrappedBatches; - } - - /** - * @param Object type - * @param objects Collection of the objects - * @return Lists with max size of BATCH_SIZE - */ - public static List>> splitIntoBatchesWithID(Map objects) { - List>> wrappedBatches = new ArrayList<>(); - - int i = 0; - int j = 0; - - for (Entry entry : objects.entrySet()) { - T object = entry.getValue(); - if (wrappedBatches.size() <= j) { - wrappedBatches.add(new ArrayList<>()); - } - - wrappedBatches.get(j).add(new Container<>(object, entry.getKey())); - i++; - if (i % BATCH_SIZE == 0) { - j++; - } - } - return wrappedBatches; - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/database/Database.java b/Plan/src/main/java/com/djrapitops/plan/database/Database.java deleted file mode 100644 index e0ad1310e..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/database/Database.java +++ /dev/null @@ -1,269 +0,0 @@ -package com.djrapitops.plan.database; - -import com.djrapitops.plan.api.exceptions.DatabaseInitException; -import com.djrapitops.plan.data.PlayerProfile; -import com.djrapitops.plan.data.ServerProfile; -import com.djrapitops.plan.database.tables.*; -import org.apache.commons.lang3.StringUtils; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -/** - * Abstract class representing a Database. - *

- * All methods should be only called from an asynchronous thread, unless stated - * otherwise. - * - * @author Rsl1122 - */ -public abstract class Database { - - protected UsersTable usersTable; - protected UserInfoTable userInfoTable; - protected ActionsTable actionsTable; - protected KillsTable killsTable; - protected NicknamesTable nicknamesTable; - protected SessionsTable sessionsTable; - protected IPsTable ipsTable; - protected CommandUseTable commandUseTable; - protected TPSTable tpsTable; - protected VersionTable versionTable; - protected SecurityTable securityTable; - protected WorldTable worldTable; - protected WorldTimesTable worldTimesTable; - protected ServerTable serverTable; - - - - /** - * Super constructor. - */ - public Database() { - } - - /** - * Initiates the database. - * - * @throws DatabaseInitException if SQLException or other exception occurs. - */ - public void init() throws DatabaseInitException { - } - - /** - * Condition if the user is saved in the database. - * - * @param uuid UUID of the user. - * @return true/false - */ - public abstract boolean wasSeenBefore(UUID uuid); - - /** - * Used to get the name of the database type. - *

- * Thread safe. - * - * @return SQLite/MySQL - */ - public abstract String getName(); - - /** - * Used to get the config name of the database type. - *

- * Thread safe. - * - * @return sqlite/mysql - */ - public String getConfigName() { - return StringUtils.remove(getName().toLowerCase(), ' '); - } - - public abstract boolean isNewDatabase() throws SQLException; - - /** - * Used to get the database schema version. - * - * @return Integer starting from 0, incremented by one when schema is - * updated. - * @throws SQLException If a database error occurs. - */ - public abstract int getVersion() throws SQLException; - - /** - * Used to set the database schema version. - * - * @param version Integer starting from 0, incremented by one when schema is - * updated. - * @throws SQLException If a database error occurs. - */ - public abstract void setVersion(int version) throws SQLException; - - /** - * Closes the database and it's resources. - * - * @throws SQLException If a database error occurs. - */ - public abstract void close() throws SQLException; - - /** - * Returns a connection to the MySQL connection pool. - *

- * On SQLite does nothing. - * - * @param connection Connection to return. - * @throws SQLException DB Error - */ - public abstract void returnToPool(Connection connection) throws SQLException; - - /** - * Removes all data related to an account from the database. - * - * @param uuid UUID of the account. - * @throws SQLException If a database error occurs. - */ - public abstract void removeAccount(UUID uuid) throws SQLException; - - /** - * Used to clear all data from the database. - *

- * Uses DELETE * FROM table. - * - * @throws SQLException if remove fails. - */ - public abstract void removeAllData() throws SQLException; - - /** - * Used to fetch the saved UUIDs in the users table. - * - * @return Set of saved UUIDs - * @throws SQLException If a database error occurs. - */ - public Set getSavedUUIDs() throws SQLException { - return usersTable.getSavedUUIDs(); - } - - /** - * Used to get the Command usage mep. - * - * @return String command (key), Integer times used - * @throws SQLException If a database error occurs. - */ - public Map getCommandUse() throws SQLException { - return commandUseTable.getCommandUse(); - } - - /** - * Used to get the users table. - * - * @return Table representing plan_users - */ - public UsersTable getUsersTable() { - return usersTable; - } - - /** - * Used to get the users table. - * - * @return Table representing plan_sessions - */ - public SessionsTable getSessionsTable() { - return sessionsTable; - } - - /** - * Used to get the kills table. - * - * @return Table representing plan_kills - */ - public KillsTable getKillsTable() { - return killsTable; - } - - /** - * Used to get the ips table. - * - * @return Table representing plan_ips - */ - public IPsTable getIpsTable() { - return ipsTable; - } - - /** - * Used to get the nicknames table. - * - * @return Table representing plan_nicknames - */ - public NicknamesTable getNicknamesTable() { - return nicknamesTable; - } - - /** - * Used to get the command usage table. - * - * @return Table representing plan_commandusages - */ - public CommandUseTable getCommandUseTable() { - return commandUseTable; - } - - /** - * Used to get the tps table. - * - * @return Table representing plan_tps - */ - public TPSTable getTpsTable() { - return tpsTable; - } - - /** - * Used to get the security table. - * - * @return Table representing plan_security - */ - public SecurityTable getSecurityTable() { - return securityTable; - } - - /** - * Used to get the worlds table. - * - * @return Table representing plan_worlds - */ - public WorldTable getWorldTable() { - return worldTable; - } - - /** - * Used to get the world times table. - * - * @return Table representing plan_world_times - */ - public WorldTimesTable getWorldTimesTable() { - return worldTimesTable; - } - - public ServerTable getServerTable() { - return serverTable; - } - - public ActionsTable getActionsTable() { - return actionsTable; - } - - public UserInfoTable getUserInfoTable() { - return userInfoTable; - } - - public abstract void commit(Connection connection) throws SQLException; - - public boolean isUsingMySQL() { - return "mysql".equals(getConfigName()); - } - - public abstract PlayerProfile getPlayerProfile(UUID uuid) throws SQLException; - - public abstract ServerProfile getServerProfile(UUID serverUUID) throws SQLException; -} diff --git a/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLDB.java b/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLDB.java deleted file mode 100644 index ed544d912..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLDB.java +++ /dev/null @@ -1,445 +0,0 @@ -package com.djrapitops.plan.database.databases; - -import com.djrapitops.plan.api.exceptions.DatabaseInitException; -import com.djrapitops.plan.data.PlayerProfile; -import com.djrapitops.plan.data.ServerProfile; -import com.djrapitops.plan.data.container.*; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.database.tables.*; -import com.djrapitops.plan.database.tables.move.Version8TransferTable; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plugin.api.Benchmark; -import com.djrapitops.plugin.api.TimeAmount; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.task.AbsRunnable; -import com.djrapitops.plugin.task.ITask; -import com.djrapitops.plugin.task.RunnableFactory; -import org.apache.commons.dbcp2.BasicDataSource; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.*; - -/** - * Class containing main logic for different data related save and load functionality. - * - * @author Rsl1122 - * @since 2.0.0 - */ -public abstract class SQLDB extends Database { - - private final boolean usingMySQL; - private boolean open = false; - private ITask dbCleanTask; - - public SQLDB() { - usingMySQL = getName().equals("MySQL"); - - versionTable = new VersionTable(this, usingMySQL); - serverTable = new ServerTable(this, usingMySQL); - securityTable = new SecurityTable(this, usingMySQL); - - commandUseTable = new CommandUseTable(this, usingMySQL); - tpsTable = new TPSTable(this, usingMySQL); - - usersTable = new UsersTable(this, usingMySQL); - userInfoTable = new UserInfoTable(this, usingMySQL); - actionsTable = new ActionsTable(this, usingMySQL); - ipsTable = new IPsTable(this, usingMySQL); - nicknamesTable = new NicknamesTable(this, usingMySQL); - sessionsTable = new SessionsTable(this, usingMySQL); - killsTable = new KillsTable(this, usingMySQL); - worldTable = new WorldTable(this, usingMySQL); - worldTimesTable = new WorldTimesTable(this, usingMySQL); - } - - /** - * Initializes the Database. - *

- * All tables exist in the database after call to this. - * Updates Schema to latest version. - * Converts Unsaved Bukkit player files to database data. - * Cleans the database. - * - * @throws DatabaseInitException if Database fails to initiate. - */ - @Override - public void init() throws DatabaseInitException { - setStatus("Init"); - String benchName = "Init " + getConfigName(); - Benchmark.start("Database", benchName); - try { - setupDataSource(); - setupDatabase(); - open = true; - } finally { - Benchmark.stop("Database", benchName); - Log.logDebug("Database"); - } - } - - public void scheduleClean(long secondsDelay) { - dbCleanTask = RunnableFactory.createNew("DB Clean Task", new AbsRunnable() { - @Override - public void run() { - try { - if (isOpen()) { - clean(); - } - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } finally { - cancel(); - } - } - }).runTaskLaterAsynchronously(TimeAmount.SECOND.ticks() * secondsDelay); - } - - /** - * Ensures connection functions correctly and all tables exist. - *

- * Updates to latest schema. - * - * @throws DatabaseInitException if something goes wrong. - */ - public void setupDatabase() throws DatabaseInitException { - try { - boolean newDatabase = isNewDatabase(); - - versionTable.createTable(); - createTables(); - - if (newDatabase) { - Log.info("New Database created."); - setVersion(13); - } - - int version = getVersion(); - - final SQLDB db = this; - if (version < 10) { - RunnableFactory.createNew("DB v8 -> v10 Task", new AbsRunnable() { - @Override - public void run() { - try { - new Version8TransferTable(db, isUsingMySQL()).alterTablesToV10(); - } catch (DatabaseInitException | SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - } - }).runTaskLaterAsynchronously(TimeAmount.SECOND.ticks() * 5L); - } - if (version < 11) { - serverTable.alterTableV11(); - setVersion(11); - } - if (version < 12) { - actionsTable.alterTableV12(); - ipsTable.alterTableV12(); - setVersion(12); - } - if (version < 13) { - ipsTable.alterTableV13(); - setVersion(13); - } - } catch (SQLException e) { - throw new DatabaseInitException("Failed to set-up Database", e); - } - } - - /** - * Creates the tables that contain data. - *

- * Updates table columns to latest schema. - */ - private void createTables() throws DatabaseInitException { - Benchmark.start("Database", "Create tables"); - for (Table table : getAllTables()) { - table.createTable(); - } - Benchmark.stop("Database", "Create tables"); - } - - /** - * Get all tables in a create order. - * - * @return Table array. - */ - public Table[] getAllTables() { - return new Table[]{ - serverTable, usersTable, userInfoTable, ipsTable, - nicknamesTable, sessionsTable, killsTable, - commandUseTable, actionsTable, tpsTable, - worldTable, worldTimesTable, securityTable - }; - } - - /** - * Get all tables for removal of data. - * - * @return Tables in the order the data should be removed in. - */ - public Table[] getAllTablesInRemoveOrder() { - return new Table[]{ - ipsTable, nicknamesTable, killsTable, - worldTimesTable, sessionsTable, actionsTable, - worldTable, userInfoTable, usersTable, - commandUseTable, tpsTable, securityTable, - serverTable - }; - } - - /** - * Setups the {@link BasicDataSource} - */ - public abstract void setupDataSource() throws DatabaseInitException; - - /** - * Closes the SQLDB - * - * @throws SQLException DB Error - */ - @Override - public void close() throws SQLException { - setStatus("Closed"); - open = false; - Log.logDebug("Database"); // Log remaining Debug info if present - if (dbCleanTask != null) { - dbCleanTask.cancel(); - } - } - - /** - * @return @throws SQLException - */ - @Override - public int getVersion() throws SQLException { - return versionTable.getVersion(); - } - - @Override - public void setVersion(int version) throws SQLException { - versionTable.setVersion(version); - } - - @Override - public boolean isNewDatabase() throws SQLException { - return versionTable.isNewDatabase(); - } - - @Override - public PlayerProfile getPlayerProfile(UUID uuid) throws SQLException { - if (!wasSeenBefore(uuid)) { - return null; - } - - String playerName = usersTable.getPlayerName(uuid); - Optional registerDate = usersTable.getRegisterDate(uuid); - - if (!registerDate.isPresent()) { - throw new IllegalStateException("User has been saved with null register date to a NOT NULL column"); - } - - PlayerProfile profile = new PlayerProfile(uuid, playerName, registerDate.get()); - profile.setTimesKicked(usersTable.getTimesKicked(uuid)); - - Map userInfo = userInfoTable.getAllUserInfo(uuid); - addUserInfoToProfile(profile, userInfo); - - profile.setActions(actionsTable.getActions(uuid)); - profile.setNicknames(nicknamesTable.getAllNicknames(uuid)); - profile.setGeoInformation(ipsTable.getGeoInfo(uuid)); - - Map> sessions = sessionsTable.getSessions(uuid); - profile.setSessions(sessions); - profile.calculateWorldTimesPerServer(); - profile.setTotalWorldTimes(worldTimesTable.getWorldTimesOfUser(uuid)); - - return profile; - } - - private void addUserInfoToProfile(PlayerProfile profile, Map userInfo) { - for (Map.Entry entry : userInfo.entrySet()) { - UUID serverUUID = entry.getKey(); - UserInfo info = entry.getValue(); - - profile.setRegistered(serverUUID, info.getRegistered()); - if (info.isBanned()) { - profile.bannedOnServer(serverUUID); - } - if (info.isOpped()) { - profile.oppedOnServer(serverUUID); - } - } - } - - @Override - public ServerProfile getServerProfile(UUID serverUUID) throws SQLException { - ServerProfile profile = new ServerProfile(serverUUID); - - profile.setPlayers(getPlayers(serverUUID)); - profile.setTps(tpsTable.getTPSData(serverUUID)); - Optional allTimePeak = tpsTable.getAllTimePeak(serverUUID); - if (allTimePeak.isPresent()) { - TPS peak = allTimePeak.get(); - profile.setAllTimePeak(peak.getDate()); - profile.setAllTimePeakPlayers(peak.getPlayers()); - } - Optional lastPeak = tpsTable.getPeakPlayerCount(serverUUID, MiscUtils.getTime() - (TimeAmount.DAY.ms() * 2L)); - if (lastPeak.isPresent()) { - TPS peak = lastPeak.get(); - profile.setLastPeakDate(peak.getDate()); - profile.setLastPeakPlayers(peak.getPlayers()); - } - - profile.setCommandUsage(commandUseTable.getCommandUse(serverUUID)); - profile.setServerWorldtimes(worldTimesTable.getWorldTimesOfServer(serverUUID)); - - return profile; - } - - private List getPlayers(UUID serverUUID) throws SQLException { - List serverUserInfo = userInfoTable.getServerUserInfo(serverUUID); - Map timesKicked = usersTable.getAllTimesKicked(); - Map> actions = actionsTable.getServerActions(serverUUID); - Map> geoInfo = ipsTable.getAllGeoInfo(); - - Map> sessions = sessionsTable.getSessionInfoOfServer(serverUUID); - Map>> map = new HashMap<>(); - map.put(serverUUID, sessions); - killsTable.addKillsToSessions(map); - worldTimesTable.addWorldTimesToSessions(map); - - List players = new ArrayList<>(); - - for (UserInfo userInfo : serverUserInfo) { - UUID uuid = userInfo.getUuid(); - PlayerProfile profile = new PlayerProfile(uuid, userInfo.getName(), userInfo.getRegistered()); - profile.setTimesKicked(timesKicked.getOrDefault(uuid, 0)); - if (userInfo.isBanned()) { - profile.bannedOnServer(serverUUID); - } - if (userInfo.isOpped()) { - profile.oppedOnServer(serverUUID); - } - profile.setActions(actions.getOrDefault(uuid, new ArrayList<>())); - profile.setGeoInformation(geoInfo.getOrDefault(uuid, new ArrayList<>())); - profile.setSessions(serverUUID, sessions.getOrDefault(uuid, new ArrayList<>())); - - players.add(profile); - } - return players; - } - - @Override - public boolean wasSeenBefore(UUID uuid) { - if (uuid == null) { - return false; - } - try { - return usersTable.isRegistered(uuid); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - return false; - } finally { - setAvailable(); - } - } - - public void removeAccount(UUID uuid) throws SQLException { - if (uuid == null) { - return; - } - - try { - Log.logDebug("Database", "Removing Account: " + uuid); - Benchmark.start("Database", "Remove Account"); - - for (Table t : getAllTablesInRemoveOrder()) { - if (!(t instanceof UserIDTable)) { - continue; - } - - UserIDTable table = (UserIDTable) t; - table.removeUser(uuid); - } - } finally { - Benchmark.stop("Database", "Remove Account"); - setAvailable(); - } - } - - private void clean() throws SQLException { - Log.info("Cleaning the database."); - tpsTable.clean(); - Log.info("Clean complete."); - } - - @Override - public void removeAllData() throws SQLException { - setStatus("Clearing all data"); - try { - for (Table table : getAllTablesInRemoveOrder()) { - table.removeAllData(); - } - } finally { - setAvailable(); - } - } - - private void setStatus(String status) { - Log.logDebug("Database", status); - } - - public void setAvailable() { - Log.logDebug("Database"); - } - - public abstract Connection getConnection() throws SQLException; - - /** - * Commits changes to the .db file when using SQLite Database. - *

- * MySQL has Auto Commit enabled. - */ - @Override - public void commit(Connection connection) throws SQLException { - try { - if (!usingMySQL) { - connection.commit(); - } - } catch (SQLException e) { - if (!e.getMessage().contains("cannot commit")) { - Log.toLog(this.getClass().getName(), e); - } - } finally { - returnToPool(connection); - } - } - - @Override - public void returnToPool(Connection connection) throws SQLException { - if (usingMySQL && connection != null) { - connection.close(); - } - } - - /** - * Reverts transaction when using SQLite Database. - *

- * MySQL has Auto Commit enabled. - */ - public void rollback(Connection connection) throws SQLException { - try { - if (!usingMySQL) { - connection.rollback(); - } - } finally { - returnToPool(connection); - } - } - - public boolean isOpen() { - return open; - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLiteDB.java b/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLiteDB.java deleted file mode 100644 index 90468f3f9..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/database/databases/SQLiteDB.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.djrapitops.plan.database.databases; - -import com.djrapitops.plan.api.exceptions.DatabaseInitException; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.task.AbsRunnable; -import com.djrapitops.plugin.task.ITask; -import com.djrapitops.plugin.task.RunnableFactory; -import org.apache.commons.dbcp2.BasicDataSource; - -import java.io.File; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.sql.Statement; - -/** - * @author Rsl1122 - */ -public class SQLiteDB extends SQLDB { - - private final String dbName; - private Connection connection; - private ITask connectionPingTask; - - /** - * Class Constructor. - */ - public SQLiteDB() { - this("database"); - } - - public SQLiteDB(String dbName) { - this.dbName = dbName; - } - - /** - * Setups the {@link BasicDataSource} - */ - @Override - public void setupDataSource() throws DatabaseInitException { - try { - connection = getNewConnection(dbName); - } catch (SQLException e) { - throw new DatabaseInitException(e); - } - startConnectionPingTask(); - } - - public Connection getNewConnection(String dbName) throws SQLException { - try { - Class.forName("org.sqlite.JDBC"); - } catch (ClassNotFoundException e) { - Log.toLog(this.getClass().getName(), e); - return null; // Should never happen. - } - - String dbFilePath = new File(MiscUtils.getIPlan().getDataFolder(), dbName + ".db").getAbsolutePath(); - Connection connection; - - try { - connection = DriverManager.getConnection("jdbc:sqlite:" + dbFilePath + "?journal_mode=WAL"); - } catch (SQLException ignored) { - connection = DriverManager.getConnection("jdbc:sqlite:" + dbFilePath); - Log.info("SQLite WAL mode not supported on this server version, using default. This may or may not affect performance."); - } - connection.setAutoCommit(false); -// connection. - -// setJournalMode(connection); - - return connection; - } - - private void setJournalMode(Connection connection) throws SQLException { - try (Statement statement = connection.createStatement()) { - statement.execute(""); - } - } - - private void startConnectionPingTask() { - stopConnectionPingTask(); - - // Maintains Connection. - connectionPingTask = RunnableFactory.createNew(new AbsRunnable("DBConnectionPingTask " + getName()) { - @Override - public void run() { - Statement statement = null; - try { - if (connection != null && !connection.isClosed()) { - statement = connection.createStatement(); - statement.execute("/* ping */ SELECT 1"); - } - } catch (SQLException e) { - try { - connection = getNewConnection(dbName); - } catch (SQLException e1) { - Log.toLog(this.getClass().getName(), e1); - Log.error("SQLite connection maintaining task had to be closed due to exception."); - this.cancel(); - } - } finally { - MiscUtils.close(statement); - } - } - }).runTaskTimerAsynchronously(60L * 20L, 60L * 20L); - } - - private void stopConnectionPingTask() { - if (connectionPingTask != null) { - try { - connectionPingTask.cancel(); - } catch (Exception ignored) { - } - } - } - - /** - * @return the name of the Database - */ - @Override - public String getName() { - return "SQLite"; - } - - @Override - public Connection getConnection() throws SQLException { - if (connection == null) { - connection = getNewConnection(dbName); - } - return connection; - } - - @Override - public void close() throws SQLException { - stopConnectionPingTask(); - MiscUtils.close(connection); - super.close(); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/BukkitSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/BukkitSystem.java new file mode 100644 index 000000000..af1f624e3 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/BukkitSystem.java @@ -0,0 +1,63 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.ShutdownHook; +import com.djrapitops.plan.api.BukkitAPI; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.data.plugin.HookHandler; +import com.djrapitops.plan.system.database.BukkitDBSystem; +import com.djrapitops.plan.system.file.FileSystem; +import com.djrapitops.plan.system.info.BukkitInfoSystem; +import com.djrapitops.plan.system.info.server.BukkitServerInfo; +import com.djrapitops.plan.system.listeners.BukkitListenerSystem; +import com.djrapitops.plan.system.settings.PlanErrorManager; +import com.djrapitops.plan.system.settings.config.BukkitConfigSystem; +import com.djrapitops.plan.system.settings.network.NetworkSettings; +import com.djrapitops.plan.system.tasks.BukkitTaskSystem; +import com.djrapitops.plan.system.update.VersionCheckSystem; +import com.djrapitops.plugin.StaticHolder; +import com.djrapitops.plugin.api.utility.log.Log; + +/** + * Represents PlanSystem for Plan. + * + * @author Rsl1122 + */ +public class BukkitSystem extends PlanSystem { + + public BukkitSystem(Plan plugin) { + testSystem = this; + + Log.setErrorManager(new PlanErrorManager()); + + versionCheckSystem = new VersionCheckSystem(plugin.getVersion()); + fileSystem = new FileSystem(plugin); + configSystem = new BukkitConfigSystem(); + databaseSystem = new BukkitDBSystem(); + listenerSystem = new BukkitListenerSystem(plugin); + taskSystem = new BukkitTaskSystem(plugin); + + infoSystem = new BukkitInfoSystem(); + serverInfo = new BukkitServerInfo(plugin); + + hookHandler = new HookHandler(); + planAPI = new BukkitAPI(this); + + StaticHolder.saveInstance(ShutdownHook.class, plugin.getClass()); + new ShutdownHook().register(); + } + + public static BukkitSystem getInstance() { + return Plan.getInstance().getSystem(); + } + + @Override + public void enable() throws EnableException { + super.enable(); + NetworkSettings.loadSettingsFromDB(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/BungeeSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/BungeeSystem.java new file mode 100644 index 000000000..087ed82ab --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/BungeeSystem.java @@ -0,0 +1,63 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system; + +import com.djrapitops.plan.PlanBungee; +import com.djrapitops.plan.api.BungeeAPI; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.data.plugin.HookHandler; +import com.djrapitops.plan.system.database.BungeeDBSystem; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.file.FileSystem; +import com.djrapitops.plan.system.info.BungeeInfoSystem; +import com.djrapitops.plan.system.info.server.BungeeServerInfo; +import com.djrapitops.plan.system.listeners.BungeeListenerSystem; +import com.djrapitops.plan.system.settings.PlanErrorManager; +import com.djrapitops.plan.system.settings.config.BungeeConfigSystem; +import com.djrapitops.plan.system.settings.network.NetworkSettings; +import com.djrapitops.plan.system.tasks.BungeeTaskSystem; +import com.djrapitops.plan.system.update.VersionCheckSystem; +import com.djrapitops.plugin.api.utility.log.Log; + +/** + * Represents PlanSystem for PlanBungee. + * + * @author Rsl1122 + */ +public class BungeeSystem extends PlanSystem { + + public BungeeSystem(PlanBungee plugin) { + testSystem = this; + + Log.setErrorManager(new PlanErrorManager()); + + versionCheckSystem = new VersionCheckSystem(plugin.getVersion()); + fileSystem = new FileSystem(plugin); + configSystem = new BungeeConfigSystem(); + databaseSystem = new BungeeDBSystem(); + listenerSystem = new BungeeListenerSystem(plugin); + taskSystem = new BungeeTaskSystem(plugin); + + infoSystem = new BungeeInfoSystem(); + serverInfo = new BungeeServerInfo(plugin); + + hookHandler = new HookHandler(); + planAPI = new BungeeAPI(this); + } + + public static BungeeSystem getInstance() { + return PlanBungee.getInstance().getSystem(); + } + + public void setDatabaseSystem(DBSystem dbSystem) { + this.databaseSystem = dbSystem; + } + + @Override + public void enable() throws EnableException { + super.enable(); + NetworkSettings.placeSettingsToDB(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/PlanSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/PlanSystem.java new file mode 100644 index 000000000..5cd4d46e6 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/PlanSystem.java @@ -0,0 +1,196 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system; + +import com.djrapitops.plan.api.PlanAPI; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.data.plugin.HookHandler; +import com.djrapitops.plan.system.cache.CacheSystem; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.file.FileSystem; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.listeners.ListenerSystem; +import com.djrapitops.plan.system.processing.ProcessingQueue; +import com.djrapitops.plan.system.settings.config.ConfigSystem; +import com.djrapitops.plan.system.tasks.TaskSystem; +import com.djrapitops.plan.system.update.VersionCheckSystem; +import com.djrapitops.plan.system.webserver.WebServerSystem; +import com.djrapitops.plugin.api.Check; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +/** + * PlanSystem contains everything Plan needs to run. + *

+ * This is an abstraction layer on top of Plugin instances so that tests can be run with less mocks. + * + * @author Rsl1122 + */ +public abstract class PlanSystem implements SubSystem { + + protected static PlanSystem testSystem; + + // Initialized in this class + protected final ProcessingQueue processingQueue; + protected final WebServerSystem webServerSystem; + protected final CacheSystem cacheSystem; + + // These need to be initialized in the sub class. + protected VersionCheckSystem versionCheckSystem; + protected FileSystem fileSystem; + protected ConfigSystem configSystem; + protected DBSystem databaseSystem; + protected InfoSystem infoSystem; + + protected ListenerSystem listenerSystem; + protected TaskSystem taskSystem; + protected ServerInfo serverInfo; + + protected HookHandler hookHandler; + + // Not a SubSystem. + protected PlanAPI planAPI; + + public PlanSystem() { + processingQueue = new ProcessingQueue(); + webServerSystem = new WebServerSystem(); + cacheSystem = new CacheSystem(this); + } + + public static PlanSystem getInstance() { + boolean bukkitAvailable = Check.isBukkitAvailable(); + boolean bungeeAvailable = Check.isBungeeAvailable(); + if (bukkitAvailable && bungeeAvailable) { + return testSystem; + } else if (bungeeAvailable) { + return BungeeSystem.getInstance(); + } else if (bukkitAvailable) { + return BukkitSystem.getInstance(); + } + throw new IllegalAccessError("PlanSystem is not available on this platform."); + } + + @Override + public void enable() throws EnableException { + checkSubSystemInitialization(); + + SubSystem[] systems = new SubSystem[]{ + versionCheckSystem, + fileSystem, + configSystem, + databaseSystem, + webServerSystem, + processingQueue, + serverInfo, + infoSystem, + cacheSystem, + listenerSystem, + taskSystem, + hookHandler + }; + for (SubSystem system : systems) { + system.enable(); + } + } + + @Override + public void disable() { + SubSystem[] systems = new SubSystem[]{ + taskSystem, + hookHandler, + cacheSystem, + listenerSystem, + processingQueue, + databaseSystem, + webServerSystem, + infoSystem, + serverInfo, + configSystem, + fileSystem, + versionCheckSystem + }; + for (SubSystem system : systems) { + try { + if (system != null) { + system.disable(); + } + } catch (Exception e) { + Log.toLog(this.getClass(), e); + } + } + } + + private void checkSubSystemInitialization() throws EnableException { + try { + Verify.nullCheck(versionCheckSystem, () -> new IllegalStateException("Version Check system was not initialized.")); + Verify.nullCheck(fileSystem, () -> new IllegalStateException("File system was not initialized.")); + Verify.nullCheck(configSystem, () -> new IllegalStateException("Config system was not initialized.")); + Verify.nullCheck(databaseSystem, () -> new IllegalStateException("Database system was not initialized.")); + Verify.nullCheck(infoSystem, () -> new IllegalStateException("Info system was not initialized.")); + Verify.nullCheck(serverInfo, () -> new IllegalStateException("ServerInfo was not initialized.")); + Verify.nullCheck(listenerSystem, () -> new IllegalStateException("Listener system was not initialized.")); + Verify.nullCheck(taskSystem, () -> new IllegalStateException("Task system was not initialized.")); + Verify.nullCheck(hookHandler, () -> new IllegalStateException("Plugin Hooks were not initialized.")); + Verify.nullCheck(planAPI, () -> new IllegalStateException("Plan API was not initialized.")); + } catch (Exception e) { + throw new EnableException("One of the subsystems is not initialized on enable for " + this.getClass().getSimpleName() + ".", e); + } + } + + // Accessor methods. + + public ProcessingQueue getProcessingQueue() { + return processingQueue; + } + + public VersionCheckSystem getVersionCheckSystem() { + return versionCheckSystem; + } + + public ConfigSystem getConfigSystem() { + return configSystem; + } + + public FileSystem getFileSystem() { + return fileSystem; + } + + public DBSystem getDatabaseSystem() { + return databaseSystem; + } + + public ListenerSystem getListenerSystem() { + return listenerSystem; + } + + public TaskSystem getTaskSystem() { + return taskSystem; + } + + public WebServerSystem getWebServerSystem() { + return webServerSystem; + } + + public ServerInfo getServerInfo() { + return serverInfo; + } + + public CacheSystem getCacheSystem() { + return cacheSystem; + } + + public InfoSystem getInfoSystem() { + return infoSystem; + } + + public HookHandler getHookHandler() { + return hookHandler; + } + + public PlanAPI getPlanAPI() { + return planAPI; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/SubSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/SubSystem.java new file mode 100644 index 000000000..be8b9be91 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/SubSystem.java @@ -0,0 +1,28 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system; + +import com.djrapitops.plan.api.exceptions.EnableException; + +/** + * Represents a system that can be enabled and disabled. + * + * @author Rsl1122 + */ +public interface SubSystem { + + /** + * Performs enable actions for the subsystem. + * + * @throws EnableException If an error occurred during enable and it is fatal to the subsystem. + */ + void enable() throws EnableException; + + /** + * Performs disable actions for the subsystem + */ + void disable(); + +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/cache/CacheSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/cache/CacheSystem.java new file mode 100644 index 000000000..1d24c607c --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/cache/CacheSystem.java @@ -0,0 +1,52 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.cache; + +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plugin.utilities.Verify; + +/** + * System that holds data caches of the plugin. + * + * @author Rsl1122 + */ +public class CacheSystem implements SubSystem { + + private final DataCache dataCache; + private final GeolocationCache geolocationCache; + + public CacheSystem(PlanSystem system) { + dataCache = new DataCache(system); + geolocationCache = new GeolocationCache(); + } + + public static CacheSystem getInstance() { + CacheSystem cacheSystem = PlanSystem.getInstance().getCacheSystem(); + Verify.nullCheck(cacheSystem, () -> new IllegalStateException("Cache System was not initialized.")); + return cacheSystem; + } + + @Override + public void enable() throws EnableException { + dataCache.enable(); + geolocationCache.enable(); + + } + + @Override + public void disable() { + geolocationCache.clearCache(); + } + + public DataCache getDataCache() { + return dataCache; + } + + public GeolocationCache getGeolocationCache() { + return geolocationCache; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/cache/DataCache.java b/Plan/src/main/java/com/djrapitops/plan/system/cache/DataCache.java similarity index 57% rename from Plan/src/main/java/com/djrapitops/plan/systems/cache/DataCache.java rename to Plan/src/main/java/com/djrapitops/plan/system/cache/DataCache.java index 4aad6c76e..ceeaf749e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/cache/DataCache.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/cache/DataCache.java @@ -1,10 +1,12 @@ -package com.djrapitops.plan.systems.cache; +package com.djrapitops.plan.system.cache; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.database.Database; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plan.system.database.databases.Database; import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; -import java.sql.SQLException; import java.util.*; /** @@ -20,28 +22,36 @@ import java.util.*; * @author Rsl1122 * @since 4.0.0 */ -public class DataCache extends SessionCache { +public class DataCache extends SessionCache implements SubSystem { - private static final Map firstSessionInformation = new HashMap<>(); - private final Database db; + private Database db; private final Map playerNames; private final Map uuids; private final Map displayNames; - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public DataCache(Plan plugin) { - super(plugin); - db = plugin.getDB(); + public DataCache(PlanSystem system) { + super(system); playerNames = new HashMap<>(); displayNames = new HashMap<>(); uuids = new HashMap<>(); } + @Override + public void enable() { + db = system.getDatabaseSystem().getActiveDatabase(); + } + + @Override + public void disable() { + } + + public static DataCache getInstance() { + DataCache dataCache = CacheSystem.getInstance().getDataCache(); + Verify.nullCheck(dataCache, () -> new IllegalStateException("Data Cache was not initialized.")); + return dataCache; + } + /** * Used to update PlayerName and DisplayName caches. * @@ -61,13 +71,13 @@ public class DataCache extends SessionCache { public void cacheSavedNames() { try { - Map playerNames = db.getUsersTable().getPlayerNames(); + Map playerNames = db.fetch().getPlayerNames(); this.playerNames.putAll(playerNames); for (Map.Entry entry : playerNames.entrySet()) { uuids.put(entry.getValue(), entry.getKey()); } - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } @@ -81,10 +91,10 @@ public class DataCache extends SessionCache { String name = playerNames.get(uuid); if (name == null) { try { - name = db.getUsersTable().getPlayerName(uuid); + name = db.fetch().getPlayerName(uuid); playerNames.put(uuid, name); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + } catch (DBException e) { + Log.toLog(this.getClass(), e); name = "Error occurred"; } } @@ -104,58 +114,21 @@ public class DataCache extends SessionCache { if (cached == null) { List nicknames; try { - nicknames = db.getNicknamesTable().getNicknames(uuid); + nicknames = db.fetch().getNicknames(uuid); if (!nicknames.isEmpty()) { return nicknames.get(nicknames.size() - 1); } - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } return cached; } - /** - * Used for marking first Session Actions to be saved. - * - * @param uuid UUID of the new player. - */ - public void markFirstSession(UUID uuid) { - firstSessionInformation.put(uuid, 0); - } - - /** - * Condition if a session is player's first session on the server. - * - * @param uuid UUID of the player - * @return true / false - */ - public boolean isFirstSession(UUID uuid) { - return firstSessionInformation.containsKey(uuid); - } - - public void endFirstSessionActionTracking(UUID uuid) { - firstSessionInformation.remove(uuid); - } - - public void firstSessionMessageSent(UUID uuid) { - Integer msgCount = firstSessionInformation.getOrDefault(uuid, 0); - msgCount++; - firstSessionInformation.put(uuid, msgCount); - } - - public int getFirstSessionMsgCount(UUID uuid) { - return firstSessionInformation.getOrDefault(uuid, 0); - } - public Set getUuids() { return playerNames.keySet(); } - public Map getFirstSessionMsgCounts() { - return firstSessionInformation; - } - public UUID getUUIDof(String playerName) { return uuids.get(playerName); } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/cache/GeolocationCache.java b/Plan/src/main/java/com/djrapitops/plan/system/cache/GeolocationCache.java similarity index 67% rename from Plan/src/main/java/com/djrapitops/plan/systems/cache/GeolocationCache.java rename to Plan/src/main/java/com/djrapitops/plan/system/cache/GeolocationCache.java index 2c58f3d38..353083fac 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/cache/GeolocationCache.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/cache/GeolocationCache.java @@ -1,8 +1,11 @@ -package com.djrapitops.plan.systems.cache; +package com.djrapitops.plan.system.cache; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plan.system.file.FileSystem; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; import com.maxmind.geoip2.DatabaseReader; import com.maxmind.geoip2.exception.GeoIp2Exception; import com.maxmind.geoip2.model.CountryResponse; @@ -13,8 +16,11 @@ import java.io.FileOutputStream; import java.io.IOException; import java.net.InetAddress; import java.net.URL; +import java.net.UnknownHostException; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; +import java.util.HashMap; +import java.util.Map; import java.util.zip.GZIPInputStream; /** @@ -27,18 +33,35 @@ import java.util.zip.GZIPInputStream; * @author Fuzzlemann * @since 3.5.5 */ -public class GeolocationCache { +public class GeolocationCache implements SubSystem { - private static File geolocationDB = new File(MiscUtils.getIPlan().getDataFolder(), "GeoIP.dat"); + private final Map geolocationCache; + private File geolocationDB; - private static final Cache geolocationCache = CacheBuilder.newBuilder() - .build(); + public GeolocationCache() { + geolocationCache = new HashMap<>(); + } - /** - * Constructor used to hide the public constructor - */ - private GeolocationCache() { - throw new IllegalStateException("Utility class"); + @Override + public void enable() throws EnableException { + geolocationDB = new File(FileSystem.getDataFolder(), "GeoIP.dat"); + try { + GeolocationCache.checkDB(); + } catch (UnknownHostException e) { + Log.error("Plan Requires internet access on first run to download GeoLite2 Geolocation database."); + } catch (IOException e) { + throw new EnableException("Something went wrong saving the downloaded GeoLite2 Geolocation database", e); + } + } + + @Override + public void disable() { + } + + private static GeolocationCache getInstance() { + GeolocationCache geolocationCache = CacheSystem.getInstance().getGeolocationCache(); + Verify.nullCheck(geolocationCache, () -> new IllegalStateException("GeolocationCache was not initialized.")); + return geolocationCache; } /** @@ -60,7 +83,7 @@ public class GeolocationCache { return country; } else { country = getUnCachedCountry(ipAddress); - geolocationCache.put(ipAddress, country); + getInstance().geolocationCache.put(ipAddress, country); return country; } @@ -87,7 +110,7 @@ public class GeolocationCache { try { checkDB(); - try (DatabaseReader reader = new DatabaseReader.Builder(geolocationDB).build()) { + try (DatabaseReader reader = new DatabaseReader.Builder(getInstance().geolocationDB).build()) { InetAddress inetAddress = InetAddress.getByName(ipAddress); CountryResponse response = reader.country(inetAddress); @@ -107,12 +130,12 @@ public class GeolocationCache { * @throws IOException when an error at download or saving the DB happens */ public static void checkDB() throws IOException { - if (geolocationDB.exists()) { + if (getInstance().geolocationDB.exists()) { return; } URL downloadSite = new URL("http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz"); try (ReadableByteChannel rbc = Channels.newChannel(new GZIPInputStream(downloadSite.openStream())); - FileOutputStream fos = new FileOutputStream(geolocationDB.getAbsoluteFile())) { + FileOutputStream fos = new FileOutputStream(getInstance().geolocationDB.getAbsoluteFile())) { fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); } } @@ -124,7 +147,7 @@ public class GeolocationCache { * @return The cached country, {@code null} if the country is not cached */ private static String getCachedCountry(String ipAddress) { - return geolocationCache.getIfPresent(ipAddress); + return getInstance().geolocationCache.get(ipAddress); } /** @@ -134,13 +157,13 @@ public class GeolocationCache { * @return true if the IP Address is cached */ public static boolean isCached(String ipAddress) { - return geolocationCache.asMap().containsKey(ipAddress); + return getInstance().geolocationCache.containsKey(ipAddress); } /** * Clears the cache */ - public static void clearCache() { - geolocationCache.invalidateAll(); + public void clearCache() { + geolocationCache.clear(); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/cache/SessionCache.java b/Plan/src/main/java/com/djrapitops/plan/system/cache/SessionCache.java new file mode 100644 index 000000000..73cae746f --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/cache/SessionCache.java @@ -0,0 +1,135 @@ +package com.djrapitops.plan.system.cache; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.container.Session; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.connection.WebExceptionLogger; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +/** + * This class is used to store active sessions of players in memory. + * + * @author Rsl1122 + * @since 3.0.0 + */ +public class SessionCache { + + private static final Map firstSessionInformation = new HashMap<>(); + private static final Map activeSessions = new HashMap<>(); + protected final PlanSystem system; + + public SessionCache(PlanSystem system) { + this.system = system; + } + + public static SessionCache getInstance() { + DataCache dataCache = CacheSystem.getInstance().getDataCache(); + Verify.nullCheck(dataCache, () -> new IllegalStateException("Data Cache was not initialized.")); + return dataCache; + } + + /** + * Used to get the Map of active sessions. + *

+ * Used for testing. + * + * @return key:value UUID:Session + */ + public static Map getActiveSessions() { + return activeSessions; + } + + public static void clear() { + activeSessions.clear(); + } + + public void cacheSession(UUID uuid, Session session) { + activeSessions.put(uuid, session); + Processor.queue(() -> WebExceptionLogger.logIfOccurs(this.getClass(), () -> + system.getInfoSystem().generateAndCachePlayerPage(uuid)) + ); + } + + public void endSession(UUID uuid, long time) { + try { + Session session = activeSessions.get(uuid); + if (session == null) { + return; + } + session.endSession(time); + Database.getActive().save().session(uuid, session); + } catch (DBException e) { + Log.toLog(this.getClass(), e); + } finally { + activeSessions.remove(uuid); + + WebExceptionLogger.logIfOccurs(this.getClass(), () -> system.getInfoSystem().generateAndCachePlayerPage(uuid)); + } + } + + public static void refreshActiveSessionsState() { + for (Session session : activeSessions.values()) { + session.getWorldTimes().updateState(MiscUtils.getTime()); + } + } + + /** + * Used to get the Session of the player in the sessionCache. + * + * @param uuid UUID of the player. + * @return Session or null if not cached. + */ + public static Optional getCachedSession(UUID uuid) { + Session session = activeSessions.get(uuid); + if (session != null) { + return Optional.of(session); + } + return Optional.empty(); + } + + /** + * Used for marking first Session Actions to be saved. + * + * @param uuid UUID of the new player. + */ + public void markFirstSession(UUID uuid) { + firstSessionInformation.put(uuid, 0); + } + + /** + * Condition if a session is player's first session on the server. + * + * @param uuid UUID of the player + * @return true / false + */ + public boolean isFirstSession(UUID uuid) { + return firstSessionInformation.containsKey(uuid); + } + + public void endFirstSessionActionTracking(UUID uuid) { + firstSessionInformation.remove(uuid); + } + + public void firstSessionMessageSent(UUID uuid) { + Integer msgCount = firstSessionInformation.getOrDefault(uuid, 0); + msgCount++; + firstSessionInformation.put(uuid, msgCount); + } + + public int getFirstSessionMsgCount(UUID uuid) { + return firstSessionInformation.getOrDefault(uuid, 0); + } + + public Map getFirstSessionMsgCounts() { + return firstSessionInformation; + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/BukkitDBSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/database/BukkitDBSystem.java new file mode 100644 index 000000000..50837dc6e --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/BukkitDBSystem.java @@ -0,0 +1,27 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.database; + +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.sql.MySQLDB; +import com.djrapitops.plan.system.database.databases.sql.SQLiteDB; +import com.djrapitops.plan.system.settings.Settings; + +/** + * Bukkit Database system that initializes SQLite and MySQL database objects. + * + * @author Rsl1122 + */ +public class BukkitDBSystem extends DBSystem { + + @Override + protected void initDatabase() throws DBInitException { + databases.add(new MySQLDB()); + databases.add(new SQLiteDB()); + + String dbType = Settings.DB_TYPE.toString().toLowerCase().trim(); + db = getActiveDatabaseByName(dbType); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/BungeeDBSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/database/BungeeDBSystem.java new file mode 100644 index 000000000..36da79755 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/BungeeDBSystem.java @@ -0,0 +1,23 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.database; + +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.sql.MySQLDB; + +/** + * Bungee Database system that initializes MySQL object. + * + * @author Rsl1122 + */ +public class BungeeDBSystem extends DBSystem { + + @Override + protected void initDatabase() throws DBInitException { + db = new MySQLDB(); + databases.add(db); + db.init(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/DBSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/database/DBSystem.java new file mode 100644 index 000000000..d0bf54c71 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/DBSystem.java @@ -0,0 +1,92 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.database; + +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plugin.api.Benchmark; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.HashSet; +import java.util.Set; + +/** + * System that holds the active databases. + * + * @author Rsl1122 + */ +public abstract class DBSystem implements SubSystem { + + protected Database db; + protected Set databases; + + public DBSystem() { + databases = new HashSet<>(); + } + + public static DBSystem getInstance() { + DBSystem dbSystem = PlanSystem.getInstance().getDatabaseSystem(); + Verify.nullCheck(dbSystem, () -> new IllegalStateException("Database system was not initialized.")); + return dbSystem; + } + + @Override + public void enable() throws EnableException { + try { + Benchmark.start("Init Database"); + Log.info(Locale.get(Msg.ENABLE_DB_INIT).toString()); + initDatabase(); + db.scheduleClean(1L); + Log.info(Locale.get(Msg.ENABLE_DB_INFO).parse(db.getConfigName())); + Benchmark.stop("Enable", "Init Database"); + } catch (DBInitException e) { + throw new EnableException("Database failed to initialize", e); + } + } + + protected abstract void initDatabase() throws DBInitException; + + public Set getDatabases() { + return databases; + } + + @Override + public void disable() { + try { + if (db != null) { + db.close(); + } + } catch (DBException e) { + Log.toLog(this.getClass(), e); + } + } + + public Database getActiveDatabase() { + return db; + } + + public static Database getActiveDatabaseByName(String dbName) throws DBInitException { + for (Database database : getInstance().getDatabases()) { + String dbConfigName = database.getConfigName(); + if (Verify.equalsIgnoreCase(dbName, dbConfigName)) { + database.init(); + return database; + } + } + throw new DBInitException(Locale.get(Msg.ENABLE_FAIL_WRONG_DB) + " " + dbName); + } + + public void setActiveDatabase(Database db) throws DBException { + this.db.close(); + this.db = db; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/Database.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/Database.java new file mode 100644 index 000000000..692206289 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/Database.java @@ -0,0 +1,72 @@ +package com.djrapitops.plan.system.database.databases; + +import com.djrapitops.plan.api.exceptions.connection.UnsupportedTransferDatabaseException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.database.databases.operation.*; +import com.djrapitops.plugin.utilities.Verify; + +/** + * Abstract class representing a Database. + *

+ * All Operations methods should be only called from an asynchronous thread. + * + * @author Rsl1122 + */ +public abstract class Database { + + protected boolean open = false; + + public static Database getActive() { + Database database = DBSystem.getInstance().getActiveDatabase(); + Verify.nullCheck(database, () -> new IllegalStateException("Database was not initialized.")); + return database; + } + + public abstract void init() throws DBInitException; + + public abstract BackupOperations backup(); + + public abstract CheckOperations check(); + + public abstract FetchOperations fetch(); + + public abstract RemoveOperations remove(); + + public abstract SearchOperations search(); + + public abstract CountOperations count(); + + public abstract SaveOperations save(); + + /** + * Used to get the name of the database type. + *

+ * Thread safe. + * + * @return SQLite/MySQL + */ + public abstract String getName(); + + /** + * Used to get the config name of the database type. + *

+ * Thread safe. + * + * @return sqlite/mysql + */ + public String getConfigName() { + return getName().toLowerCase().trim(); + } + + public abstract void close() throws DBException; + + public boolean isOpen() { + return open; + } + + public abstract void scheduleClean(long delay); + + public abstract TransferOperations transfer() throws UnsupportedTransferDatabaseException; +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/BackupOperations.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/BackupOperations.java new file mode 100644 index 000000000..be20d5e97 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/BackupOperations.java @@ -0,0 +1,12 @@ +package com.djrapitops.plan.system.database.databases.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; + +public interface BackupOperations { + + void backup(Database toDatabase) throws DBException; + + void restore(Database fromDatabase) throws DBException; + +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/CheckOperations.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/CheckOperations.java new file mode 100644 index 000000000..c58e4f3b2 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/CheckOperations.java @@ -0,0 +1,21 @@ +package com.djrapitops.plan.system.database.databases.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.info.server.ServerInfo; + +import java.util.UUID; + +public interface CheckOperations { + + boolean isPlayerRegistered(UUID player) throws DBException; + + boolean isPlayerRegistered(UUID player, UUID server) throws DBException; + + boolean doesWebUserExists(String username) throws DBException; + + default boolean isPlayerRegisteredOnThisServer(UUID player) throws DBException { + return isPlayerRegistered(player, ServerInfo.getServerUUID()); + } + + boolean isServerInDatabase(UUID serverUUID) throws DBException; +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/CountOperations.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/CountOperations.java new file mode 100644 index 000000000..8ab728d06 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/CountOperations.java @@ -0,0 +1,12 @@ +package com.djrapitops.plan.system.database.databases.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; + +import java.util.UUID; + +public interface CountOperations { + + int getServerPlayerCount(UUID server) throws DBException; + + int getNetworkPlayerCount() throws DBException; +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/FetchOperations.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/FetchOperations.java new file mode 100644 index 000000000..f96d7c55d --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/FetchOperations.java @@ -0,0 +1,91 @@ +package com.djrapitops.plan.system.database.databases.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.PlayerProfile; +import com.djrapitops.plan.data.ServerProfile; +import com.djrapitops.plan.data.WebUser; +import com.djrapitops.plan.data.container.*; +import com.djrapitops.plan.system.info.server.Server; + +import java.util.*; + +public interface FetchOperations { + + // Profiles + + ServerProfile getServerProfile(UUID serverUUID) throws DBException; + + List getPlayers(UUID serverUUID) throws DBException; + + PlayerProfile getPlayerProfile(UUID uuid) throws DBException; + + // UUIDs + + Set getSavedUUIDs() throws DBException; + + Set getSavedUUIDs(UUID server) throws DBException; + + Map getServerNames() throws DBException; + + Optional getServerUUID(String serverName) throws DBException; + + UUID getUuidOf(String playerName) throws DBException; + + // WebUsers + + WebUser getWebUser(String username) throws DBException; + + // Servers + + Optional getServerName(UUID serverUUID) throws DBException; + + Optional getBungeeInformation() throws DBException; + + Optional getServerID(UUID serverUUID) throws DBException; + + // Raw Data + + List getTPSData(UUID serverUUID) throws DBException; + + List getNetworkOnlineData() throws DBException; + + List getRegisterDates() throws DBException; + + Optional getAllTimePeak(UUID serverUUID) throws DBException; + + Optional getPeakPlayerCount(UUID serverUUID, long afterDate) throws DBException; + + Map>> getSessionsWithNoExtras() throws DBException; + + Map>> getSessionsAndExtras() throws DBException; + + Set getWorldNames(UUID serverUuid) throws DBException; + + List getNicknamesOfPlayerOnServer(UUID uuid, UUID serverUUID) throws DBException; + + List getActions(UUID uuid) throws DBException; + + Map getUsers() throws DBException; + + Map getLastSeenForAllPlayers() throws DBException; + + Map> getAllGeoInfo() throws DBException; + + Map getPlayerNames() throws DBException; + + String getPlayerName(UUID playerUUID) throws DBException; + + List getNicknames(UUID uuid) throws DBException; + + Map getBukkitServers() throws DBException; + + List getWebUsers() throws DBException; + + Map getServerNamesByID() throws DBException; + + Map>> getSessionsInLastMonth() throws DBException; + + List getServers() throws DBException; + + List getServerUUIDs() throws DBException; +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/RemoveOperations.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/RemoveOperations.java new file mode 100644 index 000000000..672351821 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/RemoveOperations.java @@ -0,0 +1,18 @@ +package com.djrapitops.plan.system.database.databases.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; + +import java.util.UUID; + +public interface RemoveOperations { + + void player(UUID uuid) throws DBException; + + void player(UUID player, UUID server) throws DBException; + + void server(UUID serverUUID) throws DBException; + + void everything() throws DBException; + + void webUser(String name) throws DBException; +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/SaveOperations.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/SaveOperations.java new file mode 100644 index 000000000..29c3ff5a8 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/SaveOperations.java @@ -0,0 +1,73 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.database.databases.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.WebUser; +import com.djrapitops.plan.data.container.*; +import com.djrapitops.plan.system.info.server.Server; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * Operation methods for saving data. + * + * Note: Method names subject to change (TODO remove insert update and such) + * + * @author Rsl1122 + */ +public interface SaveOperations { + + // Bulk save + + void insertTPS(Map> ofServers) throws DBException; + + void insertCommandUsage(Map> ofServers) throws DBException; + + void insertUsers(Map ofServers) throws DBException; + + void insertSessions(Map>> ofServers, boolean containsExtraData) + throws DBException; + + void kickAmount(Map ofUsers) throws DBException; + + void insertUserInfo(Map> ofServers) throws DBException; + + void insertNicknames(Map>> ofServers) throws DBException; + + void insertAllGeoInfo(Map> ofUsers) throws DBException; + + // Single data point + + void banStatus(UUID uuid, boolean banned) throws DBException; + + void opStatus(UUID uuid, boolean op) throws DBException; + + void registerNewUser(UUID uuid, long registered, String name) throws DBException; + + void action(UUID uuid, Action action) throws DBException; + + void geoInfo(UUID uuid, GeoInfo geoInfo) throws DBException; + + void playerWasKicked(UUID uuid) throws DBException; + + void playerName(UUID uuid, String playerName) throws DBException; + + void playerDisplayName(UUID uuid, String displayName) throws DBException; + + void registerNewUserOnThisServer(UUID uuid, long registered) throws DBException; + + void commandUsed(String commandName) throws DBException; + + void insertTPSforThisServer(TPS tps) throws DBException; + + void session(UUID uuid, Session session) throws DBException; + + void serverInfoForThisServer(Server server) throws DBException; + + void webUser(WebUser webUser) throws DBException; +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/SearchOperations.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/SearchOperations.java new file mode 100644 index 000000000..a4662b1e3 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/SearchOperations.java @@ -0,0 +1,11 @@ +package com.djrapitops.plan.system.database.databases.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; + +import java.util.List; + +public interface SearchOperations { + + List matchingPlayers(String search) throws DBException; + +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/TransferOperations.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/TransferOperations.java new file mode 100644 index 000000000..982989143 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/operation/TransferOperations.java @@ -0,0 +1,49 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.database.databases.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; + +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +/** + * Operations for transferring data via Database to another server. + *

+ * Receiving server has to be using the same database. + * + * @author Rsl1122 + */ +public interface TransferOperations { + + // Save + + void storePlayerHtml(UUID player, String encodedHtml) throws DBException; + + void storeServerHtml(UUID serverUUID, String encodedHtml) throws DBException; + + void storeNetworkPageContent(UUID serverUUID, String encodedHtml) throws DBException; + + void storePlayerPluginsTab(UUID player, String encodedHtml) throws DBException; + + void storeConfigSettings(String encodedSettingString) throws DBException; + + void playerOnline(UUID playerUUID) throws DBException; + + // Get + + Map getEncodedPlayerHtml() throws DBException; + + Map getEncodedNetworkPageContent() throws DBException; + + Map getEncodedServerHtml() throws DBException; + + Optional getServerPlayerIsOnlineOn(UUID playerUUID) throws DBException; + + Map getEncodedPlayerPluginsTabs(UUID playerUUID) throws DBException; + + Optional getEncodedConfigSettings() throws DBException; +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/database/databases/MySQLDB.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/MySQLDB.java similarity index 84% rename from Plan/src/main/java/com/djrapitops/plan/database/databases/MySQLDB.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/MySQLDB.java index 9d9c75e49..34cf4fed0 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/databases/MySQLDB.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/MySQLDB.java @@ -1,6 +1,6 @@ -package com.djrapitops.plan.database.databases; +package com.djrapitops.plan.system.database.databases.sql; -import com.djrapitops.plan.settings.Settings; +import com.djrapitops.plan.system.settings.Settings; import com.djrapitops.plugin.api.utility.log.Log; import org.apache.commons.dbcp2.BasicDataSource; @@ -14,6 +14,9 @@ public class MySQLDB extends SQLDB { private BasicDataSource dataSource; + public MySQLDB() { + } + /** * Setups the {@link BasicDataSource} */ @@ -57,8 +60,12 @@ public class MySQLDB extends SQLDB { } @Override - public void close() throws SQLException { - dataSource.close(); + public void close() { + try { + dataSource.close(); + } catch (SQLException e) { + Log.toLog(this.getClass(), e); + } super.close(); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/SQLDB.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/SQLDB.java new file mode 100644 index 000000000..fbc282df8 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/SQLDB.java @@ -0,0 +1,382 @@ +package com.djrapitops.plan.system.database.databases.sql; + +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.database.databases.operation.*; +import com.djrapitops.plan.system.database.databases.sql.operation.*; +import com.djrapitops.plan.system.database.databases.sql.tables.*; +import com.djrapitops.plan.system.database.databases.sql.tables.move.Version8TransferTable; +import com.djrapitops.plugin.api.TimeAmount; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.task.AbsRunnable; +import com.djrapitops.plugin.task.ITask; +import com.djrapitops.plugin.task.RunnableFactory; +import org.apache.commons.dbcp2.BasicDataSource; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * Class containing main logic for different data related save and load functionality. + * + * @author Rsl1122 + * @since 2.0.0 + */ +public abstract class SQLDB extends Database { + + private final UsersTable usersTable; + private final UserInfoTable userInfoTable; + private final ActionsTable actionsTable; + private final KillsTable killsTable; + private final NicknamesTable nicknamesTable; + private final SessionsTable sessionsTable; + private final GeoInfoTable geoInfoTable; + private final CommandUseTable commandUseTable; + private final TPSTable tpsTable; + private final VersionTable versionTable; + private final SecurityTable securityTable; + private final WorldTable worldTable; + private final WorldTimesTable worldTimesTable; + private final ServerTable serverTable; + private final TransferTable transferTable; + + private final SQLBackupOps backupOps; + private final SQLCheckOps checkOps; + private final SQLFetchOps fetchOps; + private final SQLRemoveOps removeOps; + private final SQLSearchOps searchOps; + private final SQLCountOps countOps; + private final SQLSaveOps saveOps; + private final SQLTransferOps transferOps; + + private final boolean usingMySQL; + private ITask dbCleanTask; + + public SQLDB() { + usingMySQL = getName().equals("MySQL"); + + versionTable = new VersionTable(this); + serverTable = new ServerTable(this); + securityTable = new SecurityTable(this); + + commandUseTable = new CommandUseTable(this); + tpsTable = new TPSTable(this); + + usersTable = new UsersTable(this); + userInfoTable = new UserInfoTable(this); + actionsTable = new ActionsTable(this); + geoInfoTable = new GeoInfoTable(this); + nicknamesTable = new NicknamesTable(this); + sessionsTable = new SessionsTable(this); + killsTable = new KillsTable(this); + worldTable = new WorldTable(this); + worldTimesTable = new WorldTimesTable(this); + transferTable = new TransferTable(this); + + backupOps = new SQLBackupOps(this); + checkOps = new SQLCheckOps(this); + fetchOps = new SQLFetchOps(this); + removeOps = new SQLRemoveOps(this); + countOps = new SQLCountOps(this); + searchOps = new SQLSearchOps(this); + saveOps = new SQLSaveOps(this); + transferOps = new SQLTransferOps(this); + } + + /** + * Initializes the Database. + *

+ * All tables exist in the database after call to this. + * Updates Schema to latest version. + * Converts Unsaved Bukkit player files to database data. + * Cleans the database. + * + * @throws DBInitException if Database fails to initiate. + */ + @Override + public void init() throws DBInitException { + open = true; + setupDataSource(); + setupDatabase(); + } + + @Override + public void scheduleClean(long secondsDelay) { + dbCleanTask = RunnableFactory.createNew("DB Clean Task", new AbsRunnable() { + @Override + public void run() { + try { + if (isOpen()) { + clean(); + } + } catch (SQLException e) { + Log.toLog(this.getClass(), e); + } finally { + cancel(); + } + } + }).runTaskLaterAsynchronously(TimeAmount.SECOND.ticks() * secondsDelay); + } + + /** + * Ensures connection functions correctly and all tables exist. + *

+ * Updates to latest schema. + * + * @throws DBInitException if something goes wrong. + */ + public void setupDatabase() throws DBInitException { + try { + boolean newDatabase = versionTable.isNewDatabase(); + + versionTable.createTable(); + createTables(); + + if (newDatabase) { + Log.info("New Database created."); + versionTable.setVersion(13); + } + + int version = versionTable.getVersion(); + + final SQLDB db = this; + if (version < 10) { + RunnableFactory.createNew("DB v8 -> v10 Task", new AbsRunnable() { + @Override + public void run() { + try { + new Version8TransferTable(db).alterTablesToV10(); + } catch (DBInitException | SQLException e) { + Log.toLog(this.getClass(), e); + } + } + }).runTaskLaterAsynchronously(TimeAmount.SECOND.ticks() * 5L); + } + if (version < 11) { + serverTable.alterTableV11(); + versionTable.setVersion(11); + } + if (version < 12) { + actionsTable.alterTableV12(); + geoInfoTable.alterTableV12(); + versionTable.setVersion(12); + } + if (version < 13) { + geoInfoTable.alterTableV13(); + versionTable.setVersion(13); + } + } catch (SQLException e) { + throw new DBInitException("Failed to set-up Database", e); + } + } + + /** + * Creates the tables that contain data. + *

+ * Updates table columns to latest schema. + */ + private void createTables() throws DBInitException { + for (Table table : getAllTables()) { + table.createTable(); + } + } + + /** + * Get all tables in a create order. + * + * @return Table array. + */ + public Table[] getAllTables() { + return new Table[]{ + serverTable, usersTable, userInfoTable, geoInfoTable, + nicknamesTable, sessionsTable, killsTable, + commandUseTable, actionsTable, tpsTable, + worldTable, worldTimesTable, securityTable, transferTable + }; + } + + /** + * Get all tables for removal of data. + * + * @return Tables in the order the data should be removed in. + */ + public Table[] getAllTablesInRemoveOrder() { + return new Table[]{ + transferTable, geoInfoTable, nicknamesTable, killsTable, + worldTimesTable, sessionsTable, actionsTable, + worldTable, userInfoTable, usersTable, + commandUseTable, tpsTable, securityTable, + serverTable + }; + } + + /** + * Setups the {@link BasicDataSource} + */ + public abstract void setupDataSource() throws DBInitException; + + @Override + public void close() { + open = false; + if (dbCleanTask != null) { + dbCleanTask.cancel(); + } + } + + public int getVersion() throws SQLException { + return versionTable.getVersion(); + } + + public void setVersion(int version) throws SQLException { + versionTable.setVersion(version); + } + + private void clean() throws SQLException { + Log.info("Cleaning the database."); + tpsTable.clean(); + transferTable.clean(); + Log.info("Clean complete."); + } + + public abstract Connection getConnection() throws SQLException; + + /** + * Commits changes to the .db file when using SQLite Database. + *

+ * MySQL has Auto Commit enabled. + */ + public void commit(Connection connection) throws SQLException { + try { + if (!usingMySQL) { + connection.commit(); + } + } catch (SQLException e) { + if (!e.getMessage().contains("cannot commit")) { + Log.toLog(this.getClass(), e); + } + } finally { + returnToPool(connection); + } + } + + public void returnToPool(Connection connection) throws SQLException { + if (usingMySQL && connection != null) { + connection.close(); + } + } + + /** + * Reverts transaction when using SQLite Database. + *

+ * MySQL has Auto Commit enabled. + */ + public void rollback(Connection connection) throws SQLException { + try { + if (!usingMySQL) { + connection.rollback(); + } + } finally { + returnToPool(connection); + } + } + + public UsersTable getUsersTable() { + return usersTable; + } + + public SessionsTable getSessionsTable() { + return sessionsTable; + } + + public KillsTable getKillsTable() { + return killsTable; + } + + public GeoInfoTable getGeoInfoTable() { + return geoInfoTable; + } + + public NicknamesTable getNicknamesTable() { + return nicknamesTable; + } + + public CommandUseTable getCommandUseTable() { + return commandUseTable; + } + + public TPSTable getTpsTable() { + return tpsTable; + } + + public SecurityTable getSecurityTable() { + return securityTable; + } + + public WorldTable getWorldTable() { + return worldTable; + } + + public WorldTimesTable getWorldTimesTable() { + return worldTimesTable; + } + + public ServerTable getServerTable() { + return serverTable; + } + + public ActionsTable getActionsTable() { + return actionsTable; + } + + public UserInfoTable getUserInfoTable() { + return userInfoTable; + } + + public TransferTable getTransferTable() { + return transferTable; + } + + public boolean isUsingMySQL() { + return this instanceof MySQLDB; + } + + @Override + public BackupOperations backup() { + return backupOps; + } + + @Override + public CheckOperations check() { + return checkOps; + } + + @Override + public FetchOperations fetch() { + return fetchOps; + } + + @Override + public RemoveOperations remove() { + return removeOps; + } + + @Override + public SearchOperations search() { + return searchOps; + } + + @Override + public CountOperations count() { + return countOps; + } + + @Override + public SaveOperations save() { + return saveOps; + } + + @Override + public TransferOperations transfer() { + return transferOps; + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/SQLiteDB.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/SQLiteDB.java new file mode 100644 index 000000000..2467321aa --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/SQLiteDB.java @@ -0,0 +1,139 @@ +package com.djrapitops.plan.system.database.databases.sql; + +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.task.AbsRunnable; +import com.djrapitops.plugin.task.ITask; +import com.djrapitops.plugin.task.RunnableFactory; +import org.apache.commons.dbcp2.BasicDataSource; + +import java.io.File; +import java.sql.*; + +/** + * @author Rsl1122 + */ +public class SQLiteDB extends SQLDB { + + private final String dbName; + private Connection connection; + private ITask connectionPingTask; + + /** + * Class Constructor. + */ + public SQLiteDB() { + this("database"); + } + + public SQLiteDB(String dbName) { + this.dbName = dbName; + } + + /** + * Setups the {@link BasicDataSource} + */ + @Override + public void setupDataSource() throws DBInitException { + try { + connection = getNewConnection(dbName); + } catch (SQLException e) { + throw new DBInitException(e); + } + startConnectionPingTask(); + } + + public Connection getNewConnection(String dbName) throws SQLException { + try { + Class.forName("org.sqlite.JDBC"); + } catch (ClassNotFoundException e) { + Log.toLog(this.getClass(), e); + return null; // Should never happen. + } + + String dbFilePath = new File(PlanPlugin.getInstance().getDataFolder(), dbName + ".db").getAbsolutePath(); + + Connection newConnection = getConnectionFor(dbFilePath); + Log.debug("SQLite " + dbName + ": Opened a new Connection"); + newConnection.setAutoCommit(false); + return newConnection; + } + + private Connection getConnectionFor(String dbFilePath) throws SQLException { + try { + return DriverManager.getConnection("jdbc:sqlite:" + dbFilePath + "?journal_mode=WAL"); + } catch (SQLException ignored) { + Log.info("SQLite WAL mode not supported on this server version, using default. This may or may not affect performance."); + return DriverManager.getConnection("jdbc:sqlite:" + dbFilePath); + } + } + + private void startConnectionPingTask() { + stopConnectionPingTask(); + try { + // Maintains Connection. + connectionPingTask = RunnableFactory.createNew(new AbsRunnable("DBConnectionPingTask " + getName()) { + @Override + public void run() { + Statement statement = null; + ResultSet resultSet = null; + try { + if (connection != null && !connection.isClosed()) { + statement = connection.createStatement(); + resultSet = statement.executeQuery("/* ping */ SELECT 1"); + } + } catch (SQLException e) { + Log.debug("Something went wrong during Ping task."); + try { + connection = getNewConnection(dbName); + } catch (SQLException e1) { + Log.toLog(this.getClass(), e1); + Log.error("SQLite connection maintaining task had to be closed due to exception."); + this.cancel(); + } + } finally { + MiscUtils.close(statement, resultSet); + } + } + }).runTaskTimerAsynchronously(60L * 20L, 60L * 20L); + } catch (Exception ignored) { + } + } + + private void stopConnectionPingTask() { + if (connectionPingTask != null) { + try { + connectionPingTask.cancel(); + } catch (Exception ignored) { + } + } + } + + /** + * @return the name of the Database + */ + @Override + public String getName() { + return "SQLite"; + } + + @Override + public Connection getConnection() throws SQLException { + if (connection == null) { + connection = getNewConnection(dbName); + } + return connection; + } + + @Override + public void close() { + stopConnectionPingTask(); + if (connection != null) { + Log.debug("SQLite " + dbName + ": Closed Connection"); + MiscUtils.close(connection); + } + super.close(); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLBackupOps.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLBackupOps.java new file mode 100644 index 000000000..d9cfca617 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLBackupOps.java @@ -0,0 +1,22 @@ +package com.djrapitops.plan.system.database.databases.sql.operation; + +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.database.databases.operation.BackupOperations; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; + +public class SQLBackupOps extends SQLOps implements BackupOperations { + + public SQLBackupOps(SQLDB db) { + super(db); + } + + @Override + public void backup(Database toDatabase) { + // TODO + } + + @Override + public void restore(Database fromDatabase) { + // TODO + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLCheckOps.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLCheckOps.java new file mode 100644 index 000000000..a496a03ef --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLCheckOps.java @@ -0,0 +1,57 @@ +package com.djrapitops.plan.system.database.databases.sql.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.operation.CheckOperations; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.info.server.ServerInfo; + +import java.sql.SQLException; +import java.util.UUID; + +public class SQLCheckOps extends SQLOps implements CheckOperations { + + public SQLCheckOps(SQLDB db) { + super(db); + } + + @Override + public boolean isPlayerRegistered(UUID player) throws DBException { + try { + return usersTable.isRegistered(player); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public boolean isPlayerRegistered(UUID player, UUID server) throws DBException { + try { + return userInfoTable.isRegistered(player, server); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public boolean doesWebUserExists(String username) throws DBException { + try { + return securityTable.userExists(username); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public boolean isPlayerRegisteredOnThisServer(UUID player) throws DBException { + return isPlayerRegistered(player, ServerInfo.getServerUUID()); + } + + @Override + public boolean isServerInDatabase(UUID serverUUID) throws DBException { + try { + return serverTable.getServerID(serverUUID).isPresent(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLCountOps.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLCountOps.java new file mode 100644 index 000000000..7d544aca9 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLCountOps.java @@ -0,0 +1,33 @@ +package com.djrapitops.plan.system.database.databases.sql.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.operation.CountOperations; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; + +import java.sql.SQLException; +import java.util.UUID; + +public class SQLCountOps extends SQLOps implements CountOperations { + + public SQLCountOps(SQLDB db) { + super(db); + } + + @Override + public int getServerPlayerCount(UUID server) throws DBException { + try { + return userInfoTable.getServerUserCount(server); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public int getNetworkPlayerCount() throws DBException { + try { + return usersTable.getPlayerCount(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLErrorUtil.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLErrorUtil.java new file mode 100644 index 000000000..6fa20cb0d --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLErrorUtil.java @@ -0,0 +1,38 @@ +package com.djrapitops.plan.system.database.databases.sql.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.api.exceptions.database.FatalDBException; + +import java.sql.SQLException; + +public class SQLErrorUtil { + + private SQLErrorUtil() { + } + + public static DBException getExceptionFor(SQLException e) { + String message = e.getMessage(); + if (message.contains("Communications link failure")) { + return new FatalDBException("MySQL-connection failed", e); + } else if (message.contains("constraint failed")) { + return new FatalDBException("There is an error in saving an item.", e); + } else if (message.contains("syntax") + || message.contains("SQL Error or missing database") + || message.contains("SQLITE_MISUSE") + || message.contains("no such column")) { + return new FatalDBException("There is an error in SQL syntax", e); + } else if (message.contains("duplicate key")) { + return new FatalDBException("An SQL save method attempts to save duplicates.", e); + } + return new DBException(e); + } + + public static FatalDBException getFatalExceptionFor(SQLException e) { + DBException normalException = getExceptionFor(e); + if (normalException instanceof FatalDBException) { + return (FatalDBException) normalException; + } else { + return new FatalDBException(normalException.getCause()); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLFetchOps.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLFetchOps.java new file mode 100644 index 000000000..3526307cd --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLFetchOps.java @@ -0,0 +1,419 @@ +package com.djrapitops.plan.system.database.databases.sql.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.PlayerProfile; +import com.djrapitops.plan.data.ServerProfile; +import com.djrapitops.plan.data.WebUser; +import com.djrapitops.plan.data.container.*; +import com.djrapitops.plan.system.database.databases.operation.FetchOperations; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plugin.api.TimeAmount; + +import java.sql.SQLException; +import java.util.*; + +public class SQLFetchOps extends SQLOps implements FetchOperations { + + public SQLFetchOps(SQLDB db) { + super(db); + } + + @Override + public ServerProfile getServerProfile(UUID serverUUID) throws DBException { + try { + ServerProfile profile = new ServerProfile(serverUUID); + + profile.setPlayers(getPlayers(serverUUID)); + profile.setTps(tpsTable.getTPSData(serverUUID)); + Optional allTimePeak = tpsTable.getAllTimePeak(serverUUID); + allTimePeak.ifPresent(peak -> { + profile.setAllTimePeak(peak.getDate()); + profile.setAllTimePeakPlayers(peak.getPlayers()); + }); + Optional lastPeak = tpsTable.getPeakPlayerCount(serverUUID, MiscUtils.getTime() - (TimeAmount.DAY.ms() * 2L)); + lastPeak.ifPresent(peak -> { + profile.setLastPeakDate(peak.getDate()); + profile.setLastPeakPlayers(peak.getPlayers()); + }); + + profile.setCommandUsage(commandUseTable.getCommandUse(serverUUID)); + profile.setServerWorldtimes(worldTimesTable.getWorldTimesOfServer(serverUUID)); + + return profile; + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public List getPlayers(UUID serverUUID) throws DBException { + try { + List serverUserInfo = userInfoTable.getServerUserInfo(serverUUID); + Map timesKicked = usersTable.getAllTimesKicked(); + Map> actions = actionsTable.getServerActions(serverUUID); + Map> geoInfo = geoInfoTable.getAllGeoInfo(); + + Map> sessions = sessionsTable.getSessionInfoOfServer(serverUUID); + Map>> map = new HashMap<>(); + map.put(serverUUID, sessions); + killsTable.addKillsToSessions(map); + worldTimesTable.addWorldTimesToSessions(map); + + List players = new ArrayList<>(); + + for (UserInfo userInfo : serverUserInfo) { + UUID uuid = userInfo.getUuid(); + PlayerProfile profile = new PlayerProfile(uuid, userInfo.getName(), userInfo.getRegistered()); + profile.setTimesKicked(timesKicked.getOrDefault(uuid, 0)); + if (userInfo.isBanned()) { + profile.bannedOnServer(serverUUID); + } + if (userInfo.isOpped()) { + profile.oppedOnServer(serverUUID); + } + profile.setActions(actions.getOrDefault(uuid, new ArrayList<>())); + profile.setGeoInformation(geoInfo.getOrDefault(uuid, new ArrayList<>())); + profile.setSessions(serverUUID, sessions.getOrDefault(uuid, new ArrayList<>())); + + players.add(profile); + } + return players; + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public PlayerProfile getPlayerProfile(UUID uuid) throws DBException { + try { + if (!usersTable.isRegistered(uuid)) { + return null; + } + + String playerName = usersTable.getPlayerName(uuid); + Optional registerDate = usersTable.getRegisterDate(uuid); + + if (!registerDate.isPresent()) { + throw new IllegalStateException("User has been saved with null register date to a NOT NULL column"); + } + + PlayerProfile profile = new PlayerProfile(uuid, playerName, registerDate.get()); + profile.setTimesKicked(usersTable.getTimesKicked(uuid)); + + Map userInfo = userInfoTable.getAllUserInfo(uuid); + addUserInfoToProfile(profile, userInfo); + + profile.setActions(actionsTable.getActions(uuid)); + profile.setNicknames(nicknamesTable.getAllNicknames(uuid)); + profile.setGeoInformation(geoInfoTable.getGeoInfo(uuid)); + + Map> sessions = sessionsTable.getSessions(uuid); + profile.setSessions(sessions); + profile.calculateWorldTimesPerServer(); + profile.setTotalWorldTimes(worldTimesTable.getWorldTimesOfUser(uuid)); + + return profile; + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + private void addUserInfoToProfile(PlayerProfile profile, Map userInfo) { + for (Map.Entry entry : userInfo.entrySet()) { + UUID serverUUID = entry.getKey(); + UserInfo info = entry.getValue(); + + profile.setRegistered(serverUUID, info.getRegistered()); + if (info.isBanned()) { + profile.bannedOnServer(serverUUID); + } + if (info.isOpped()) { + profile.oppedOnServer(serverUUID); + } + } + } + + @Override + public Set getSavedUUIDs() throws DBException { + try { + return usersTable.getSavedUUIDs(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Set getSavedUUIDs(UUID server) throws DBException { + try { + return userInfoTable.getSavedUUIDs(server); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map getServerNames() throws DBException { + try { + return serverTable.getServerNames(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Optional getServerUUID(String serverName) throws DBException { + try { + return serverTable.getServerUUID(serverName); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public UUID getUuidOf(String playerName) throws DBException { + try { + return usersTable.getUuidOf(playerName); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public WebUser getWebUser(String username) throws DBException { + try { + return securityTable.getWebUser(username); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public List getTPSData(UUID serverUUID) throws DBException { + try { + return tpsTable.getTPSData(serverUUID); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public List getNetworkOnlineData() throws DBException { + try { + return tpsTable.getNetworkOnlineData(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public List getRegisterDates() throws DBException { + try { + return usersTable.getRegisterDates(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Optional getAllTimePeak(UUID serverUUID) throws DBException { + try { + return tpsTable.getAllTimePeak(serverUUID); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Optional getPeakPlayerCount(UUID serverUUID, long afterDate) throws DBException { + try { + return tpsTable.getPeakPlayerCount(serverUUID, afterDate); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map>> getSessionsWithNoExtras() throws DBException { + try { + return sessionsTable.getAllSessions(false); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map>> getSessionsAndExtras() throws DBException { + try { + return sessionsTable.getAllSessions(true); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map>> getSessionsInLastMonth() throws DBException { + try { + return sessionsTable.getSessionInLastMonth(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Set getWorldNames(UUID serverUuid) throws DBException { + try { + return worldTable.getWorldNames(serverUuid); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public List getNicknamesOfPlayerOnServer(UUID uuid, UUID serverUUID) throws DBException { + try { + return nicknamesTable.getNicknames(uuid, serverUUID); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public List getActions(UUID uuid) throws DBException { + try { + return actionsTable.getActions(uuid); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map getUsers() throws DBException { + try { + return usersTable.getUsers(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map getLastSeenForAllPlayers() throws DBException { + try { + return sessionsTable.getLastSeenForAllPlayers(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map> getAllGeoInfo() throws DBException { + try { + return geoInfoTable.getAllGeoInfo(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map getPlayerNames() throws DBException { + try { + return usersTable.getPlayerNames(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public String getPlayerName(UUID playerUUID) throws DBException { + try { + return usersTable.getPlayerName(playerUUID); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Optional getServerName(UUID serverUUID) throws DBException { + try { + return serverTable.getServerName(serverUUID); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public List getNicknames(UUID uuid) throws DBException { + try { + return nicknamesTable.getNicknames(uuid); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Optional getBungeeInformation() throws DBException { + try { + return serverTable.getBungeeInfo(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Optional getServerID(UUID serverUUID) throws DBException { + try { + return serverTable.getServerID(serverUUID); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map getBukkitServers() throws DBException { + try { + return serverTable.getBukkitServers(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public List getWebUsers() throws DBException { + try { + return securityTable.getUsers(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map getServerNamesByID() throws DBException { + try { + return serverTable.getServerNamesByID(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public List getServers() throws DBException { + Map bukkitServers = getBukkitServers(); + Optional bungeeInformation = getBungeeInformation(); + + List servers = new ArrayList<>(bukkitServers.values()); + bungeeInformation.ifPresent(servers::add); + + Collections.sort(servers); + return servers; + } + + @Override + public List getServerUUIDs() throws DBException { + try { + return serverTable.getServerUUIDs(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLOps.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLOps.java new file mode 100644 index 000000000..72de0ab2f --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLOps.java @@ -0,0 +1,43 @@ +package com.djrapitops.plan.system.database.databases.sql.operation; + +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.tables.*; + +public class SQLOps { + + protected final SQLDB db; + + protected final UsersTable usersTable; + protected final UserInfoTable userInfoTable; + protected final ActionsTable actionsTable; + protected final KillsTable killsTable; + protected final NicknamesTable nicknamesTable; + protected final SessionsTable sessionsTable; + protected final GeoInfoTable geoInfoTable; + protected final CommandUseTable commandUseTable; + protected final TPSTable tpsTable; + protected final SecurityTable securityTable; + protected final WorldTable worldTable; + protected final WorldTimesTable worldTimesTable; + protected final ServerTable serverTable; + protected final TransferTable transferTable; + + public SQLOps(SQLDB db) { + this.db = db; + + usersTable = db.getUsersTable(); + userInfoTable = db.getUserInfoTable(); + actionsTable = db.getActionsTable(); + killsTable = db.getKillsTable(); + nicknamesTable = db.getNicknamesTable(); + sessionsTable = db.getSessionsTable(); + geoInfoTable = db.getGeoInfoTable(); + commandUseTable = db.getCommandUseTable(); + tpsTable = db.getTpsTable(); + securityTable = db.getSecurityTable(); + worldTable = db.getWorldTable(); + worldTimesTable = db.getWorldTimesTable(); + serverTable = db.getServerTable(); + transferTable = db.getTransferTable(); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLRemoveOps.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLRemoveOps.java new file mode 100644 index 000000000..d48ebbe7f --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLRemoveOps.java @@ -0,0 +1,72 @@ +package com.djrapitops.plan.system.database.databases.sql.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.api.exceptions.database.FatalDBException; +import com.djrapitops.plan.system.database.databases.operation.RemoveOperations; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.tables.Table; +import com.djrapitops.plan.system.database.databases.sql.tables.UserIDTable; + +import java.sql.SQLException; +import java.util.UUID; + +public class SQLRemoveOps extends SQLOps implements RemoveOperations { + + public SQLRemoveOps(SQLDB db) { + super(db); + } + + @Override + public void player(UUID uuid) throws DBException { + if (uuid == null) { + return; + } + + try { + String webUser = usersTable.getPlayerName(uuid); + + for (Table t : db.getAllTablesInRemoveOrder()) { + if (!(t instanceof UserIDTable)) { + continue; + } + + UserIDTable table = (UserIDTable) t; + table.removeUser(uuid); + } + + securityTable.removeUser(webUser); + } catch (SQLException e) { + throw SQLErrorUtil.getFatalExceptionFor(e); + } + } + + @Override + public void player(UUID player, UUID server) throws DBException { + throw new FatalDBException("Not Implemented"); + } + + @Override + public void server(UUID serverUUID) throws DBException { + throw new FatalDBException("Not Implemented"); + } + + @Override + public void everything() throws DBException { + try { + for (Table table : db.getAllTablesInRemoveOrder()) { + table.removeAllData(); + } + } catch (SQLException e) { + throw SQLErrorUtil.getFatalExceptionFor(e); + } + } + + @Override + public void webUser(String userName) throws DBException { + try { + securityTable.removeUser(userName); + } catch (SQLException e) { + throw SQLErrorUtil.getFatalExceptionFor(e); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLSaveOps.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLSaveOps.java new file mode 100644 index 000000000..45b93514e --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLSaveOps.java @@ -0,0 +1,227 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.database.databases.sql.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.WebUser; +import com.djrapitops.plan.data.container.*; +import com.djrapitops.plan.system.database.databases.operation.SaveOperations; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.info.server.Server; + +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * SaveOperations implementation for SQL databases. + * + * @author Rsl1122 + */ +public class SQLSaveOps extends SQLOps implements SaveOperations { + + public SQLSaveOps(SQLDB db) { + super(db); + } + + @Override + public void insertTPS(Map> ofServers) throws DBException { + try { + tpsTable.insertAllTPS(ofServers); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void insertCommandUsage(Map> ofServers) throws DBException { + try { + commandUseTable.insertCommandUsage(ofServers); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void insertUsers(Map ofServers) throws DBException { + try { + usersTable.insertUsers(ofServers); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void insertSessions(Map>> ofServers, boolean containsExtraData) throws DBException { + try { + sessionsTable.insertSessions(ofServers, containsExtraData); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void kickAmount(Map ofUsers) throws DBException { + try { + usersTable.updateKicked(ofUsers); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void insertUserInfo(Map> ofServers) throws DBException { + try { + userInfoTable.insertUserInfo(ofServers); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void insertNicknames(Map>> ofServers) throws DBException { + try { + nicknamesTable.insertNicknames(ofServers); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void insertAllGeoInfo(Map> ofUsers) throws DBException { + try { + geoInfoTable.insertAllGeoInfo(ofUsers); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void banStatus(UUID uuid, boolean banned) throws DBException { + try { + userInfoTable.updateBanStatus(uuid, banned); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void opStatus(UUID uuid, boolean op) throws DBException { + try { + userInfoTable.updateOpStatus(uuid, op); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void registerNewUser(UUID uuid, long registered, String name) throws DBException { + try { + usersTable.registerUser(uuid, registered, name); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void action(UUID uuid, Action action) throws DBException { + try { + actionsTable.insertAction(uuid, action); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void geoInfo(UUID uuid, GeoInfo geoInfo) throws DBException { + try { + geoInfoTable.saveGeoInfo(uuid, geoInfo); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void playerWasKicked(UUID uuid) throws DBException { + try { + usersTable.kicked(uuid); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void playerName(UUID uuid, String playerName) throws DBException { + try { + usersTable.updateName(uuid, playerName); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void playerDisplayName(UUID uuid, String displayName) throws DBException { + try { + nicknamesTable.saveUserName(uuid, displayName); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void registerNewUserOnThisServer(UUID uuid, long registered) throws DBException { + try { + userInfoTable.registerUserInfo(uuid, registered); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void commandUsed(String commandName) throws DBException { + try { + commandUseTable.commandUsed(commandName); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void insertTPSforThisServer(TPS tps) throws DBException { + try { + tpsTable.insertTPS(tps); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void session(UUID uuid, Session session) throws DBException { + try { + sessionsTable.saveSession(uuid, session); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void serverInfoForThisServer(Server server) throws DBException { + try { + serverTable.saveCurrentServerInfo(server); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void webUser(WebUser webUser) throws DBException { + try { + securityTable.addNewUser(webUser); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLSearchOps.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLSearchOps.java new file mode 100644 index 000000000..a560fbd6e --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLSearchOps.java @@ -0,0 +1,24 @@ +package com.djrapitops.plan.system.database.databases.sql.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.operation.SearchOperations; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; + +import java.sql.SQLException; +import java.util.List; + +public class SQLSearchOps extends SQLOps implements SearchOperations { + + public SQLSearchOps(SQLDB db) { + super(db); + } + + @Override + public List matchingPlayers(String search) throws DBException { + try { + return usersTable.getMatchingNames(search); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLTransferOps.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLTransferOps.java new file mode 100644 index 000000000..6611a10ce --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/SQLTransferOps.java @@ -0,0 +1,134 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.database.databases.sql.operation; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.operation.TransferOperations; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; + +import java.sql.SQLException; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +/** + * TransferOperations for MySQL Database. + * + * @author Rsl1122 + */ +public class SQLTransferOps extends SQLOps implements TransferOperations { + + public SQLTransferOps(SQLDB db) { + super(db); + } + + @Override + public void storePlayerHtml(UUID player, String encodedHtml) throws DBException { + try { + transferTable.storePlayerHtml(player, encodedHtml); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void storeServerHtml(UUID serverUUID, String encodedHtml) throws DBException { + try { + transferTable.storeServerHtml(serverUUID, encodedHtml); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void storeNetworkPageContent(UUID serverUUID, String encodedHtml) throws DBException { + try { + transferTable.storeNetworkPageContent(serverUUID, encodedHtml); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map getEncodedPlayerHtml() throws DBException { + try { + return transferTable.getPlayerHtml(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map getEncodedNetworkPageContent() throws DBException { + try { + return transferTable.getNetworkPageContent(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map getEncodedServerHtml() throws DBException { + try { + return transferTable.getServerHtml(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void storePlayerPluginsTab(UUID player, String encodedHtml) throws DBException { + try { + transferTable.storePlayerPluginsTab(player, encodedHtml); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Optional getServerPlayerIsOnlineOn(UUID playerUUID) throws DBException { + try { + return transferTable.getServerPlayerIsOnline(playerUUID); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Map getEncodedPlayerPluginsTabs(UUID playerUUID) throws DBException { + try { + return transferTable.getPlayerPluginsTabs(playerUUID); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void storeConfigSettings(String encodedSettingString) throws DBException { + try { + transferTable.storeConfigSettings(encodedSettingString); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public Optional getEncodedConfigSettings() throws DBException { + try { + return transferTable.getConfigSettings(); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } + + @Override + public void playerOnline(UUID playerUUID) throws DBException { + try { + transferTable.storePlayerOnlineOnThisServer(playerUUID); + } catch (SQLException e) { + throw SQLErrorUtil.getExceptionFor(e); + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/database/processing/ExecStatement.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/processing/ExecStatement.java similarity index 59% rename from Plan/src/main/java/com/djrapitops/plan/database/processing/ExecStatement.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/processing/ExecStatement.java index 0efe6c60b..8a6b00776 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/processing/ExecStatement.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/processing/ExecStatement.java @@ -1,41 +1,54 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.database.processing; +package com.djrapitops.plan.system.database.databases.sql.processing; + +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plugin.api.Benchmark; +import com.djrapitops.plugin.api.utility.log.Log; import java.sql.PreparedStatement; import java.sql.SQLException; /** - * //TODO Class Javadoc Comment + * SQL executing statement that closes appropriate elements. * * @author Rsl1122 */ public abstract class ExecStatement { private final String sql; + private final boolean devMode; public ExecStatement(String sql) { this.sql = sql; -// Log.debug("Execute Statement: " + sql); + devMode = Settings.DEV_MODE.isTrue(); } public boolean execute(PreparedStatement statement) throws SQLException { + Benchmark.start("SQL: " + sql); try { prepare(statement); return statement.executeUpdate() > 0; } finally { statement.close(); + if (devMode) { + Log.debug(Benchmark.stopAndFormat("SQL: " + sql)); + } } } public void executeBatch(PreparedStatement statement) throws SQLException { + Benchmark.start("SQL: " + sql + " (Batch)"); try { prepare(statement); statement.executeBatch(); } finally { statement.close(); + if (devMode) { + Log.debug(Benchmark.stopAndFormat("SQL: " + sql + " (Batch)")); + } } } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/processing/QueryAllStatement.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/processing/QueryAllStatement.java similarity index 83% rename from Plan/src/main/java/com/djrapitops/plan/database/processing/QueryAllStatement.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/processing/QueryAllStatement.java index e7d0247ff..c552b1a74 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/processing/QueryAllStatement.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/processing/QueryAllStatement.java @@ -1,15 +1,15 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.database.processing; +package com.djrapitops.plan.system.database.databases.sql.processing; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** - * //TODO Class Javadoc Comment + * SQL query that doesn't require preparing that closes proper elements. * * @author Rsl1122 */ diff --git a/Plan/src/main/java/com/djrapitops/plan/database/processing/QueryStatement.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/processing/QueryStatement.java similarity index 70% rename from Plan/src/main/java/com/djrapitops/plan/database/processing/QueryStatement.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/processing/QueryStatement.java index e024374bb..ed48e6adc 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/processing/QueryStatement.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/processing/QueryStatement.java @@ -1,15 +1,19 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.database.processing; +package com.djrapitops.plan.system.database.databases.sql.processing; + +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plugin.api.Benchmark; +import com.djrapitops.plugin.api.utility.log.Log; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** - * //TODO Class Javadoc Comment + * SQL query that closes proper elements. * * @author Rsl1122 */ @@ -17,6 +21,7 @@ public abstract class QueryStatement { private final String sql; private final int fetchSize; + private boolean devMode; public QueryStatement(String sql) { this(sql, 10); @@ -24,11 +29,12 @@ public abstract class QueryStatement { public QueryStatement(String sql, int fetchSize) { this.sql = sql; -// Log.debug("Query Statement: " + sql); + devMode = Settings.DEV_MODE.isTrue(); this.fetchSize = fetchSize; } public T executeQuery(PreparedStatement statement) throws SQLException { + Benchmark.start("SQL: " + sql); try { statement.setFetchSize(fetchSize); prepare(statement); @@ -37,6 +43,9 @@ public abstract class QueryStatement { } } finally { statement.close(); + if (devMode) { + Log.debug(Benchmark.stopAndFormat("SQL: " + sql)); + } } } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/sql/Insert.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Insert.java similarity index 91% rename from Plan/src/main/java/com/djrapitops/plan/database/sql/Insert.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Insert.java index 7acba858a..b3e7a44c2 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/sql/Insert.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Insert.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.database.sql; +package com.djrapitops.plan.system.database.databases.sql.statements; public class Insert extends SqlParser { diff --git a/Plan/src/main/java/com/djrapitops/plan/database/sql/Select.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Select.java similarity index 89% rename from Plan/src/main/java/com/djrapitops/plan/database/sql/Select.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Select.java index 142f36a0b..9ed55c38c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/sql/Select.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Select.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.database.sql; +package com.djrapitops.plan.system.database.databases.sql.statements; public class Select extends WhereParser { diff --git a/Plan/src/main/java/com/djrapitops/plan/database/sql/Sql.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Sql.java similarity index 85% rename from Plan/src/main/java/com/djrapitops/plan/database/sql/Sql.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Sql.java index c9b552060..973c2d38b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/sql/Sql.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Sql.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.database.sql; +package com.djrapitops.plan.system.database.databases.sql.statements; public class Sql { public static final String INT = "integer"; diff --git a/Plan/src/main/java/com/djrapitops/plan/database/sql/SqlParser.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/SqlParser.java similarity index 88% rename from Plan/src/main/java/com/djrapitops/plan/database/sql/SqlParser.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/SqlParser.java index 9110e135a..0d6109bfe 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/sql/SqlParser.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/SqlParser.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.database.sql; +package com.djrapitops.plan.system.database.databases.sql.statements; /** * Class for parsing different SQL strings. diff --git a/Plan/src/main/java/com/djrapitops/plan/database/sql/TableSqlParser.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/TableSqlParser.java similarity index 97% rename from Plan/src/main/java/com/djrapitops/plan/database/sql/TableSqlParser.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/TableSqlParser.java index 0f286a891..ec0a0df70 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/sql/TableSqlParser.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/TableSqlParser.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.database.sql; +package com.djrapitops.plan.system.database.databases.sql.statements; /** * SqlParser Class for parsing table creation, removal and modification statements. diff --git a/Plan/src/main/java/com/djrapitops/plan/database/sql/Update.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Update.java similarity index 90% rename from Plan/src/main/java/com/djrapitops/plan/database/sql/Update.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Update.java index 183f0a2fb..9e9b4b73c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/sql/Update.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/Update.java @@ -1,8 +1,8 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.database.sql; +package com.djrapitops.plan.system.database.databases.sql.statements; /** * @author Fuzzlemann diff --git a/Plan/src/main/java/com/djrapitops/plan/database/sql/WhereParser.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/WhereParser.java similarity index 93% rename from Plan/src/main/java/com/djrapitops/plan/database/sql/WhereParser.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/WhereParser.java index d38bb0ce3..7b534abf3 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/sql/WhereParser.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/statements/WhereParser.java @@ -1,8 +1,8 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.database.sql; +package com.djrapitops.plan.system.database.databases.sql.statements; /** * @author Fuzzlemann diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/ActionsTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/ActionsTable.java similarity index 85% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/ActionsTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/ActionsTable.java index 6c5b688f9..9856e5ff6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/ActionsTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/ActionsTable.java @@ -1,19 +1,20 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.data.Actions; import com.djrapitops.plan.data.container.Action; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Select; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Select; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; @@ -37,16 +38,16 @@ import java.util.*; */ public class ActionsTable extends UserIDTable { - private final String columnServerID = "server_id"; - private final String columnDate = "date"; - private final String columnActionID = "action_id"; - private final String columnAdditionalInfo = "additional_info"; + private static final String columnServerID = "server_id"; + private static final String columnDate = "date"; + private static final String columnActionID = "action_id"; + private static final String columnAdditionalInfo = "additional_info"; private final ServerTable serverTable; private String insertStatement; - public ActionsTable(SQLDB db, boolean usingMySQL) { - super("plan_actions", db, usingMySQL); + public ActionsTable(SQLDB db) { + super("plan_actions", db); serverTable = db.getServerTable(); insertStatement = "INSERT INTO " + tableName + " (" + columnUserID + ", " @@ -61,7 +62,7 @@ public class ActionsTable extends UserIDTable { } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { ServerTable serverTable = db.getServerTable(); createTable(TableSqlParser.createTable(tableName) .column(columnUserID, Sql.INT).notNull() @@ -85,7 +86,7 @@ public class ActionsTable extends UserIDTable { @Override public void prepare(PreparedStatement statement) throws SQLException { statement.setString(1, uuid.toString()); - statement.setString(2, Plan.getServerUUID().toString()); + statement.setString(2, ServerInfo.getServerUUID().toString()); statement.setInt(3, action.getDoneAction().getId()); statement.setLong(4, action.getDate()); statement.setString(5, action.getAdditionalInfo()); @@ -138,8 +139,8 @@ public class ActionsTable extends UserIDTable { usersUUIDColumn + ", " + serverUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + - " JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; + " INNER JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + + " INNER JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; return query(new QueryAllStatement>>>(sql, 20000) { @Override @@ -203,7 +204,7 @@ public class ActionsTable extends UserIDTable { columnAdditionalInfo + ", " + usersUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + + " INNER JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + " WHERE " + serverTable.statementSelectServerID + "=" + columnServerID; return query(new QueryStatement>>(sql, 20000) { diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/CommandUseTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/CommandUseTable.java similarity index 83% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/CommandUseTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/CommandUseTable.java index 0161f7db2..0a1aeae54 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/CommandUseTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/CommandUseTable.java @@ -1,14 +1,14 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Select; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Select; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; +import com.djrapitops.plan.system.info.server.ServerInfo; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -23,16 +23,16 @@ import java.util.UUID; */ public class CommandUseTable extends Table { - private final String columnCommandId = "id"; - private final String columnCommand = "command"; - private final String columnTimesUsed = "times_used"; - private final String columnServerID = "server_id"; + private static final String columnCommandId = "id"; + private static final String columnCommand = "command"; + private static final String columnTimesUsed = "times_used"; + private static final String columnServerID = "server_id"; private final ServerTable serverTable; private String insertStatement; - public CommandUseTable(SQLDB db, boolean usingMySQL) { - super("plan_commandusages", db, usingMySQL); + public CommandUseTable(SQLDB db) { + super("plan_commandusages", db); serverTable = db.getServerTable(); insertStatement = "INSERT INTO " + tableName + " (" + columnCommand + ", " @@ -42,7 +42,7 @@ public class CommandUseTable extends Table { } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { ServerTable serverTable = db.getServerTable(); createTable(TableSqlParser.createTable(tableName) .primaryKeyIDColumn(usingMySQL, columnCommandId) @@ -62,7 +62,7 @@ public class CommandUseTable extends Table { * @throws SQLException DB Error */ public Map getCommandUse() throws SQLException { - return getCommandUse(Plan.getServerUUID()); + return getCommandUse(ServerInfo.getServerUUID()); } /** @@ -110,7 +110,7 @@ public class CommandUseTable extends Table { boolean updated = execute(new ExecStatement(sql) { @Override public void prepare(PreparedStatement statement) throws SQLException { - statement.setString(1, Plan.getServerUUID().toString()); + statement.setString(1, ServerInfo.getServerUUID().toString()); statement.setString(2, command); } }); @@ -125,7 +125,7 @@ public class CommandUseTable extends Table { public void prepare(PreparedStatement statement) throws SQLException { statement.setString(1, command); statement.setInt(2, 1); - statement.setString(3, Plan.getServerUUID().toString()); + statement.setString(3, ServerInfo.getServerUUID().toString()); } }); } @@ -176,7 +176,7 @@ public class CommandUseTable extends Table { columnTimesUsed + ", " + serverUUIDColumn + " FROM " + tableName + - " JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; + " INNER JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; return query(new QueryAllStatement>>(sql, 10000) { @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/IPsTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/GeoInfoTable.java similarity index 86% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/IPsTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/GeoInfoTable.java index e75af6596..274dd8c05 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/IPsTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/GeoInfoTable.java @@ -1,14 +1,14 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; import com.djrapitops.plan.data.container.GeoInfo; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Select; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Select; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; @@ -19,19 +19,15 @@ import java.util.*; /** * @author Rsl1122 */ -public class IPsTable extends UserIDTable { +public class GeoInfoTable extends UserIDTable { - private final String columnIP = "ip"; - private final String columnGeolocation = "geolocation"; - private final String columnLastUsed = "last_used"; + private static final String columnIP = "ip"; + private static final String columnGeolocation = "geolocation"; + private static final String columnLastUsed = "last_used"; private String insertStatement; - /** - * @param db The database - * @param usingMySQL if the server is using MySQL - */ - public IPsTable(SQLDB db, boolean usingMySQL) { - super("plan_ips", db, usingMySQL); + public GeoInfoTable(SQLDB db) { + super("plan_ips", db); insertStatement = "INSERT INTO " + tableName + " (" + columnUserID + ", " + columnIP + ", " @@ -43,7 +39,7 @@ public class IPsTable extends UserIDTable { } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(tableName) .column(columnUserID, Sql.INT).notNull() .column(columnIP, Sql.varchar(39)).notNull() @@ -115,7 +111,6 @@ public class IPsTable extends UserIDTable { " AND " + columnIP + "=?" + " AND " + columnGeolocation + "=?"; - execute(new ExecStatement(sql) { @Override public void prepare(PreparedStatement statement) throws SQLException { @@ -157,7 +152,7 @@ public class IPsTable extends UserIDTable { columnLastUsed + ", " + usersUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID; + " INNER JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID; return query(new QueryAllStatement>>(sql, 50000) { @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/KillsTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/KillsTable.java similarity index 87% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/KillsTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/KillsTable.java index 129f17b41..b7ab62c54 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/KillsTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/KillsTable.java @@ -1,14 +1,14 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; import com.djrapitops.plan.data.container.PlayerKill; import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; @@ -21,17 +21,17 @@ import java.util.*; */ public class KillsTable extends UserIDTable { - private final String columnKillerUserID = "killer_id"; - private final String columnVictimUserID = "victim_id"; - private final String columnWeapon = "weapon"; - private final String columnDate = "date"; - private final String columnSessionID = "session_id"; + private static final String columnKillerUserID = "killer_id"; + private static final String columnVictimUserID = "victim_id"; + private static final String columnWeapon = "weapon"; + private static final String columnDate = "date"; + private static final String columnSessionID = "session_id"; private final SessionsTable sessionsTable; private String insertStatement; - public KillsTable(SQLDB db, boolean usingMySQL) { - super("plan_kills", db, usingMySQL); + public KillsTable(SQLDB db) { + super("plan_kills", db); sessionsTable = db.getSessionsTable(); insertStatement = "INSERT INTO " + tableName + " (" + columnKillerUserID + ", " @@ -46,7 +46,7 @@ public class KillsTable extends UserIDTable { } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(tableName) .column(columnKillerUserID, Sql.INT).notNull() .column(columnVictimUserID, Sql.INT).notNull() @@ -111,7 +111,7 @@ public class KillsTable extends UserIDTable { columnWeapon + ", " + usersUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnVictimUserID + + " INNER JOIN " + usersTable + " on " + usersIDColumn + "=" + columnVictimUserID + " WHERE " + columnKillerUserID + "=" + usersTable.statementSelectID; query(new QueryStatement(sql, 50000) { @@ -150,8 +150,8 @@ public class KillsTable extends UserIDTable { usersVictimUUIDColumn + ", " + usersKillerUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersVictimIDColumn + "=" + columnVictimUserID + - " JOIN " + usersTable + " a on " + usersKillerIDColumn + "=" + columnKillerUserID; + " INNER JOIN " + usersTable + " on " + usersVictimIDColumn + "=" + columnVictimUserID + + " INNER JOIN " + usersTable + " a on " + usersKillerIDColumn + "=" + columnKillerUserID; return query(new QueryAllStatement>>(sql, 50000) { @Override @@ -230,7 +230,7 @@ public class KillsTable extends UserIDTable { columnWeapon + ", " + usersUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnVictimUserID; + " INNER JOIN " + usersTable + " on " + usersIDColumn + "=" + columnVictimUserID; return query(new QueryAllStatement>>(sql, 50000) { @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/NicknamesTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/NicknamesTable.java similarity index 85% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/NicknamesTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/NicknamesTable.java index 04ad76e4f..16a0beb8e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/NicknamesTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/NicknamesTable.java @@ -1,13 +1,13 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; @@ -20,18 +20,14 @@ import java.util.*; */ public class NicknamesTable extends UserIDTable { - private final String columnNick = "nickname"; - private final String columnServerID = "server_id"; + private static final String columnNick = "nickname"; + private static final String columnServerID = "server_id"; private final ServerTable serverTable; private String insertStatement; - /** - * @param db The database - * @param usingMySQL if the server is using MySQL - */ - public NicknamesTable(SQLDB db, boolean usingMySQL) { - super("plan_nicknames", db, usingMySQL); + public NicknamesTable(SQLDB db) { + super("plan_nicknames", db); serverTable = db.getServerTable(); insertStatement = "INSERT INTO " + tableName + " (" + columnUserID + ", " + @@ -44,7 +40,7 @@ public class NicknamesTable extends UserIDTable { } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(tableName) .column(columnUserID, Sql.INT).notNull() .column(columnNick, Sql.varchar(75)).notNull() @@ -71,7 +67,7 @@ public class NicknamesTable extends UserIDTable { columnNick + ", " + serverUUIDColumn + " FROM " + tableName + - " JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID + + " INNER JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID + " WHERE (" + columnUserID + "=" + usersTable.statementSelectID + ")"; return query(new QueryStatement>>(sql, 5000) { @@ -108,7 +104,7 @@ public class NicknamesTable extends UserIDTable { * @throws SQLException when an error at retrieval happens */ public List getNicknames(UUID uuid) throws SQLException { - return getNicknames(uuid, Plan.getServerUUID()); + return getNicknames(uuid, ServerInfo.getServerUUID()); } /** @@ -160,7 +156,7 @@ public class NicknamesTable extends UserIDTable { @Override public void prepare(PreparedStatement statement) throws SQLException { statement.setString(1, uuid.toString()); - statement.setString(2, Plan.getServerUUID().toString()); + statement.setString(2, ServerInfo.getServerUUID().toString()); statement.setString(3, displayName); } }); @@ -176,8 +172,8 @@ public class NicknamesTable extends UserIDTable { usersUUIDColumn + ", " + serverUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + - " JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; + " INNER JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + + " INNER JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; return query(new QueryAllStatement>>>(sql, 5000) { @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/SecurityTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/SecurityTable.java similarity index 80% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/SecurityTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/SecurityTable.java index 2c34dc0ce..3ef5bf6a6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/SecurityTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/SecurityTable.java @@ -3,18 +3,18 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; import com.djrapitops.plan.data.WebUser; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Insert; -import com.djrapitops.plan.database.sql.Select; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Insert; +import com.djrapitops.plan.system.database.databases.sql.statements.Select; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; @@ -28,13 +28,13 @@ import java.util.List; */ public class SecurityTable extends Table { - private final String columnUser = "username"; - private final String columnSaltedHash = "salted_pass_hash"; - private final String columnPermLevel = "permission_level"; + private static final String columnUser = "username"; + private static final String columnSaltedHash = "salted_pass_hash"; + private static final String columnPermLevel = "permission_level"; private String insertStatement; - public SecurityTable(SQLDB db, boolean usingMySQL) { - super("plan_security", db, usingMySQL); + public SecurityTable(SQLDB db) { + super("plan_security", db); insertStatement = Insert.values(tableName, columnUser, columnSaltedHash, @@ -42,7 +42,7 @@ public class SecurityTable extends Table { } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(tableName) .column(columnUser, Sql.varchar(100)).notNull().unique() .column(columnSaltedHash, Sql.varchar(100)).notNull().unique() diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/ServerTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/ServerTable.java similarity index 81% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/ServerTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/ServerTable.java index ef905b567..6968801bc 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/ServerTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/ServerTable.java @@ -1,16 +1,16 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.*; -import com.djrapitops.plan.systems.info.server.ServerInfo; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.*; +import com.djrapitops.plan.system.info.server.Server; import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; @@ -37,18 +37,18 @@ public class ServerTable extends Table { public final String statementSelectServerID; public final String statementSelectServerNameID; - private final String columnServerID = "id"; - private final String columnServerUUID = "uuid"; - private final String columnServerName = "name"; - private final String columnWebserverAddress = "web_address"; - private final String columnInstalled = "is_installed"; - private final String columnMaxPlayers = "max_players"; + private static final String columnServerID = "id"; + private static final String columnServerUUID = "uuid"; + private static final String columnServerName = "name"; + private static final String columnWebserverAddress = "web_address"; + private static final String columnInstalled = "is_installed"; + private static final String columnMaxPlayers = "max_players"; private String insertStatement; - public ServerTable(SQLDB db, boolean usingMySQL) { - super("plan_servers", db, usingMySQL); - statementSelectServerID = "(" + Select.from(tableName, tableName + "." + columnServerID).where(columnServerUUID + "=?").toString() + ")"; - statementSelectServerNameID = "(" + Select.from(tableName, tableName + "." + columnServerName).where(columnServerID + "=?").toString() + ")"; + public ServerTable(SQLDB db) { + super("plan_servers", db); + statementSelectServerID = "(" + Select.from(tableName, tableName + "." + columnServerID).where(tableName + "." + columnServerUUID + "=?").toString() + " LIMIT 1)"; + statementSelectServerNameID = "(" + Select.from(tableName, tableName + "." + columnServerName).where(tableName + "." + columnServerID + "=?").toString() + " LIMIT 1)"; insertStatement = Insert.values(tableName, columnServerUUID, columnServerName, @@ -58,7 +58,7 @@ public class ServerTable extends Table { } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(tableName) .primaryKeyIDColumn(usingMySQL, columnServerID) .column(columnServerUUID, Sql.varchar(36)).notNull().unique() @@ -77,7 +77,7 @@ public class ServerTable extends Table { } } - public void saveCurrentServerInfo(ServerInfo info) throws SQLException { + public void saveCurrentServerInfo(Server info) throws SQLException { if (getServerID(info.getUuid()).isPresent()) { updateServerInfo(info); } else { @@ -85,7 +85,7 @@ public class ServerTable extends Table { } } - private void updateServerInfo(ServerInfo info) throws SQLException { + private void updateServerInfo(Server info) throws SQLException { String sql = Update.values(tableName, columnServerUUID, columnServerName, @@ -112,10 +112,10 @@ public class ServerTable extends Table { * Inserts new row for a server into the table. * * @param info Info to instert (All variables should be present. - * @throws IllegalStateException if one of the ServerInfo variables is null + * @throws IllegalStateException if one of the Server variables is null * @throws SQLException DB Error */ - private void saveNewServerInfo(ServerInfo info) throws SQLException { + private void saveNewServerInfo(Server info) throws SQLException { UUID uuid = info.getUuid(); String name = info.getName(); String webAddress = info.getWebAddress(); @@ -229,7 +229,7 @@ public class ServerTable extends Table { }); } - public Map getServerUuids() throws SQLException { + public Map getServerUUIDsByID() throws SQLException { String sql = Select.from(tableName, columnServerID, columnServerUUID) .toString(); @@ -253,21 +253,21 @@ public class ServerTable extends Table { * @return information about Bungee server. * @throws SQLException DB Error */ - public Optional getBungeeInfo() throws SQLException { + public Optional getBungeeInfo() throws SQLException { String sql = Select.from(tableName, "*") .where(columnServerName + "=?") .toString(); - return query(new QueryStatement>(sql) { + return query(new QueryStatement>(sql) { @Override public void prepare(PreparedStatement statement) throws SQLException { statement.setString(1, "BungeeCord"); } @Override - public Optional processResults(ResultSet set) throws SQLException { + public Optional processResults(ResultSet set) throws SQLException { if (set.next()) { - return Optional.of(new ServerInfo( + return Optional.of(new Server( set.getInt(columnServerID), UUID.fromString(set.getString(columnServerUUID)), set.getString(columnServerName), @@ -280,24 +280,25 @@ public class ServerTable extends Table { }); } - public List getBukkitServers() throws SQLException { + public Map getBukkitServers() throws SQLException { String sql = Select.from(tableName, "*") .where(columnServerName + "!=?") .toString(); - return query(new QueryStatement>(sql, 100) { + return query(new QueryStatement>(sql, 100) { @Override public void prepare(PreparedStatement statement) throws SQLException { statement.setString(1, "BungeeCord"); } @Override - public List processResults(ResultSet set) throws SQLException { - List servers = new ArrayList<>(); + public Map processResults(ResultSet set) throws SQLException { + Map servers = new HashMap<>(); while (set.next()) { - servers.add(new ServerInfo( + UUID serverUUID = UUID.fromString(set.getString(columnServerUUID)); + servers.put(serverUUID, new Server( set.getInt(columnServerID), - UUID.fromString(set.getString(columnServerUUID)), + serverUUID, set.getString(columnServerName), set.getString(columnWebserverAddress), set.getInt(columnMaxPlayers))); @@ -315,15 +316,15 @@ public class ServerTable extends Table { return columnServerUUID; } - public void insertAllServers(List allServerInfo) throws SQLException { - if (Verify.isEmpty(allServerInfo)) { + public void insertAllServers(List allServer) throws SQLException { + if (Verify.isEmpty(allServer)) { return; } executeBatch(new ExecStatement(insertStatement) { @Override public void prepare(PreparedStatement statement) throws SQLException { - for (ServerInfo info : allServerInfo) { + for (Server info : allServer) { UUID uuid = info.getUuid(); String name = info.getName(); String webAddress = info.getWebAddress(); @@ -382,21 +383,21 @@ public class ServerTable extends Table { }); } - public Optional getServerInfo(UUID serverUUID) throws SQLException { + public Optional getServerInfo(UUID serverUUID) throws SQLException { String sql = Select.from(tableName, "*") .where(columnServerUUID + "=?") .toString(); - return query(new QueryStatement>(sql) { + return query(new QueryStatement>(sql) { @Override public void prepare(PreparedStatement statement) throws SQLException { statement.setString(1, serverUUID.toString()); } @Override - public Optional processResults(ResultSet set) throws SQLException { + public Optional processResults(ResultSet set) throws SQLException { if (set.next()) { - return Optional.of(new ServerInfo( + return Optional.of(new Server( set.getInt(columnServerID), UUID.fromString(set.getString(columnServerUUID)), set.getString(columnServerName), @@ -411,12 +412,7 @@ public class ServerTable extends Table { public int getMaxPlayers() throws SQLException { String sql = "SELECT SUM(" + columnMaxPlayers + ") AS max FROM " + tableName; - return query(new QueryStatement(sql) { - @Override - public void prepare(PreparedStatement statement) { - - } - + return query(new QueryAllStatement(sql) { @Override public Integer processResults(ResultSet set) throws SQLException { if (set.next()) { diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/SessionsTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/SessionsTable.java similarity index 84% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/SessionsTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/SessionsTable.java index a9a98e8cb..505b7fb1b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/SessionsTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/SessionsTable.java @@ -1,15 +1,17 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Select; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Select; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; @@ -24,18 +26,18 @@ import java.util.stream.Collectors; */ public class SessionsTable extends UserIDTable { - private final String columnID = "id"; - private final String columnSessionStart = "session_start"; - private final String columnSessionEnd = "session_end"; - private final String columnServerID = "server_id"; - private final String columnMobKills = "mob_kills"; - private final String columnDeaths = "deaths"; + private static final String columnID = "id"; + private static final String columnSessionStart = "session_start"; + private static final String columnSessionEnd = "session_end"; + private static final String columnServerID = "server_id"; + private static final String columnMobKills = "mob_kills"; + private static final String columnDeaths = "deaths"; private final ServerTable serverTable; private String insertStatement; - public SessionsTable(SQLDB db, boolean usingMySQL) { - super("plan_sessions", db, usingMySQL); + public SessionsTable(SQLDB db) { + super("plan_sessions", db); serverTable = db.getServerTable(); insertStatement = "INSERT INTO " + tableName + " (" + columnUserID + ", " @@ -51,7 +53,7 @@ public class SessionsTable extends UserIDTable { } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(this.tableName) .primaryKeyIDColumn(usingMySQL, columnID) .column(columnUserID, Sql.INT).notNull() @@ -105,7 +107,7 @@ public class SessionsTable extends UserIDTable { statement.setLong(3, session.getSessionEnd()); statement.setInt(4, session.getDeaths()); statement.setInt(5, session.getMobKills()); - statement.setString(6, Plan.getServerUUID().toString()); + statement.setString(6, ServerInfo.getServerUUID().toString()); } }); } @@ -152,7 +154,7 @@ public class SessionsTable extends UserIDTable { * @throws SQLException DB Error */ private Map> getSessionInformation(UUID uuid) throws SQLException { - Map serverUUIDs = serverTable.getServerUuids(); + Map serverUUIDs = serverTable.getServerUUIDsByID(); String sql = Select.from(tableName, "*") .where(columnUserID + "=" + usersTable.statementSelectID) .toString(); @@ -204,7 +206,7 @@ public class SessionsTable extends UserIDTable { * @throws SQLException DB Error */ public long getPlaytime(UUID uuid) throws SQLException { - return getPlaytime(uuid, Plan.getServerUUID()); + return getPlaytime(uuid, ServerInfo.getServerUUID()); } /** @@ -216,7 +218,7 @@ public class SessionsTable extends UserIDTable { * @throws SQLException DB Error */ public long getPlaytime(UUID uuid, long afterDate) throws SQLException { - return getPlaytime(uuid, Plan.getServerUUID(), afterDate); + return getPlaytime(uuid, ServerInfo.getServerUUID(), afterDate); } /** @@ -321,7 +323,7 @@ public class SessionsTable extends UserIDTable { * @throws SQLException DB Error */ public long getPlaytimeOfServer() throws SQLException { - return getPlaytimeOfServer(Plan.getServerUUID()); + return getPlaytimeOfServer(ServerInfo.getServerUUID()); } /** @@ -343,7 +345,7 @@ public class SessionsTable extends UserIDTable { * @throws SQLException DB Error */ public long getPlaytimeOfServer(long afterDate) throws SQLException { - return getPlaytimeOfServer(Plan.getServerUUID(), afterDate); + return getPlaytimeOfServer(ServerInfo.getServerUUID(), afterDate); } /** @@ -398,7 +400,7 @@ public class SessionsTable extends UserIDTable { * @throws SQLException DB Error */ public int getSessionCount(UUID uuid, long afterDate) throws SQLException { - return getSessionCount(uuid, Plan.getServerUUID(), afterDate); + return getSessionCount(uuid, ServerInfo.getServerUUID(), afterDate); } /** @@ -453,7 +455,7 @@ public class SessionsTable extends UserIDTable { } public Map> getSessionInfoOfServer() throws SQLException { - return getSessionInfoOfServer(Plan.getServerUUID()); + return getSessionInfoOfServer(ServerInfo.getServerUUID()); } public Map> getSessionInfoOfServer(UUID serverUUID) throws SQLException { @@ -467,7 +469,7 @@ public class SessionsTable extends UserIDTable { columnMobKills + ", " + usersUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + + " INNER JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + " WHERE " + columnServerID + "=" + serverTable.statementSelectServerID; return query(new QueryStatement>>(sql, 5000) { @@ -526,7 +528,7 @@ public class SessionsTable extends UserIDTable { " MAX(" + columnSessionEnd + ") as last_seen, " + usersUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + + " INNER JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + " GROUP BY uuid"; return query(new QueryAllStatement>(sql, 20000) { @@ -544,29 +546,26 @@ public class SessionsTable extends UserIDTable { } public Map>> getAllSessions(boolean getKillsAndWorldTimes) throws SQLException { - String usersIDColumn = usersTable + "." + usersTable.getColumnID(); - String usersUUIDColumn = usersTable + "." + usersTable.getColumnUUID() + " as uuid"; - String serverIDColumn = serverTable + "." + serverTable.getColumnID(); - String serverUUIDColumn = serverTable + "." + serverTable.getColumnUUID() + " as s_uuid"; + Map uuidsByID = usersTable.getUUIDsByID(); + Map serverUUIDsByID = serverTable.getServerUUIDsByID(); + String sql = "SELECT " + - tableName + "." + columnID + ", " + + columnID + ", " + + columnUserID + ", " + + columnServerID + ", " + columnSessionStart + ", " + columnSessionEnd + ", " + columnDeaths + ", " + - columnMobKills + ", " + - usersUUIDColumn + ", " + - serverUUIDColumn + - " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + - " JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; + columnMobKills + + " FROM " + tableName; return query(new QueryAllStatement>>>(sql, 20000) { @Override public Map>> processResults(ResultSet set) throws SQLException { Map>> map = new HashMap<>(); while (set.next()) { - UUID serverUUID = UUID.fromString(set.getString("s_uuid")); - UUID uuid = UUID.fromString(set.getString("uuid")); + UUID serverUUID = serverUUIDsByID.get(set.getInt(columnServerID)); + UUID uuid = uuidsByID.get(set.getInt(columnUserID)); Map> sessionsByUser = map.getOrDefault(serverUUID, new HashMap<>()); List sessions = sessionsByUser.getOrDefault(uuid, new ArrayList<>()); @@ -678,4 +677,53 @@ public class SessionsTable extends UserIDTable { String getcolumnServerID() { return columnServerID; } + + public Map>> getSessionInLastMonth() throws SQLException { + Map uuidsByID = usersTable.getUUIDsByID(); + Map serverUUIDsByID = serverTable.getServerUUIDsByID(); + + String sql = "SELECT " + + columnID + ", " + + columnUserID + ", " + + columnServerID + ", " + + columnSessionStart + ", " + + columnSessionEnd + ", " + + columnDeaths + ", " + + columnMobKills + + " FROM " + tableName + + " WHERE " + columnSessionStart + ">?"; + + return query(new QueryStatement>>>(sql, 20000) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setLong(1, MiscUtils.getTime() - TimeAmount.MONTH.ms()); + } + + @Override + public Map>> processResults(ResultSet set) throws SQLException { + Map>> map = new HashMap<>(); + while (set.next()) { + UUID serverUUID = serverUUIDsByID.get(set.getInt(columnServerID)); + UUID uuid = uuidsByID.get(set.getInt(columnUserID)); + + Map> sessionsByUser = map.getOrDefault(serverUUID, new HashMap<>()); + List sessions = sessionsByUser.getOrDefault(uuid, new ArrayList<>()); + + long start = set.getLong(columnSessionStart); + long end = set.getLong(columnSessionEnd); + + int deaths = set.getInt(columnDeaths); + int mobKills = set.getInt(columnMobKills); + int id = set.getInt(columnID); + + Session session = new Session(id, start, end, mobKills, deaths); + sessions.add(session); + + sessionsByUser.put(uuid, sessions); + map.put(serverUUID, sessionsByUser); + } + return map; + } + }); + } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/TPSTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/TPSTable.java similarity index 69% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/TPSTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/TPSTable.java index e144d4ae9..240e56e55 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/TPSTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/TPSTable.java @@ -1,15 +1,17 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; import com.djrapitops.plan.data.container.TPS; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Select; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; -import com.djrapitops.plan.systems.info.server.ServerInfo; +import com.djrapitops.plan.data.container.builders.TPSBuilder; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Select; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.utilities.Verify; @@ -27,20 +29,20 @@ import java.util.*; */ public class TPSTable extends Table { - private final String columnServerID = "server_id"; - private final String columnDate = "date"; - private final String columnTPS = "tps"; - private final String columnPlayers = "players_online"; - private final String columnCPUUsage = "cpu_usage"; - private final String columnRAMUsage = "ram_usage"; - private final String columnEntities = "entities"; - private final String columnChunksLoaded = "chunks_loaded"; + private static final String columnServerID = "server_id"; + private static final String columnDate = "date"; + private static final String columnTPS = "tps"; + private static final String columnPlayers = "players_online"; + private static final String columnCPUUsage = "cpu_usage"; + private static final String columnRAMUsage = "ram_usage"; + private static final String columnEntities = "entities"; + private static final String columnChunksLoaded = "chunks_loaded"; private final ServerTable serverTable; private String insertStatement; - public TPSTable(SQLDB db, boolean usingMySQL) { - super("plan_tps", db, usingMySQL); + public TPSTable(SQLDB db) { + super("plan_tps", db); serverTable = db.getServerTable(); insertStatement = "INSERT INTO " + tableName + " (" + columnServerID + ", " @@ -57,7 +59,7 @@ public class TPSTable extends Table { } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(tableName) .column(columnServerID, Sql.INT).notNull() .column(columnDate, Sql.LONG).notNull() @@ -76,7 +78,7 @@ public class TPSTable extends Table { * @return @throws SQLException */ public List getTPSData() throws SQLException { - return getTPSData(MiscUtils.getIPlan().getServerUuid()); + return getTPSData(ServerInfo.getServerUUID()); } public List getTPSData(UUID serverUUID) throws SQLException { @@ -94,14 +96,18 @@ public class TPSTable extends Table { public List processResults(ResultSet set) throws SQLException { List data = new ArrayList<>(); while (set.next()) { - long date = set.getLong(columnDate); - double tps = set.getDouble(columnTPS); - int players = set.getInt(columnPlayers); - double cpuUsage = set.getDouble(columnCPUUsage); - long ramUsage = set.getLong(columnRAMUsage); - int entities = set.getInt(columnEntities); - int chunksLoaded = set.getInt(columnChunksLoaded); - data.add(new TPS(date, tps, players, cpuUsage, ramUsage, entities, chunksLoaded)); + + TPS tps = TPSBuilder.get() + .date(set.getLong(columnDate)) + .tps(set.getDouble(columnTPS)) + .playersOnline(set.getInt(columnPlayers)) + .usedCPU(set.getDouble(columnCPUUsage)) + .usedMemory(set.getLong(columnRAMUsage)) + .entities(set.getInt(columnEntities)) + .chunksLoaded(set.getInt(columnChunksLoaded)) + .toTPS(); + + data.add(tps); } return data; } @@ -112,7 +118,7 @@ public class TPSTable extends Table { execute(new ExecStatement(insertStatement) { @Override public void prepare(PreparedStatement statement) throws SQLException { - statement.setString(1, MiscUtils.getIPlan().getServerUuid().toString()); + statement.setString(1, ServerInfo.getServerUUID().toString()); statement.setLong(2, tps.getDate()); statement.setDouble(3, tps.getTicksPerSecond()); statement.setInt(4, tps.getPlayers()); @@ -162,7 +168,7 @@ public class TPSTable extends Table { } public Optional getPeakPlayerCount(long afterDate) throws SQLException { - return getPeakPlayerCount(MiscUtils.getIPlan().getServerUuid(), afterDate); + return getPeakPlayerCount(ServerInfo.getServerUUID(), afterDate); } public Optional getPeakPlayerCount(UUID serverUUID, long afterDate) throws SQLException { @@ -182,14 +188,18 @@ public class TPSTable extends Table { @Override public Optional processResults(ResultSet set) throws SQLException { if (set.next()) { - long date = set.getLong(columnDate); - double tps = set.getDouble(columnTPS); - int players = set.getInt(columnPlayers); - double cpuUsage = set.getDouble(columnCPUUsage); - long ramUsage = set.getLong(columnRAMUsage); - int entities = set.getInt(columnEntities); - int chunksLoaded = set.getInt(columnChunksLoaded); - return Optional.of(new TPS(date, tps, players, cpuUsage, ramUsage, entities, chunksLoaded)); + + TPS tps = TPSBuilder.get() + .date(set.getLong(columnDate)) + .tps(set.getDouble(columnTPS)) + .playersOnline(set.getInt(columnPlayers)) + .usedCPU(set.getDouble(columnCPUUsage)) + .usedMemory(set.getLong(columnRAMUsage)) + .entities(set.getInt(columnEntities)) + .chunksLoaded(set.getInt(columnChunksLoaded)) + .toTPS(); + + return Optional.of(tps); } return Optional.empty(); } @@ -209,7 +219,7 @@ public class TPSTable extends Table { columnChunksLoaded + ", " + serverUUIDColumn + " FROM " + tableName + - " JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; + " INNER JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; return query(new QueryAllStatement>>(sql, 50000) { @Override @@ -220,15 +230,17 @@ public class TPSTable extends Table { List tpsList = serverMap.getOrDefault(serverUUID, new ArrayList<>()); - long date = set.getLong(columnDate); - double tps = set.getDouble(columnTPS); - int players = set.getInt(columnPlayers); - double cpuUsage = set.getDouble(columnCPUUsage); - long ramUsage = set.getLong(columnRAMUsage); - int entities = set.getInt(columnEntities); - int chunksLoaded = set.getInt(columnChunksLoaded); + TPS tps = TPSBuilder.get() + .date(set.getLong(columnDate)) + .tps(set.getDouble(columnTPS)) + .playersOnline(set.getInt(columnPlayers)) + .usedCPU(set.getDouble(columnCPUUsage)) + .usedMemory(set.getLong(columnRAMUsage)) + .entities(set.getInt(columnEntities)) + .chunksLoaded(set.getInt(columnChunksLoaded)) + .toTPS(); - tpsList.add(new TPS(date, tps, players, cpuUsage, ramUsage, entities, chunksLoaded)); + tpsList.add(tps); serverMap.put(serverUUID, tpsList); } return serverMap; @@ -266,7 +278,7 @@ public class TPSTable extends Table { } public List getNetworkOnlineData() throws SQLException { - Optional bungeeInfo = serverTable.getBungeeInfo(); + Optional bungeeInfo = serverTable.getBungeeInfo(); if (!bungeeInfo.isPresent()) { return new ArrayList<>(); } @@ -288,10 +300,14 @@ public class TPSTable extends Table { public List processResults(ResultSet set) throws SQLException { List tpsList = new ArrayList<>(); while (set.next()) { - long date = set.getLong(columnDate); - int players = set.getInt(columnPlayers); - tpsList.add(new TPS(date, 0, players, 0, 0, 0, 0)); + TPS tps = TPSBuilder.get() + .date(set.getLong(columnDate)) + .skipTPS() + .playersOnline(set.getInt(columnPlayers)) + .toTPS(); + + tpsList.add(tps); } return tpsList; } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/Table.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/Table.java similarity index 72% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/Table.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/Table.java index 0abde340b..c9b96cc16 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/Table.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/Table.java @@ -1,57 +1,45 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryStatement; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.utilities.Verify; import com.google.common.base.Objects; import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.SQLException; -import java.sql.Statement; /** * @author Rsl1122 */ public abstract class Table { - /** - * - */ protected final String tableName; - - /** - * - */ protected final SQLDB db; - - /** - * - */ protected final boolean usingMySQL; /** * Constructor. * - * @param name Name of the table in the db. - * @param db Database to use. - * @param usingMySQL Is the database using MySQL? + * @param name Name of the table in the db. + * @param db Database to use. */ - public Table(String name, SQLDB db, boolean usingMySQL) { + public Table(String name, SQLDB db) { this.tableName = name; this.db = db; - this.usingMySQL = usingMySQL; + this.usingMySQL = db != null && db.isUsingMySQL(); } - public abstract void createTable() throws DBCreateTableException; + public abstract void createTable() throws DBInitException; - protected void createTable(String sql) throws DBCreateTableException { + protected void createTable(String sql) throws DBInitException { try { execute(sql); } catch (SQLException e) { - throw new DBCreateTableException(tableName, "Failed to create table", e); + throw new DBInitException("Failed to create table: " + tableName, e); } } @@ -83,19 +71,12 @@ public abstract class Table { * @throws SQLException DB error */ protected boolean execute(String statementString) throws SQLException { - Statement statement = null; - Connection connection = null; - try { - connection = getConnection(); - statement = connection.createStatement(); - boolean b = statement.execute(statementString); -// Log.debug("Execute: " + statementString); - commit(connection); - return b; - } finally { - close(statement); - db.returnToPool(connection); - } + return execute(new ExecStatement(statementString) { + @Override + public void prepare(PreparedStatement statement) { + /* No preparations necessary */ + } + }); } /** @@ -184,25 +165,27 @@ public abstract class Table { } protected boolean execute(ExecStatement statement) throws SQLException { - boolean updatedSomething; Connection connection = null; try { connection = getConnection(); - updatedSomething = statement.execute(connection.prepareStatement(statement.getSql())); - commit(connection); + try (PreparedStatement preparedStatement = connection.prepareStatement(statement.getSql())) { + return statement.execute(preparedStatement); + } } finally { + commit(connection); db.returnToPool(connection); } - return updatedSomething; } protected void executeBatch(ExecStatement statement) throws SQLException { Connection connection = null; try { connection = getConnection(); - statement.executeBatch(connection.prepareStatement(statement.getSql())); - commit(connection); + try (PreparedStatement preparedStatement = connection.prepareStatement(statement.getSql())) { + statement.executeBatch(preparedStatement); + } } finally { + commit(connection); db.returnToPool(connection); } } @@ -211,7 +194,9 @@ public abstract class Table { Connection connection = null; try { connection = getConnection(); - return statement.executeQuery(connection.prepareStatement(statement.getSql())); + try (PreparedStatement preparedStatement = connection.prepareStatement(statement.getSql())) { + return statement.executeQuery(preparedStatement); + } } finally { db.returnToPool(connection); } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/TransferTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/TransferTable.java new file mode 100644 index 000000000..c959d680b --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/TransferTable.java @@ -0,0 +1,296 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.database.databases.sql.tables; + +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; +import com.djrapitops.plan.system.info.request.CacheAnalysisPageRequest; +import com.djrapitops.plan.system.info.request.CacheInspectPageRequest; +import com.djrapitops.plan.system.info.request.CacheInspectPluginsTabRequest; +import com.djrapitops.plan.system.info.request.CacheNetworkPageContentRequest; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plugin.api.TimeAmount; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +/** + * Table that represents plan_transfer in SQL database. + * + * @author Rsl1122 + */ +public class TransferTable extends Table { + + private static final String columnSenderID = "sender_server_id"; + private static final String columnExpiry = "expiry_date"; + private static final String columnInfoType = "type"; + private static final String columnContent = "content_64"; + private static final String columnExtraVariables = "extra_variables"; + + private final ServerTable serverTable; + + private final String insertStatement; + private final String selectStatement; + + public TransferTable(SQLDB db) { + super("plan_transfer", db); + + serverTable = db.getServerTable(); + insertStatement = "INSERT INTO " + tableName + " (" + + columnSenderID + ", " + + columnExpiry + ", " + + columnInfoType + ", " + + columnExtraVariables + ", " + + columnContent + + ") VALUES (" + + serverTable.statementSelectServerID + ", " + + "?, ?, ?, ?)"; + + selectStatement = "SELECT * FROM " + tableName + + " WHERE " + columnInfoType + "= ?" + + " AND " + columnExpiry + "> ?" + + " ORDER BY " + columnExpiry + " DESC"; + } + + @Override + public void createTable() throws DBInitException { + createTable(TableSqlParser.createTable(tableName) + .column(columnSenderID, Sql.INT).notNull() + .column(columnExpiry, Sql.LONG).notNull().defaultValue("0") + .column(columnInfoType, Sql.varchar(100)).notNull() + .column(columnExtraVariables, Sql.varchar(255)).defaultValue("''") + .column(columnContent, usingMySQL ? "MEDIUMTEXT" : Sql.varchar(1)) // SQLite does not enforce varchar limits. + .foreignKey(columnSenderID, serverTable.toString(), serverTable.getColumnID()) + .toString() + ); + } + + public void clean() throws SQLException { + String sql = "DELETE FROM " + tableName + + " WHERE " + columnExpiry + " < ?" + + " AND " + columnInfoType + " != ?"; + + execute(new ExecStatement(sql) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setLong(1, MiscUtils.getTime()); + statement.setString(2, "onlineStatus"); + } + }); + sql = "DELETE FROM " + tableName + + " WHERE " + columnSenderID + " = " + serverTable.statementSelectServerID + + " AND " + columnInfoType + " = ?"; + + execute(new ExecStatement(sql) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, ServerInfo.getServerUUID().toString()); + statement.setString(2, "onlineStatus"); + } + }); + } + + public void storePlayerHtml(UUID player, String encodedHtml) throws SQLException { + execute(new ExecStatement(insertStatement) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, ServerInfo.getServerUUID().toString()); + statement.setLong(2, MiscUtils.getTime() + TimeAmount.MINUTE.ms()); + statement.setString(3, CacheInspectPageRequest.class.getSimpleName().toLowerCase()); + statement.setString(4, player.toString()); + statement.setString(5, encodedHtml); + } + }); + } + + public void storeServerHtml(UUID serverUUID, String encodedHtml) throws SQLException { + execute(new ExecStatement(insertStatement) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, ServerInfo.getServerUUID().toString()); + statement.setLong(2, MiscUtils.getTime() + TimeAmount.MINUTE.ms()); + statement.setString(3, CacheAnalysisPageRequest.class.getSimpleName().toLowerCase()); + statement.setString(4, serverUUID.toString()); + statement.setString(5, encodedHtml); + } + }); + } + + public void storeNetworkPageContent(UUID serverUUID, String encodedHtml) throws SQLException { + execute(new ExecStatement(insertStatement) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, ServerInfo.getServerUUID().toString()); + statement.setLong(2, MiscUtils.getTime() + TimeAmount.MINUTE.ms()); + statement.setString(3, CacheNetworkPageContentRequest.class.getSimpleName().toLowerCase()); + statement.setString(4, serverUUID.toString()); + statement.setString(5, encodedHtml); + } + }); + } + + private Map getHtmlPerUUIDForCacheRequest(Class c) throws SQLException { + return query(new QueryStatement>(selectStatement, 250) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, c.getSimpleName().toLowerCase()); + statement.setLong(2, MiscUtils.getTime()); + } + + @Override + public Map processResults(ResultSet set) throws SQLException { + Map htmlPerUUID = new HashMap<>(); + while (set.next()) { + String uuidString = set.getString(columnExtraVariables); + UUID uuid = UUID.fromString(uuidString); + + if (!htmlPerUUID.containsKey(uuid)) { + htmlPerUUID.put(uuid, set.getString(columnContent)); + } + } + return htmlPerUUID; + } + }); + } + + public Map getPlayerHtml() throws SQLException { + return getHtmlPerUUIDForCacheRequest(CacheInspectPageRequest.class); + } + + public Map getNetworkPageContent() throws SQLException { + return getHtmlPerUUIDForCacheRequest(CacheNetworkPageContentRequest.class); + } + + public Map getServerHtml() throws SQLException { + return getHtmlPerUUIDForCacheRequest(CacheAnalysisPageRequest.class); + } + + public void storePlayerPluginsTab(UUID player, String encodedHtml) throws SQLException { + execute(new ExecStatement(insertStatement) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, ServerInfo.getServerUUID().toString()); + statement.setLong(2, MiscUtils.getTime() + TimeAmount.MINUTE.ms()); + statement.setString(3, CacheInspectPluginsTabRequest.class.getSimpleName().toLowerCase()); + statement.setString(4, player.toString()); + statement.setString(5, encodedHtml); + } + }); + } + + public Map getPlayerPluginsTabs(UUID playerUUID) throws SQLException { + String serverIDColumn = serverTable + "." + serverTable.getColumnID(); + String serverUUIDColumn = serverTable + "." + serverTable.getColumnUUID() + " as s_uuid"; + String sql = "SELECT " + + columnContent + ", " + + serverUUIDColumn + + " FROM " + tableName + + " INNER JOIN " + serverTable + " on " + serverIDColumn + "=" + columnSenderID + + " WHERE " + columnInfoType + "= ?" + + " AND " + columnExpiry + "> ?" + + " AND " + columnExtraVariables + "=?"; + + return query(new QueryStatement>(sql, 250) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, CacheInspectPluginsTabRequest.class.getSimpleName().toLowerCase()); + statement.setLong(2, MiscUtils.getTime()); + statement.setString(3, playerUUID.toString()); + } + + @Override + public Map processResults(ResultSet set) throws SQLException { + Map htmlPerUUID = new HashMap<>(); + while (set.next()) { + UUID serverUUID = UUID.fromString(set.getString("s_uuid")); + String html64 = set.getString(columnContent); + + htmlPerUUID.put(serverUUID, html64); + } + return htmlPerUUID; + } + }); + } + + public Optional getServerPlayerIsOnline(UUID playerUUID) throws SQLException { + String serverIDColumn = serverTable + "." + serverTable.getColumnID(); + String serverUUIDColumn = serverTable + "." + serverTable.getColumnUUID() + " as s_uuid"; + String sql = "SELECT " + + serverUUIDColumn + + " FROM " + tableName + + " INNER JOIN " + serverTable + " on " + serverIDColumn + "=" + columnSenderID + + " WHERE " + columnExtraVariables + "=?" + + " ORDER BY " + columnExpiry + " LIMIT 1"; + + return query(new QueryStatement>(sql, 1) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, playerUUID.toString()); + } + + @Override + public Optional processResults(ResultSet set) throws SQLException { + if (set.next()) { + return Optional.of(UUID.fromString(set.getString("s_uuid"))); + } + return Optional.empty(); + } + }); + } + + public void storePlayerOnlineOnThisServer(UUID playerUUID) throws SQLException { + execute(new ExecStatement(insertStatement) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, ServerInfo.getServerUUID().toString()); + statement.setLong(2, MiscUtils.getTime() + TimeAmount.MINUTE.ms()); + statement.setString(3, "onlineStatus"); + statement.setString(4, playerUUID.toString()); + statement.setString(5, null); + } + }); + } + + public void storeConfigSettings(String encodedSettingString) throws SQLException { + execute(new ExecStatement(insertStatement) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, ServerInfo.getServerUUID().toString()); + statement.setLong(2, MiscUtils.getTime() + TimeAmount.HOUR.ms()); + statement.setString(3, "configSettings"); + statement.setString(4, null); + statement.setString(5, encodedSettingString); + } + }); + } + + public Optional getConfigSettings() throws SQLException { + return query(new QueryStatement>(selectStatement, 100) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, "configSettings"); + statement.setLong(2, MiscUtils.getTime()); + } + + @Override + public Optional processResults(ResultSet set) throws SQLException { + if (set.next()) { + return Optional.ofNullable(set.getString(columnContent)); + } + return Optional.empty(); + } + }); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/UserIDTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/UserIDTable.java similarity index 74% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/UserIDTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/UserIDTable.java index cba453050..5b7154751 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/UserIDTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/UserIDTable.java @@ -1,7 +1,7 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -18,8 +18,8 @@ public abstract class UserIDTable extends Table { protected final String columnUserID = "user_id"; protected final UsersTable usersTable; - public UserIDTable(String name, SQLDB db, boolean usingMySQL) { - super(name, db, usingMySQL); + public UserIDTable(String name, SQLDB db) { + super(name, db); usersTable = db.getUsersTable(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/UserInfoTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/UserInfoTable.java similarity index 73% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/UserInfoTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/UserInfoTable.java index 14ecd642f..6fcc19cd7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/UserInfoTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/UserInfoTable.java @@ -1,22 +1,20 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; import com.djrapitops.plan.data.container.UserInfo; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Select; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; -import com.djrapitops.plan.database.sql.Update; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Select; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; +import com.djrapitops.plan.system.database.databases.sql.statements.Update; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; @@ -33,20 +31,20 @@ import java.util.*; */ public class UserInfoTable extends UserIDTable { - private final String columnRegistered = "registered"; - private final String columnOP = "opped"; - private final String columnBanned = "banned"; - private final String columnServerID = "server_id"; + private static final String columnRegistered = "registered"; + private static final String columnOP = "opped"; + private static final String columnBanned = "banned"; + private static final String columnServerID = "server_id"; private final ServerTable serverTable; - public UserInfoTable(SQLDB db, boolean usingMySQL) { - super("plan_user_info", db, usingMySQL); + public UserInfoTable(SQLDB db) { + super("plan_user_info", db); serverTable = db.getServerTable(); } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(tableName) .column(columnUserID, Sql.INT).notNull() .column(columnRegistered, Sql.LONG).notNull() @@ -77,13 +75,13 @@ public class UserInfoTable extends UserIDTable { public void prepare(PreparedStatement statement) throws SQLException { statement.setString(1, uuid.toString()); statement.setLong(2, registered); - statement.setString(3, Plan.getServerUUID().toString()); + statement.setString(3, ServerInfo.getServerUUID().toString()); } }); } public boolean isRegistered(UUID uuid) throws SQLException { - return isRegistered(uuid, MiscUtils.getIPlan().getServerUuid()); + return isRegistered(uuid, ServerInfo.getServerUUID()); } public boolean isRegistered(UUID uuid, UUID serverUUID) throws SQLException { @@ -106,23 +104,36 @@ public class UserInfoTable extends UserIDTable { }); } - public void updateOpAndBanStatus(UUID uuid, boolean opped, boolean banned) throws SQLException { - String sql = Update.values(tableName, columnOP, columnBanned) + public void updateOpStatus(UUID uuid, boolean op) throws SQLException { + String sql = Update.values(tableName, columnOP) .where(columnUserID + "=" + usersTable.statementSelectID) .toString(); execute(new ExecStatement(sql) { @Override public void prepare(PreparedStatement statement) throws SQLException { - statement.setBoolean(1, opped); - statement.setBoolean(2, banned); - statement.setString(3, uuid.toString()); + statement.setBoolean(1, op); + statement.setString(2, uuid.toString()); + } + }); + } + + public void updateBanStatus(UUID uuid, boolean banned) throws SQLException { + String sql = Update.values(tableName, columnBanned) + .where(columnUserID + "=" + usersTable.statementSelectID) + .toString(); + + execute(new ExecStatement(sql) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setBoolean(1, banned); + statement.setString(2, uuid.toString()); } }); } public UserInfo getUserInfo(UUID uuid) throws SQLException { - return getAllUserInfo(uuid).get(MiscUtils.getIPlan().getServerUuid()); + return getAllUserInfo(uuid).get(ServerInfo.getServerUUID()); } public Map getAllUserInfo(UUID uuid) throws SQLException { @@ -137,8 +148,8 @@ public class UserInfoTable extends UserIDTable { usersNameColumn + ", " + serverUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + - " JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID + + " INNER JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + + " INNER JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID + " WHERE " + columnUserID + "=" + usersTable.statementSelectID; return query(new QueryStatement>(sql) { @@ -170,21 +181,14 @@ public class UserInfoTable extends UserIDTable { * @return List of UserInfo objects. */ public List getServerUserInfo() throws SQLException { - return getServerUserInfo(Plan.getServerUUID()); + return getServerUserInfo(ServerInfo.getServerUUID()); } public List getServerUserInfo(UUID serverUUID) throws SQLException { - String usersIDColumn = usersTable + "." + usersTable.getColumnID(); - String usersUUIDColumn = usersTable + "." + usersTable.getColumnUUID() + " as uuid"; - String usersNameColumn = usersTable + "." + usersTable.getColumnName() + " as name"; - String sql = "SELECT " + - tableName + "." + columnRegistered + ", " + - columnOP + ", " + - columnBanned + ", " + - usersNameColumn + ", " + - usersUUIDColumn + - " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + + Map playerNames = usersTable.getPlayerNames(); + Map uuidsByID = usersTable.getUUIDsByID(); + + String sql = "SELECT * FROM " + tableName + " WHERE " + columnServerID + "=" + serverTable.statementSelectServerID; return query(new QueryStatement>(sql, 20000) { @@ -200,8 +204,9 @@ public class UserInfoTable extends UserIDTable { long registered = set.getLong(columnRegistered); boolean opped = set.getBoolean(columnOP); boolean banned = set.getBoolean(columnBanned); - String name = set.getString("name"); - UUID uuid = UUID.fromString(set.getString("uuid")); + int userId = set.getInt(columnUserID); + UUID uuid = uuidsByID.get(userId); + String name = playerNames.getOrDefault(uuid, "Unknown"); UserInfo info = new UserInfo(uuid, name, registered, opped, banned); if (!userInfo.contains(info)) { userInfo.add(info); @@ -224,8 +229,8 @@ public class UserInfoTable extends UserIDTable { usersUUIDColumn + ", " + serverUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + - " JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; + " INNER JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + + " INNER JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; return query(new QueryAllStatement>>(sql, 50000) { @Override @@ -295,8 +300,8 @@ public class UserInfoTable extends UserIDTable { usersUUIDColumn + ", " + serverUUIDColumn + " FROM " + tableName + - " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + - " JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; + " INNER JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + + " INNER JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID; return query(new QueryAllStatement>>(sql, 50000) { @Override @@ -316,30 +321,30 @@ public class UserInfoTable extends UserIDTable { }); } - public int getServerUserCount(UUID serverUUID) { - try { - String sql = "SELECT " + - " COUNT(" + columnRegistered + ") as c" + - " FROM " + tableName + - " WHERE " + columnServerID + "=" + serverTable.statementSelectServerID; + public int getServerUserCount(UUID serverUUID) throws SQLException { + String sql = "SELECT " + + " COUNT(" + columnRegistered + ") as c" + + " FROM " + tableName + + " WHERE " + columnServerID + "=" + serverTable.statementSelectServerID; - return query(new QueryStatement(sql, 20000) { - @Override - public void prepare(PreparedStatement statement) throws SQLException { - statement.setString(1, serverUUID.toString()); - } + return query(new QueryAllStatement(sql, 20000) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, serverUUID.toString()); + } - @Override - public Integer processResults(ResultSet set) throws SQLException { - if (set.next()) { - return set.getInt("c"); - } - return 0; + @Override + public Integer processResults(ResultSet set) throws SQLException { + if (set.next()) { + return set.getInt("c"); } - }); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - return 0; - } + return 0; + } + }); + } + + // TODO improve performance of this method. + public Set getSavedUUIDs(UUID serverUUID) throws SQLException { + return getSavedUUIDs().get(serverUUID); } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/UsersTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/UsersTable.java similarity index 89% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/UsersTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/UsersTable.java index abfdbb7f4..34bc6e202 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/UsersTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/UsersTable.java @@ -1,12 +1,12 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; import com.djrapitops.plan.data.container.UserInfo; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.*; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.*; import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; @@ -20,16 +20,16 @@ import java.util.*; public class UsersTable extends UserIDTable { public final String statementSelectID; - private final String columnID = "id"; - private final String columnUUID = "uuid"; - private final String columnRegistered = "registered"; - private final String columnName = "name"; - private final String columnTimesKicked = "times_kicked"; + private static final String columnID = "id"; + private static final String columnUUID = "uuid"; + private static final String columnRegistered = "registered"; + private static final String columnName = "name"; + private static final String columnTimesKicked = "times_kicked"; private String insertStatement; - public UsersTable(SQLDB db, boolean usingMySQL) { - super("plan_users", db, usingMySQL); - statementSelectID = "(" + Select.from(tableName, tableName + "." + columnID).where(columnUUID + "=?").toString() + ")"; + public UsersTable(SQLDB db) { + super("plan_users", db); + statementSelectID = "(" + Select.from(tableName, tableName + "." + columnID).where(columnUUID + "=?").toString() + " LIMIT 1)"; insertStatement = Insert.values(tableName, columnUUID, columnRegistered, @@ -37,7 +37,7 @@ public class UsersTable extends UserIDTable { } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(tableName) .primaryKeyIDColumn(usingMySQL, columnID) .column(columnUUID, Sql.varchar(36)).notNull().unique() @@ -265,7 +265,7 @@ public class UsersTable extends UserIDTable { String sql = "SELECT DISTINCT " + columnName + " FROM " + tableName + " WHERE " + columnName + " LIKE ?" + " UNION SELECT DISTINCT " + columnName + " FROM " + tableName + - " JOIN " + nicknamesTable + " on " + columnID + "=" + nicknamesTable + "." + nicknamesTable.getColumnUserID() + + " INNER JOIN " + nicknamesTable + " on " + columnID + "=" + nicknamesTable + "." + nicknamesTable.getColumnUserID() + " WHERE " + nicknamesTable.getColumnNick() + " LIKE ?"; return query(new QueryStatement>(sql, 5000) { @@ -433,4 +433,23 @@ public class UsersTable extends UserIDTable { } }); } + + public Map getUUIDsByID() throws SQLException { + String sql = Select.from(tableName, columnID, columnUUID).toString(); + + return query(new QueryAllStatement>(sql, 20000) { + @Override + public Map processResults(ResultSet set) throws SQLException { + Map uuidsByID = new TreeMap<>(); + + while (set.next()) { + int id = set.getInt(columnID); + UUID uuid = UUID.fromString(set.getString(columnUUID)); + uuidsByID.put(id, uuid); + } + + return uuidsByID; + } + }); + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/VersionTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/VersionTable.java similarity index 73% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/VersionTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/VersionTable.java index d398549d8..ae2673875 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/VersionTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/VersionTable.java @@ -1,12 +1,12 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -17,12 +17,12 @@ import java.sql.SQLException; */ public class VersionTable extends Table { - public VersionTable(SQLDB db, boolean usingMySQL) { - super("plan_version", db, usingMySQL); + public VersionTable(SQLDB db) { + super("plan_version", db); } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(tableName) .column("version", Sql.INT).notNull() .toString() diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/WorldTable.java similarity index 67% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/WorldTable.java index ec9a8e53e..e1c10ffd7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/WorldTable.java @@ -1,13 +1,13 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; @@ -26,22 +26,16 @@ import java.util.*; public class WorldTable extends Table { public final String statementSelectID; - private final String columnWorldId = "id"; - private final String columnWorldName = "world_name"; + private static final String columnWorldId = "id"; + private static final String columnWorldName = "world_name"; - /** - * Constructor. - * - * @param db Database this table is a part of. - * @param usingMySQL Database is a MySQL database. - */ - public WorldTable(SQLDB db, boolean usingMySQL) { - super("plan_worlds", db, usingMySQL); - statementSelectID = "(SELECT " + columnWorldId + " FROM " + tableName + " WHERE (" + columnWorldName + "=?))"; + public WorldTable(SQLDB db) { + super("plan_worlds", db); + statementSelectID = "(SELECT " + columnWorldId + " FROM " + tableName + " WHERE (" + columnWorldName + "=?) LIMIT 1)"; } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(tableName) .primaryKeyIDColumn(usingMySQL, columnWorldId) .column(columnWorldName, Sql.varchar(100)).notNull() @@ -114,7 +108,7 @@ public class WorldTable extends Table { } public Set getWorldNames() throws SQLException { - return getWorldNames(MiscUtils.getIPlan().getServerUuid()); + return getWorldNames(ServerInfo.getServerUUID()); } public Set getWorldNames(UUID serverUUID) throws SQLException { @@ -132,8 +126,8 @@ public class WorldTable extends Table { String sql = "SELECT DISTINCT " + columnWorldName + " FROM " + tableName + - " JOIN " + worldTimesTable + " on " + worldIDColumn + "=" + tableName + "." + columnWorldId + - " JOIN " + sessionsTable + " on " + worldSessionIDColumn + "=" + sessionIDColumn + + " INNER JOIN " + worldTimesTable + " on " + worldIDColumn + "=" + tableName + "." + columnWorldId + + " INNER JOIN " + sessionsTable + " on " + worldSessionIDColumn + "=" + sessionIDColumn + " WHERE " + statementSelectServerID + "=" + sessionServerIDColumn; return query(new QueryStatement>(sql, 1000) { @@ -152,4 +146,24 @@ public class WorldTable extends Table { } }); } + + public Map getWorldIds() throws SQLException { + String sql = "SELECT DISTINCT " + + columnWorldName + ", " + + columnWorldId + " FROM " + + tableName; + + return query(new QueryAllStatement>(sql, 200) { + @Override + public Map processResults(ResultSet set) throws SQLException { + Map worldIds = new HashMap<>(); + while (set.next()) { + String worldName = set.getString(columnWorldName); + int worldId = set.getInt(columnWorldId); + worldIds.put(worldName, worldId); + } + return worldIds; + } + }); + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTimesTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/WorldTimesTable.java similarity index 89% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTimesTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/WorldTimesTable.java index fec3b97c8..baf21dd16 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTimesTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/WorldTimesTable.java @@ -1,16 +1,16 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.time.GMTimes; import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.processing.ExecStatement; -import com.djrapitops.plan.database.processing.QueryAllStatement; -import com.djrapitops.plan.database.processing.QueryStatement; -import com.djrapitops.plan.database.sql.Sql; -import com.djrapitops.plan.database.sql.TableSqlParser; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; +import com.djrapitops.plan.system.database.databases.sql.statements.Sql; +import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; @@ -27,25 +27,19 @@ import java.util.stream.Collectors; */ public class WorldTimesTable extends UserIDTable { - private final String columnSessionID = "session_id"; - private final String columnWorldId = "world_id"; - private final String columnSurvival = "survival_time"; - private final String columnCreative = "creative_time"; - private final String columnAdventure = "adventure_time"; - private final String columnSpectator = "spectator_time"; + private static final String columnSessionID = "session_id"; + private static final String columnWorldId = "world_id"; + private static final String columnSurvival = "survival_time"; + private static final String columnCreative = "creative_time"; + private static final String columnAdventure = "adventure_time"; + private static final String columnSpectator = "spectator_time"; private final WorldTable worldTable; private final SessionsTable sessionsTable; private String insertStatement; - /** - * Constructor. - * - * @param db Database this table is a part of. - * @param usingMySQL Database is a MySQL database. - */ - public WorldTimesTable(SQLDB db, boolean usingMySQL) { - super("plan_world_times", db, usingMySQL); + public WorldTimesTable(SQLDB db) { + super("plan_world_times", db); worldTable = db.getWorldTable(); sessionsTable = db.getSessionsTable(); insertStatement = "INSERT INTO " + tableName + " (" + @@ -63,7 +57,7 @@ public class WorldTimesTable extends UserIDTable { } @Override - public void createTable() throws DBCreateTableException { + public void createTable() throws DBInitException { createTable(TableSqlParser.createTable(tableName) .column(columnUserID, Sql.INT).notNull() .column(columnWorldId, Sql.INT).notNull() @@ -120,7 +114,7 @@ public class WorldTimesTable extends UserIDTable { columnSpectator + ", " + worldNameColumn + " FROM " + tableName + - " JOIN " + worldTable + " on " + worldIDColumn + "=" + columnWorldId + + " INNER JOIN " + worldTable + " on " + worldIDColumn + "=" + columnWorldId + " WHERE " + columnUserID + "=" + usersTable.statementSelectID; query(new QueryStatement(sql, 2000) { @@ -158,7 +152,7 @@ public class WorldTimesTable extends UserIDTable { } public WorldTimes getWorldTimesOfServer() throws SQLException { - return getWorldTimesOfServer(Plan.getServerUUID()); + return getWorldTimesOfServer(ServerInfo.getServerUUID()); } public WorldTimes getWorldTimesOfServer(UUID serverUUID) throws SQLException { @@ -173,8 +167,8 @@ public class WorldTimesTable extends UserIDTable { "SUM(" + columnSpectator + ") as spectator, " + worldNameColumn + " FROM " + tableName + - " JOIN " + worldTable + " on " + worldIDColumn + "=" + columnWorldId + - " JOIN " + sessionsTable + " on " + sessionIDColumn + "=" + columnSessionID + + " INNER JOIN " + worldTable + " on " + worldIDColumn + "=" + columnWorldId + + " INNER JOIN " + sessionsTable + " on " + sessionIDColumn + "=" + columnSessionID + " WHERE " + sessionServerIDColumn + "=" + db.getServerTable().statementSelectServerID + " GROUP BY " + columnWorldId; @@ -216,7 +210,7 @@ public class WorldTimesTable extends UserIDTable { "SUM(" + columnSpectator + ") as spectator, " + worldNameColumn + " FROM " + tableName + - " JOIN " + worldTable + " on " + worldIDColumn + "=" + columnWorldId + + " INNER JOIN " + worldTable + " on " + worldIDColumn + "=" + columnWorldId + " WHERE " + columnUserID + "=" + usersTable.statementSelectID + " GROUP BY " + columnWorldId; @@ -323,7 +317,7 @@ public class WorldTimesTable extends UserIDTable { columnSpectator + ", " + worldNameColumn + " FROM " + tableName + - " JOIN " + worldTable + " on " + worldIDColumn + "=" + columnWorldId; + " INNER JOIN " + worldTable + " on " + worldIDColumn + "=" + columnWorldId; return query(new QueryAllStatement>(sql, 50000) { @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/move/BatchOperationTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/move/BatchOperationTable.java similarity index 82% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/move/BatchOperationTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/move/BatchOperationTable.java index e328d2417..0e8ded0cd 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/move/BatchOperationTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/move/BatchOperationTable.java @@ -1,19 +1,20 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.database.tables.move; +package com.djrapitops.plan.system.database.databases.sql.tables.move; +import com.djrapitops.plan.api.exceptions.database.DBException; import com.djrapitops.plan.data.container.UserInfo; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.tables.ServerTable; -import com.djrapitops.plan.database.tables.Table; -import com.djrapitops.plan.database.tables.UsersTable; -import com.djrapitops.plan.systems.info.server.ServerInfo; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.tables.ServerTable; +import com.djrapitops.plan.system.database.databases.sql.tables.Table; +import com.djrapitops.plan.system.database.databases.sql.tables.UsersTable; +import com.djrapitops.plan.system.info.server.Server; import com.djrapitops.plugin.api.utility.log.Log; import java.sql.SQLException; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; @@ -39,14 +40,16 @@ import java.util.UUID; public class BatchOperationTable extends Table { /** - * Constructor, call to access copy functionality. + * Constructor. + *

+ * Call to access copy functionality. * * @param database Database to copy things from * @throws IllegalStateException if database.init has not been called. * @throws ClassCastException if database is not SQLDB. */ - public BatchOperationTable(Database database) { - super("", (SQLDB) database, false); + public BatchOperationTable(SQLDB database) { + super("", database); if (!db.isOpen()) { throw new IllegalStateException("Given Database had not been initialized."); } @@ -63,7 +66,15 @@ public class BatchOperationTable extends Table { @Override public void removeAllData() throws SQLException { - db.removeAllData(); + try { + db.remove().everything(); + } catch (DBException e) { + if (e.getCause() instanceof SQLException) { + throw (SQLException) e.getCause(); + } else { + Log.toLog(this.getClass(), e); + } + } } public void copyEverything(BatchOperationTable toDB) throws SQLException { @@ -107,7 +118,7 @@ public class BatchOperationTable extends Table { return; } Log.debug("Batch Copy IPs, Geolocations & Last used dates"); - toDB.getDb().getIpsTable().insertAllGeoInfo(db.getIpsTable().getAllGeoInfo()); + toDB.getDb().getGeoInfoTable().insertAllGeoInfo(db.getGeoInfoTable().getAllGeoInfo()); } public void copyNicknames(BatchOperationTable toDB) throws SQLException { @@ -132,7 +143,7 @@ public class BatchOperationTable extends Table { } Log.debug("Batch Copy Servers"); ServerTable serverTable = db.getServerTable(); - List servers = serverTable.getBukkitServers(); + List servers = new ArrayList<>(serverTable.getBukkitServers().values()); serverTable.getBungeeInfo().ifPresent(servers::add); toDB.getDb().getServerTable().insertAllServers(servers); } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/move/Version8TransferTable.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/move/Version8TransferTable.java similarity index 87% rename from Plan/src/main/java/com/djrapitops/plan/database/tables/move/Version8TransferTable.java rename to Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/move/Version8TransferTable.java index bce666da9..fd74bbcb6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/move/Version8TransferTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/tables/move/Version8TransferTable.java @@ -1,13 +1,13 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.database.tables.move; +package com.djrapitops.plan.system.database.databases.sql.tables.move; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.DBCreateTableException; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.tables.*; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.tables.*; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plugin.api.Benchmark; import java.sql.SQLException; @@ -24,9 +24,9 @@ public class Version8TransferTable extends Table { private final int serverID; - public Version8TransferTable(SQLDB db, boolean usingMySQL) throws SQLException { - super("", db, usingMySQL); - Optional serverID = db.getServerTable().getServerID(Plan.getServerUUID()); + public Version8TransferTable(SQLDB db) throws SQLException { + super("", db); + Optional serverID = db.getServerTable().getServerID(ServerInfo.getServerUUID()); if (!serverID.isPresent()) { throw new IllegalStateException("Server UUID was not registered, try rebooting the plugin."); } @@ -48,7 +48,7 @@ public class Version8TransferTable extends Table { return "DROP TABLE " + name; } - public void alterTablesToV10() throws SQLException, DBCreateTableException { + public void alterTablesToV10() throws SQLException, DBInitException { Benchmark.start("Schema copy from 8 to 10"); copyCommandUsage(); @@ -58,7 +58,7 @@ public class Version8TransferTable extends Table { copyUsers(); execute(dropTableSql("plan_ips")); - db.getIpsTable().createTable(); + db.getGeoInfoTable().createTable(); execute(dropTableSql("plan_world_times")); execute(dropTableSql("plan_worlds")); db.getWorldTable().createTable(); @@ -76,7 +76,7 @@ public class Version8TransferTable extends Table { Benchmark.stop("Schema copy from 8 to 10"); } - private void copyUsers() throws SQLException, DBCreateTableException { + private void copyUsers() throws SQLException, DBInitException { String tempTableName = "temp_users"; UsersTable usersTable = db.getUsersTable(); execute(tableRenameSql("plan_users", tempTableName)); @@ -137,7 +137,7 @@ public class Version8TransferTable extends Table { } } - private void copyCommandUsage() throws SQLException, DBCreateTableException { + private void copyCommandUsage() throws SQLException, DBInitException { String tempTableName = "temp_cmdusg"; CommandUseTable commandUseTable = db.getCommandUseTable(); @@ -156,7 +156,7 @@ public class Version8TransferTable extends Table { execute(dropTableSql(tempTableName)); } - private void copyTPS() throws SQLException, DBCreateTableException { + private void copyTPS() throws SQLException, DBInitException { String tempTableName = "temp_tps"; TPSTable tpsTable = db.getTpsTable(); diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/file/FileSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/file/FileSystem.java similarity index 62% rename from Plan/src/main/java/com/djrapitops/plan/systems/file/FileSystem.java rename to Plan/src/main/java/com/djrapitops/plan/system/file/FileSystem.java index 2b2de1916..7e0c4d323 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/file/FileSystem.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/file/FileSystem.java @@ -2,20 +2,20 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.file; +package com.djrapitops.plan.system.file; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.systems.SubSystem; -import com.djrapitops.plan.systems.Systems; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; import com.djrapitops.plan.utilities.file.FileUtil; +import com.djrapitops.plugin.utilities.Verify; import java.io.File; import java.io.IOException; import java.util.List; /** - * //TODO Class Javadoc Comment + * Abstracts File methods of Plugin classes so that they can be tested without Mocks. * * @author Rsl1122 */ @@ -24,16 +24,19 @@ public class FileSystem implements SubSystem { private final File dataFolder; private File configFile; - public FileSystem(IPlan plugin) { + public FileSystem(PlanPlugin plugin) { this(plugin.getDataFolder()); } public FileSystem(File dataFolder) { this.dataFolder = dataFolder; + configFile = new File(dataFolder, "config.yml"); } public static FileSystem getInstance() { - return Systems.getInstance().getFileSystem(); + FileSystem fileSystem = PlanSystem.getInstance().getFileSystem(); + Verify.nullCheck(fileSystem, () -> new IllegalStateException("File system was not initialized.")); + return fileSystem; } public static File getDataFolder() { @@ -49,17 +52,16 @@ public class FileSystem implements SubSystem { } public static List readFromResource(String fileName) throws IOException { - return FileUtil.lines(MiscUtils.getIPlan(), fileName); + return FileUtil.lines(PlanPlugin.getInstance(), fileName); } @Override - public void init() { + public void enable() { dataFolder.mkdirs(); - configFile = new File(dataFolder, "config.yml"); } @Override - public void close() { + public void disable() { } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/BukkitInfoSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/info/BukkitInfoSystem.java new file mode 100644 index 000000000..3818e46b8 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/BukkitInfoSystem.java @@ -0,0 +1,40 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info; + +import com.djrapitops.plan.api.exceptions.connection.NoServersException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.info.connection.BukkitConnectionSystem; +import com.djrapitops.plan.system.info.request.CacheNetworkPageContentRequest; +import com.djrapitops.plan.system.info.request.InfoRequest; +import com.djrapitops.plan.system.info.request.SetupRequest; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.utilities.html.HtmlStructure; + +/** + * InfoSystem for Bukkit servers. + * + * @author Rsl1122 + */ +public class BukkitInfoSystem extends InfoSystem { + + public BukkitInfoSystem() { + super(new BukkitConnectionSystem()); + } + + @Override + public void runLocally(InfoRequest infoRequest) throws WebException { + if (infoRequest instanceof SetupRequest) { + throw new NoServersException("Set-up requests can not be run locally."); + } + infoRequest.runLocally(); + } + + @Override + public void updateNetworkPage() throws WebException { + String html = HtmlStructure.createServerContainer(); + sendRequest(new CacheNetworkPageContentRequest(ServerInfo.getServerUUID(), html)); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/BungeeInfoSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/info/BungeeInfoSystem.java new file mode 100644 index 000000000..be6018541 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/BungeeInfoSystem.java @@ -0,0 +1,45 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info; + +import com.djrapitops.plan.api.exceptions.ParseException; +import com.djrapitops.plan.api.exceptions.connection.NoServersException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.api.exceptions.connection.WebFailException; +import com.djrapitops.plan.system.info.connection.BungeeConnectionSystem; +import com.djrapitops.plan.system.info.request.InfoRequest; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.webserver.pages.parsing.NetworkPage; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.pages.AnalysisPageResponse; + +/** + * InfoSystem for Bungee. + * + * @author Rsl1122 + */ +public class BungeeInfoSystem extends InfoSystem { + + public BungeeInfoSystem() { + super(new BungeeConnectionSystem()); + } + + @Override + public void runLocally(InfoRequest infoRequest) throws WebException { + // runLocally is called when ConnectionSystem has no servers. + throw new NoServersException("No servers were available to process this request (Local attempt): " + infoRequest.getClass().getSimpleName()); + } + + @Override + public void updateNetworkPage() throws WebException { + try { + String html = new NetworkPage().toHtml(); + ResponseCache.cacheResponse(PageId.SERVER.of(ServerInfo.getServerUUID()), () -> new AnalysisPageResponse(html)); + } catch (ParseException e) { + throw new WebFailException("Exception during Network Page Parsing", e); + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/InfoSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/info/InfoSystem.java new file mode 100644 index 000000000..19c39860a --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/InfoSystem.java @@ -0,0 +1,173 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info; + +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.api.exceptions.connection.BadRequestException; +import com.djrapitops.plan.api.exceptions.connection.ConnectionFailException; +import com.djrapitops.plan.api.exceptions.connection.NoServersException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.info.request.GenerateAnalysisPageRequest; +import com.djrapitops.plan.system.info.request.GenerateInspectPageRequest; +import com.djrapitops.plan.system.info.request.InfoRequest; +import com.djrapitops.plan.system.info.request.SendDBSettingsRequest; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.webserver.WebServerSystem; +import com.djrapitops.plugin.api.Check; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.UUID; + +/** + * Information management system. + *

+ * Subclasses should decide how InfoRequests are run locally if necessary. + * + * Everything should be called from an Async thread. + * + * @author Rsl1122 + */ +public abstract class InfoSystem implements SubSystem { + + protected final ConnectionSystem connectionSystem; + + protected InfoSystem(ConnectionSystem connectionSystem) { + this.connectionSystem = connectionSystem; + } + + public static InfoSystem getInstance() { + InfoSystem infoSystem = PlanSystem.getInstance().getInfoSystem(); + Verify.nullCheck(infoSystem, () -> new IllegalStateException("Info System was not initialized.")); + return infoSystem; + } + + /** + * Refreshes Player page. + *

+ * No calls from non-async thread found on 09.02.2018 + * + * @param player UUID of the player. + * @throws WebException If fails. + */ + public void generateAndCachePlayerPage(UUID player) throws WebException { + GenerateInspectPageRequest infoRequest = new GenerateInspectPageRequest(player); + try { + sendRequest(infoRequest); + } catch (ConnectionFailException e) { + connectionSystem.sendWideInfoRequest(infoRequest); + } + } + + /** + * Refreshes Analysis page. + * + * No calls from non-async thread found on 09.02.2018 + * + * @param serverUUID UUID of the server to analyze + * @throws WebException If fails. + */ + public void generateAnalysisPage(UUID serverUUID) throws WebException { + GenerateAnalysisPageRequest request = new GenerateAnalysisPageRequest(serverUUID); + if (ServerInfo.getServerUUID().equals(serverUUID)) { + runLocally(request); + } else { + sendRequest(request); + } + } + + /** + * Send an InfoRequest to another server or run locally if necessary. + * + * No calls from non-async thread found on 09.02.2018 + * + * @param infoRequest InfoRequest to send or run. + * @throws WebException If fails. + */ + public void sendRequest(InfoRequest infoRequest) throws WebException { + try { + if (!connectionSystem.isServerAvailable()) { + runLocally(infoRequest); + return; + } + connectionSystem.sendInfoRequest(infoRequest); + } catch (WebException original) { + try { + // Attempt to run locally. + runLocally(infoRequest); + } catch (NoServersException e2) { + throw original; + } + } + } + + /** + * Run the InfoRequest locally. + * + * No calls from non-async thread found on 09.02.2018 + * + * @param infoRequest InfoRequest to run. + * @throws WebException If fails. + */ + public abstract void runLocally(InfoRequest infoRequest) throws WebException; + + @Override + public void enable() throws EnableException { + connectionSystem.enable(); + Processor.queue(() -> { + try { + updateNetworkPage(); + } catch (NoServersException e) { + /* Ignored */ + } catch (WebException e) { + // TODO Exception handling + Log.toLog(this.getClass(), e); + } + }); + } + + @Override + public void disable() { + connectionSystem.disable(); + } + + public ConnectionSystem getConnectionSystem() { + return connectionSystem; + } + + /** + * Updates Network page. + * + * No calls from non-async thread found on 09.02.2018 + * + * @throws WebException If fails. + */ + public abstract void updateNetworkPage() throws WebException; + + /** + * Requests Set up from Bungee. + * + * No calls from non-async thread found on 09.02.2018 + * + * @param addressToRequestServer Address of Bungee server. + * @throws WebException If fails. + */ + public void requestSetUp(String addressToRequestServer) throws WebException { + if (Check.isBungeeAvailable()) { + throw new BadRequestException("Method not available on Bungee."); + } + Server bungee = new Server(-1, null, "Bungee", addressToRequestServer, -1); + String addressOfThisServer = WebServerSystem.getInstance().getWebServer().getAccessAddress(); + + ConnectionSystem connectionSystem = ConnectionSystem.getInstance(); + connectionSystem.setSetupAllowed(true); + connectionSystem.sendInfoRequest(new SendDBSettingsRequest(addressOfThisServer), bungee); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/connection/BukkitConnectionSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/BukkitConnectionSystem.java new file mode 100644 index 000000000..7b48d74fb --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/BukkitConnectionSystem.java @@ -0,0 +1,130 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.connection; + +import com.djrapitops.plan.api.exceptions.connection.ConnectionFailException; +import com.djrapitops.plan.api.exceptions.connection.NoServersException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.request.*; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plan.system.webserver.WebServerSystem; +import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plugin.api.TimeAmount; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.util.Optional; +import java.util.UUID; + +/** + * Connection system for Bukkit servers. + * + * @author Rsl1122 + */ +public class BukkitConnectionSystem extends ConnectionSystem { + + private long latestServerMapRefresh; + + private Server mainServer; + + public BukkitConnectionSystem() { + latestServerMapRefresh = 0; + } + + private void refreshServerMap() { + Processor.queue(() -> { + if (latestServerMapRefresh < MiscUtils.getTime() - TimeAmount.SECOND.ms() * 15L) { + try { + Database database = Database.getActive(); + Optional bungeeInformation = database.fetch().getBungeeInformation(); + bungeeInformation.ifPresent(server -> mainServer = server); + bukkitServers = database.fetch().getBukkitServers(); + latestServerMapRefresh = MiscUtils.getTime(); + } catch (DBException e) { + Log.toLog(this.getClass(), e); + } + } + }); + } + + @Override + protected Server selectServerForRequest(InfoRequest infoRequest) throws NoServersException { + refreshServerMap(); + + if (mainServer == null && bukkitServers.isEmpty()) { + throw new NoServersException("Zero servers available to process requests."); + } + + Server server = null; + if (infoRequest instanceof CacheRequest) { + server = mainServer; + } else if (infoRequest instanceof GenerateAnalysisPageRequest) { + UUID serverUUID = ((GenerateAnalysisPageRequest) infoRequest).getServerUUID(); + server = bukkitServers.get(serverUUID); + } else if (infoRequest instanceof GenerateInspectPageRequest) { + Optional serverUUID = getServerWherePlayerIsOnline((GenerateInspectPageRequest) infoRequest); + if (serverUUID.isPresent()) { + server = bukkitServers.getOrDefault(serverUUID.get(), ServerInfo.getServer()); + } + } + if (server == null) { + throw new NoServersException("Proper server is not available to process request: " + infoRequest.getClass().getSimpleName()); + } + return server; + } + + @Override + public void sendWideInfoRequest(WideRequest infoRequest) throws NoServersException { + if (bukkitServers.isEmpty()) { + throw new NoServersException("No Servers available to make wide-request: " + infoRequest.getClass().getSimpleName()); + } + for (Server server : bukkitServers.values()) { + WebExceptionLogger.logIfOccurs(this.getClass(), () -> { + try { + sendInfoRequest(infoRequest, server); + } catch (ConnectionFailException ignored) { + /* Wide Requests are used when at least one result is wanted. */ + } + }); + } + } + + @Override + public boolean isServerAvailable() { + return mainServer != null && Settings.BUNGEE_OVERRIDE_STANDALONE_MODE.isFalse(); + } + + @Override + public String getMainAddress() { + return isServerAvailable() ? mainServer.getWebAddress() : ServerInfo.getServer().getWebAddress(); + + } + + @Override + public void enable() { + refreshServerMap(); + + boolean usingBungeeWebServer = ConnectionSystem.getInstance().isServerAvailable(); + boolean usingAlternativeIP = Settings.SHOW_ALTERNATIVE_IP.isTrue(); + + if (!usingAlternativeIP && ServerInfo.getServerProperties().getIp().isEmpty()) { + Log.infoColor(Locale.get(Msg.ENABLE_NOTIFY_EMPTY_IP).toString()); + } + if (usingBungeeWebServer && usingAlternativeIP) { + String webServerAddress = WebServerSystem.getInstance().getWebServer().getAccessAddress(); + Log.info("Make sure that this address points to THIS Bukkit Server: " + webServerAddress); + } + } + + @Override + public void disable() { + + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/connection/BungeeConnectionSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/BungeeConnectionSystem.java new file mode 100644 index 000000000..4513cd3b8 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/BungeeConnectionSystem.java @@ -0,0 +1,112 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.connection; + +import com.djrapitops.plan.api.exceptions.connection.NoServersException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.request.*; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.webserver.WebServerSystem; +import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plugin.api.TimeAmount; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +/** + * ConnectionSystem for Bungee. + * + * @author Rsl1122 + */ +public class BungeeConnectionSystem extends ConnectionSystem { + + private long latestServerMapRefresh; + + public BungeeConnectionSystem() { + latestServerMapRefresh = 0; + } + + private void refreshServerMap() { + if (latestServerMapRefresh < MiscUtils.getTime() - TimeAmount.SECOND.ms() * 15L) { + try { + bukkitServers = Database.getActive().fetch().getBukkitServers(); + latestServerMapRefresh = MiscUtils.getTime(); + } catch (DBException e) { + Log.toLog(this.getClass(), e); + } + } + } + + @Override + protected Server selectServerForRequest(InfoRequest infoRequest) throws NoServersException { + refreshServerMap(); + Server server = null; + if (infoRequest instanceof CacheRequest) { + throw new NoServersException("Bungee should not send Cache requests."); + } else if (infoRequest instanceof GenerateAnalysisPageRequest) { + UUID serverUUID = ((GenerateAnalysisPageRequest) infoRequest).getServerUUID(); + server = bukkitServers.get(serverUUID); + } else if (infoRequest instanceof GenerateInspectPageRequest) { + Optional serverUUID = getServerWherePlayerIsOnline((GenerateInspectPageRequest) infoRequest); + if (serverUUID.isPresent()) { + server = bukkitServers.getOrDefault(serverUUID.get(), getOneBukkitServer()); + } else { + server = getOneBukkitServer(); + } + } + if (server == null) { + throw new NoServersException("Proper server is not available to process request: " + infoRequest.getClass().getSimpleName()); + } + return server; + } + + private Server getOneBukkitServer() { + int rand = ThreadLocalRandom.current().nextInt(bukkitServers.size()); + int i = 0; + for (Server server : bukkitServers.values()) { + if (i == rand) { + return server; + } + i++; + } + // Fallback if code above fails (Shouldn't) + Optional first = bukkitServers.values().stream().findAny(); + return first.orElse(null); + } + + @Override + public void sendWideInfoRequest(WideRequest infoRequest) throws NoServersException { + refreshServerMap(); + if (bukkitServers.isEmpty()) { + throw new NoServersException("No Servers available to make wide-request: " + infoRequest.getClass().getSimpleName()); + } + for (Server server : bukkitServers.values()) { + WebExceptionLogger.logIfOccurs(this.getClass(), () -> sendInfoRequest(infoRequest, server)); + } + } + + @Override + public boolean isServerAvailable() { + return true; + } + + @Override + public String getMainAddress() { + return WebServerSystem.getInstance().getWebServer().getAccessAddress(); + } + + @Override + public void enable() { + refreshServerMap(); + } + + @Override + public void disable() { + + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionIn.java b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionIn.java new file mode 100644 index 000000000..065520cb3 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionIn.java @@ -0,0 +1,99 @@ +package com.djrapitops.plan.system.info.connection; + +import com.djrapitops.plan.api.exceptions.connection.*; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.request.InfoRequest; +import com.djrapitops.plan.system.info.request.SetupRequest; +import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +public class ConnectionIn { + + private final Map variables; + private final InfoRequest infoRequest; + + public ConnectionIn(Request httpRequest, InfoRequest infoRequest) throws WebException { + Verify.nullCheck(httpRequest, infoRequest); + + this.variables = readVariables(httpRequest); + this.infoRequest = infoRequest; + + checkAuthentication(); + } + + private void checkAuthentication() throws WebException { + UUID serverUUID = getServerUUID(); + + try { + if (Database.getActive().check().isServerInDatabase(serverUUID)) { + return; + } + } catch (DBException e) { + throw new TransferDatabaseException(e); + } + + Log.debug("ConnectionIn: " + infoRequest.getClass().getSimpleName()); + + if (infoRequest instanceof SetupRequest) { + if (!ConnectionSystem.isSetupAllowed()) { + throw new ForbiddenException("Setup not enabled on this server, use commands to enable."); + } + } else { + throw new UnauthorizedServerException(serverUUID + " (Sender) was not found from database"); + } + } + + private UUID getServerUUID() throws BadRequestException { + String sender = variables.get("sender"); + Verify.nullCheck(sender, () -> new BadRequestException("Sender ('sender') variable not supplied in the request.")); + + try { + return UUID.fromString(sender); + } catch (IllegalArgumentException e) { + throw new BadRequestException("Sender ('sender') was not a valid UUID: " + e.getMessage()); + } + } + + private Map readVariables(Request request) throws WebException { + String requestBody = readRequestBody(request.getRequestBody()); + String[] variables = requestBody.split(";&variable;"); + + return Arrays.stream(variables) + .map(variable -> variable.split("=", 2)) + .filter(splitVariables -> splitVariables.length == 2) + .collect(Collectors.toMap(splitVariables -> splitVariables[0], splitVariables -> splitVariables[1], (a, b) -> b)); + } + + public Response handleRequest() throws WebException { + return infoRequest.handleRequest(variables); + } + + private String readRequestBody(InputStream in) throws WebFailException { + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + byte[] bytes; + + byte[] buf = new byte[4096]; + for (int n = in.read(buf); n > 0; n = in.read(buf)) { + out.write(buf, 0, n); + } + + bytes = out.toByteArray(); + + return new String(bytes, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new WebFailException("Exception while reading Request.", e); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionLog.java b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionLog.java new file mode 100644 index 000000000..1064d5ff0 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionLog.java @@ -0,0 +1,89 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.connection; + +import com.djrapitops.plan.system.info.request.InfoRequest; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.utilities.MiscUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * Class responsible for logging what ConnectionOut objects get in return. + * + * @author Rsl1122 + */ +public class ConnectionLog { + + private Map> log; + + public ConnectionLog() { + this.log = new HashMap<>(); + } + + /** + * Get a map sorted by Addresses, then Requests and then Log entries. + * + * @return {@code Map<"In: "/"Out: "+Address, Map>} + */ + public static Map> getLogEntries() { + return getInstance().getLog(); + } + + public static void logConnectionTo(Server server, InfoRequest request, int responseCode) { + logConnection(server.getWebAddress(), "Out: " + request.getClass().getSimpleName(), responseCode); + } + + public static void logConnectionFrom(String server, String requestTarget, int responseCode) { + logConnection(server, "In: " + requestTarget, responseCode); + } + + private static void logConnection(String address, String infoRequestName, int responseCode) { + Map> log = getInstance().log; + Map requestMap = log.getOrDefault(address, new HashMap<>()); + requestMap.put(infoRequestName, new Entry(responseCode, MiscUtils.getTime())); + log.put(address, requestMap); + } + + private static ConnectionLog getInstance() { + return ConnectionSystem.getInstance().getConnectionLog(); + } + + public Map> getLog() { + return log; + } + + public static class Entry implements Comparable { + + private final int responseCode; + private final long timeSent; + + public Entry(int responseCode, long timeSent) { + this.responseCode = responseCode; + this.timeSent = timeSent; + } + + public int getResponseCode() { + return responseCode; + } + + public long getTimeSent() { + return timeSent; + } + + /** + * Most recent first. + * + * @param o + * @return + */ + @Override + public int compareTo(Entry o) { + return -Long.compare(this.timeSent, o.timeSent); + } + } + +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionOut.java b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionOut.java new file mode 100644 index 000000000..0bb6ad728 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionOut.java @@ -0,0 +1,176 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.connection; + +import com.djrapitops.plan.api.exceptions.connection.*; +import com.djrapitops.plan.system.info.request.InfoRequest; +import com.djrapitops.plan.system.info.request.InfoRequestWithVariables; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +import javax.net.ssl.*; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.Map; +import java.util.UUID; + +/** + * Represents an outbound action request to another Plan server. + * + * @author Rsl1122 + */ +public class ConnectionOut { + + private static final TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { + //No need to implement. + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { + //No need to implement. + } + } + }; + + private final Server toServer; + private final UUID serverUUID; + private final InfoRequest infoRequest; + + /** + * Constructor. + * + * @param toServer Full address to another Plan webserver. (http://something:port) + * @param serverUUID UUID of server this outbound connection. + * @param infoRequest Type of the action this connection wants to be performed. + */ + public ConnectionOut(Server toServer, UUID serverUUID, InfoRequest infoRequest) { + Verify.nullCheck(toServer, serverUUID, infoRequest); + this.toServer = toServer; + this.serverUUID = serverUUID; + this.infoRequest = infoRequest; + } + + public void sendRequest() throws WebException { + String address = toServer.getWebAddress(); + + HttpURLConnection connection = null; + try { + URL url = new URL(address + "/info/" + infoRequest.getClass().getSimpleName().toLowerCase()); + connection = (HttpURLConnection) url.openConnection(); + if (address.startsWith("https")) { + HttpsURLConnection httpsConn = (HttpsURLConnection) connection; + + // Disables unsigned certificate & hostname check, because we're trusting the user given certificate. + + // This allows https connections internally to local ports. + httpsConn.setHostnameVerifier((hostname, session) -> true); + + // This allows connecting to connections with invalid certificate + // Drawback: MitM attack possible between connections to servers that are not local. + // Scope: InfoRequest transmissions + // Risk: Attacker sets up a server between Bungee and Bukkit WebServers + // - Negotiates SSL Handshake with both servers + // - Receives the SSL encrypted data, but decrypts it in the MitM server. + // -> Access to valid ServerUUID for POST requests + // -> Access to sending Html to the (Bungee) WebServer + // Mitigating factors: + // - If Server owner has access to all routing done on the domain (IP/Address) + // - If Direct IPs are used to transfer between servers + // Alternative solution: InfoRequests run only on HTTP, HTTP can be read during transmission, + // would require running two WebServers when HTTPS is used. + httpsConn.setSSLSocketFactory(getRelaxedSocketFactory()); + } + connection.setConnectTimeout(10000); + connection.setDoOutput(true); + connection.setInstanceFollowRedirects(false); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + + connection.setRequestProperty("charset", "UTF-8"); + + String parameters = parseVariables(); + infoRequest.placeDataToDatabase(); + + connection.setRequestProperty("Content-Length", Integer.toString(parameters.length())); + + byte[] toSend = parameters.getBytes(); + + connection.setUseCaches(false); + Log.debug("ConnectionOut: " + infoRequest.getClass().getSimpleName() + " to " + address); + try (DataOutputStream out = new DataOutputStream(connection.getOutputStream())) { + out.write(toSend); + } + + int responseCode = connection.getResponseCode(); + + ConnectionLog.logConnectionTo(toServer, infoRequest, responseCode); + switch (responseCode) { + case 200: + return; + case 400: + throw new BadRequestException("Bad Request: " + url.toString() + " | " + parameters); + case 403: + throw new ForbiddenException(url.toString() + " returned 403 | " + parameters); + case 404: + throw new NotFoundException(url.toString() + " returned a 404, ensure that your server is connected to an up to date Plan server."); + case 412: + throw new UnauthorizedServerException(url.toString() + " reported that it does not recognize this server. Make sure '/plan m setup' was successful."); + case 500: + throw new InternalErrorException(); + default: + throw new WebException(url.toString() + "| Wrong response code " + responseCode); + } + } catch (SocketTimeoutException e) { + ConnectionLog.logConnectionTo(toServer, infoRequest, 0); + throw new ConnectionFailException("Connection timed out after 10 seconds.", e); + } catch (NoSuchAlgorithmException | KeyManagementException | IOException e) { + if (Settings.DEV_MODE.isTrue()) { + Log.warn("THIS ERROR IS ONLY LOGGED IN DEV MODE:"); + Log.toLog(this.getClass(), e); + } + ConnectionLog.logConnectionTo(toServer, infoRequest, -1); + throw new ConnectionFailException("Connection failed to address: " + address + "
Make sure the server is online.", e); + } finally { + if (connection != null) { + connection.disconnect(); + } + } + } + + private String parseVariables() { + StringBuilder parameters = new StringBuilder("sender=" + serverUUID + ";&variable;" + + "type=" + infoRequest.getClass().getSimpleName()); + + if (infoRequest instanceof InfoRequestWithVariables) { + Map variables = ((InfoRequestWithVariables) infoRequest).getVariables(); + for (Map.Entry entry : variables.entrySet()) { + parameters.append(";&variable;").append(entry.getKey()).append("=").append(entry.getValue()); + } + } + + return parameters.toString(); + } + + private SSLSocketFactory getRelaxedSocketFactory() throws NoSuchAlgorithmException, KeyManagementException { + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + return sc.getSocketFactory(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionSystem.java new file mode 100644 index 000000000..0cdf67589 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/ConnectionSystem.java @@ -0,0 +1,133 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.connection; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.connection.NoServersException; +import com.djrapitops.plan.api.exceptions.connection.UnsupportedTransferDatabaseException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.info.request.*; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plugin.api.Check; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.*; + +/** + * ConnectionSystem manages out- and inbound InfoRequest connections. + *

+ * It decides what server to use for each request. + * + * @author Rsl1122 + */ +public abstract class ConnectionSystem implements SubSystem { + + protected final ConnectionLog connectionLog; + protected final Map dataRequests; + protected Map bukkitServers; + private boolean setupAllowed; + + public ConnectionSystem() { + setupAllowed = false; + bukkitServers = new HashMap<>(); + dataRequests = loadDataRequests(); + connectionLog = new ConnectionLog(); + } + + public static ConnectionSystem getInstance() { + ConnectionSystem connectionSystem = InfoSystem.getInstance().getConnectionSystem(); + Verify.nullCheck(connectionSystem, () -> new IllegalStateException("Connection System was not initialized")); + return connectionSystem; + } + + public static boolean isSetupAllowed() { + return getInstance().setupAllowed; + } + + public InfoRequest getInfoRequest(String name) { + return dataRequests.get(name.toLowerCase()); + } + + public void setSetupAllowed(boolean setupAllowed) { + this.setupAllowed = setupAllowed; + } + + private void putRequest(Map requests, InfoRequest request) { + requests.put(request.getClass().getSimpleName().toLowerCase(), request); + } + + protected abstract Server selectServerForRequest(InfoRequest infoRequest) throws NoServersException; + + public static String getAddress() { + return getInstance().getMainAddress(); + } + + public void sendInfoRequest(InfoRequest infoRequest) throws WebException { + Server server = selectServerForRequest(infoRequest); + sendInfoRequest(infoRequest, server); + } + + public void sendInfoRequest(InfoRequest infoRequest, Server toServer) throws WebException { + if (ServerInfo.getServerUUID().equals(toServer.getUuid())) { + InfoSystem.getInstance().runLocally(infoRequest); + } else { + new ConnectionOut(toServer, ServerInfo.getServerUUID(), infoRequest).sendRequest(); + } + } + + public ConnectionLog getConnectionLog() { + return connectionLog; + } + + public abstract boolean isServerAvailable(); + + public abstract String getMainAddress(); + + public abstract void sendWideInfoRequest(WideRequest infoRequest) throws NoServersException; + + protected Optional getServerWherePlayerIsOnline(GenerateInspectPageRequest infoRequest) { + UUID playerUUID = infoRequest.getPlayerUUID(); + + if (Check.isBukkitAvailable() && Plan.getInstance().getServer().getPlayer(playerUUID) != null) { + return Optional.of(ServerInfo.getServerUUID()); + } + + try { + return Database.getActive().transfer().getServerPlayerIsOnlineOn(playerUUID); + } catch (UnsupportedTransferDatabaseException e) { + /* Do nothing */ + } catch (DBException e) { + Log.toLog(this.getClass(), e); + } + return Optional.empty(); + } + + private Map loadDataRequests() { + Map requests = new HashMap<>(); + putRequest(requests, CacheInspectPageRequest.createHandler()); + putRequest(requests, CacheInspectPluginsTabRequest.createHandler()); + putRequest(requests, CacheAnalysisPageRequest.createHandler()); + putRequest(requests, CacheNetworkPageContentRequest.createHandler()); + + putRequest(requests, GenerateAnalysisPageRequest.createHandler()); + putRequest(requests, GenerateInspectPageRequest.createHandler()); + putRequest(requests, GenerateInspectPluginsTabRequest.createHandler()); + putRequest(requests, GenerateNetworkPageContentRequest.createHandler()); + + putRequest(requests, SaveDBSettingsRequest.createHandler()); + putRequest(requests, SendDBSettingsRequest.createHandler()); + return requests; + } + + public List getBukkitServers() { + return new ArrayList<>(bukkitServers.values()); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/connection/InfoRequestPageHandler.java b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/InfoRequestPageHandler.java new file mode 100644 index 000000000..e08bd39de --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/InfoRequestPageHandler.java @@ -0,0 +1,73 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.connection; + +import com.djrapitops.plan.api.exceptions.connection.*; +import com.djrapitops.plan.system.info.request.InfoRequest; +import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.pages.PageHandler; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.api.BadRequestResponse; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.List; + +/** + * PageHandler for /info/requestclassname pages. + *

+ * Used for answering info requests by other servers. + *

+ * requestclassname should be replaced with lowercase version of {@code Class.getSimpleName()} + * + * @author Rsl1122 + */ +public class InfoRequestPageHandler extends PageHandler { + + @Override + public Response getResponse(Request request, List target) throws WebException { + int responseCode = 200; + + try { + if (target.isEmpty()) { + return DefaultResponses.NOT_FOUND.get(); + } + + if (!request.getRequestMethod().equals("POST")) { + return new BadRequestResponse("POST should be used for Info calls."); + } + + String requestName = target.get(0); + InfoRequest infoRequest = ConnectionSystem.getInstance().getInfoRequest(requestName); + + Verify.nullCheck(infoRequest, () -> new NotFoundException("Info Request has not been registered.")); + + return new ConnectionIn(request, infoRequest).handleRequest(); + } catch (WebException e) { + responseCode = getResponseCodeFor(e); + throw e; + } finally { + ConnectionLog.logConnectionFrom(request.getRemoteAddress(), request.getTarget(), responseCode); + } + } + + private int getResponseCodeFor(WebException e) { + if (e instanceof BadRequestException) { + return 400; + } else if (e instanceof ForbiddenException) { + return 403; + } else if (e instanceof NotFoundException) { + return 404; + } else if (e instanceof UnauthorizedServerException) { + return 412; + } else if (e instanceof InternalErrorException) { + return 500; + } else if (e instanceof ConnectionFailException) { + return -1; + } else { + return 0; + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/connection/WebExceptionLogger.java b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/WebExceptionLogger.java new file mode 100644 index 000000000..13297b463 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/connection/WebExceptionLogger.java @@ -0,0 +1,71 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.connection; + +import com.djrapitops.plan.api.exceptions.connection.*; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Class that decides what to do with WebExceptions. + * + * @author Rsl1122 + */ +public class WebExceptionLogger { + + public static void logIfOccurs(Class c, ExceptionLoggingAction action) { + try { + action.performAction(); + } catch (ConnectionFailException e) { + if (shouldLog(e)) { + Log.warn(e.getMessage()); + } + } catch (UnsupportedTransferDatabaseException | UnauthorizedServerException + | NotFoundException | NoServersException e) { + Log.warn(e.getMessage()); + } catch (WebException e) { + Log.toLog(c, e); + } + } + + private static boolean shouldLog(ConnectionFailException e) { + String address = getAddress(e); + if (address == null) { + return true; + } + Map> logEntries = ConnectionLog.getLogEntries(); + Map entries = logEntries.get("Out: " + address); + if (entries != null) { + List connections = new ArrayList<>(entries.values()); + Collections.sort(connections); + return connections.isEmpty() || connections.get(0).getResponseCode() != -1; + } + return true; + } + + private static String getAddress(ConnectionFailException e) { + if (e.getMessage().contains("to address")) { + String[] split = e.getMessage().split("to address: "); + if (split.length == 2) { + String[] split2 = split[1].split("
"); + if (split2.length == 2) { + return split2[0]; + } + } + } + return null; + } + + public interface ExceptionLoggingAction { + + void performAction() throws WebException; + + } + +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheAnalysisPageRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheAnalysisPageRequest.java new file mode 100644 index 000000000..89a126f78 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheAnalysisPageRequest.java @@ -0,0 +1,93 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import com.djrapitops.plan.api.exceptions.connection.TransferDatabaseException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.pages.AnalysisPageResponse; +import com.djrapitops.plan.utilities.Base64Util; +import com.djrapitops.plan.utilities.file.export.HtmlExport; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.Map; +import java.util.UUID; + +/** + * InfoRequest used to place HTML of a server to ResponseCache. + * + * @author Rsl1122 + */ +public class CacheAnalysisPageRequest implements CacheRequest { + + private final UUID serverUUID; + private final String html; + + private CacheAnalysisPageRequest() { + serverUUID = null; + html = null; + } + + public CacheAnalysisPageRequest(UUID serverUUID, String html) { + Verify.nullCheck(serverUUID, html); + this.serverUUID = serverUUID; + this.html = html; + } + + public static CacheAnalysisPageRequest createHandler() { + return new CacheAnalysisPageRequest(); + } + + @Override + public void placeDataToDatabase() throws WebException { + Verify.nullCheck(serverUUID, html); + + String encodedHtml = Base64Util.encode(html); + try { + Database.getActive().transfer().storeServerHtml(serverUUID, encodedHtml); + } catch (DBException e) { + throw new TransferDatabaseException(e); + } + } + + @Override + public Response handleRequest(Map variables) throws WebException { + // Available variables: sender + + try { + Map pages = Database.getActive().transfer().getEncodedServerHtml(); + + boolean export = Settings.ANALYSIS_EXPORT.isTrue(); + for (Map.Entry entry : pages.entrySet()) { + UUID serverUUID = entry.getKey(); + String html = Base64Util.decode(entry.getValue()); + + cache(export, serverUUID, html); + } + } catch (DBException e) { + throw new TransferDatabaseException(e); + } + return DefaultResponses.SUCCESS.get(); + } + + private void cache(boolean export, UUID serverUUID, String html) { + ResponseCache.cacheResponse(PageId.SERVER.of(serverUUID), () -> new AnalysisPageResponse(html)); + if (export) { + Processor.queue(() -> HtmlExport.exportServer(serverUUID)); + } + } + + @Override + public void runLocally() { + cache(Settings.ANALYSIS_EXPORT.isTrue(), serverUUID, html); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheInspectPageRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheInspectPageRequest.java new file mode 100644 index 000000000..e6202cfb3 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheInspectPageRequest.java @@ -0,0 +1,98 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import com.djrapitops.plan.api.exceptions.connection.TransferDatabaseException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.pages.InspectPageResponse; +import com.djrapitops.plan.utilities.Base64Util; +import com.djrapitops.plan.utilities.file.export.HtmlExport; +import com.djrapitops.plugin.utilities.Verify; +import org.apache.commons.lang3.text.StrSubstitutor; + +import java.util.Collections; +import java.util.Map; +import java.util.UUID; + +/** + * InfoRequest used to place HTML of a player to ResponseCache. + * + * @author Rsl1122 + */ +public class CacheInspectPageRequest implements CacheRequest { + + private final UUID player; + private final String html; + + private CacheInspectPageRequest() { + player = null; + html = null; + } + + public CacheInspectPageRequest(UUID player, String html) { + Verify.nullCheck(player, html); + this.player = player; + this.html = html; + } + + public static CacheInspectPageRequest createHandler() { + return new CacheInspectPageRequest(); + } + + @Override + public void placeDataToDatabase() throws WebException { + Verify.nullCheck(player, html); + + String encodedHtml = Base64Util.encode(html); + try { + Database.getActive().transfer().storePlayerHtml(player, encodedHtml); + } catch (DBException e) { + throw new TransferDatabaseException(e); + } + } + + @Override + public Response handleRequest(Map variables) throws WebException { + // Available variables: sender + + try { + Map pages = Database.getActive().transfer().getEncodedPlayerHtml(); + + boolean export = Settings.ANALYSIS_EXPORT.isTrue(); + for (Map.Entry entry : pages.entrySet()) { + UUID uuid = entry.getKey(); + String html = Base64Util.decode(entry.getValue()); + + Map replace = Collections.singletonMap("networkName", ServerInfo.getServerName()); + + cache(export, uuid, StrSubstitutor.replace(html, replace)); + } + } catch (DBException e) { + throw new TransferDatabaseException(e); + } + return DefaultResponses.SUCCESS.get(); + } + + private void cache(boolean export, UUID uuid, String html) { + ResponseCache.cacheResponse(PageId.PLAYER.of(uuid), () -> new InspectPageResponse(uuid, html)); + if (export) { + Processor.queue(() -> HtmlExport.exportPlayer(uuid)); + } + } + + @Override + public void runLocally() { + cache(Settings.ANALYSIS_EXPORT.isTrue(), player, html); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheInspectPluginsTabRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheInspectPluginsTabRequest.java new file mode 100644 index 000000000..4403f0e95 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheInspectPluginsTabRequest.java @@ -0,0 +1,104 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import com.djrapitops.plan.api.exceptions.connection.BadRequestException; +import com.djrapitops.plan.api.exceptions.connection.TransferDatabaseException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.pages.parts.InspectPagePluginsContent; +import com.djrapitops.plan.utilities.Base64Util; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.Map; +import java.util.UUID; + +/** + * InfoRequest used to place HTML of player's Plugins Tab to ResponseCache. + * + * @author Rsl1122 + */ +public class CacheInspectPluginsTabRequest extends InfoRequestWithVariables implements CacheRequest { + + private static final String SPLIT = "AASPLITAA"; + + private final UUID player; + private final String nav; + private final String html; + + private CacheInspectPluginsTabRequest() { + player = null; + nav = null; + html = null; + } + + public CacheInspectPluginsTabRequest(UUID player, String nav, String html) { + Verify.nullCheck(player, nav); + variables.put("player", player.toString()); + this.player = player; + this.nav = nav; + this.html = html; + } + + public static CacheInspectPluginsTabRequest createHandler() { + return new CacheInspectPluginsTabRequest(); + } + + @Override + public void placeDataToDatabase() throws WebException { + Verify.nullCheck(player, nav); + + String encodedHtml = Base64Util.encode(nav + SPLIT + html); + try { + Database.getActive().transfer().storePlayerPluginsTab(player, encodedHtml); + } catch (DBException e) { + throw new TransferDatabaseException(e); + } + } + + @Override + public Response handleRequest(Map variables) throws WebException { + // Available variables: sender, player + + String player = variables.get("player"); + Verify.nullCheck(player, () -> new BadRequestException("Player UUID 'player' variable not supplied in the request.")); + + UUID uuid = UUID.fromString(player); + + try { + InspectPagePluginsContent pluginsTab = getPluginsTab(uuid); + + Map pages = Database.getActive().transfer().getEncodedPlayerPluginsTabs(uuid); + + for (Map.Entry entry : pages.entrySet()) { + UUID serverUUID = entry.getKey(); + String[] navAndHtml = Base64Util.decode(entry.getValue()).split(SPLIT); + + if (navAndHtml.length <= 1) { + continue; + } + pluginsTab.addTab(serverUUID, navAndHtml[0], navAndHtml[1]); + } + } catch (DBException e) { + throw new TransferDatabaseException(e); + } + return DefaultResponses.SUCCESS.get(); + } + + private InspectPagePluginsContent getPluginsTab(UUID uuid) { + return (InspectPagePluginsContent) ResponseCache.loadResponse(PageId.PLAYER_PLUGINS_TAB.of(uuid), InspectPagePluginsContent::new); + } + + @Override + public void runLocally() { + getPluginsTab(player).addTab(ServerInfo.getServerUUID(), nav, html); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheNetworkPageContentRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheNetworkPageContentRequest.java new file mode 100644 index 000000000..9711387ab --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheNetworkPageContentRequest.java @@ -0,0 +1,95 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import com.djrapitops.plan.api.exceptions.connection.TransferDatabaseException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.pages.parts.NetworkPageContent; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.Map; +import java.util.UUID; + +/** + * InfoRequest for caching Network page parts to ResponseCache of receiving server. + *

+ * SHOULD NOT BE SENT TO BUKKIT + * + * @author Rsl1122 + */ +public class CacheNetworkPageContentRequest implements CacheRequest { + + private final UUID serverUUID; + private final String html; + + public CacheNetworkPageContentRequest(UUID serverUUID, String html) { + Verify.nullCheck(serverUUID, html); + this.serverUUID = serverUUID; + this.html = html; + } + + private CacheNetworkPageContentRequest() { + serverUUID = null; + html = null; + } + + @Override + public void placeDataToDatabase() throws WebException { + try { + Database.getActive().transfer().storeNetworkPageContent(serverUUID, html); + } catch (DBException e) { + throw new TransferDatabaseException(e); + } + } + + @Override + public Response handleRequest(Map variables) throws WebException { + // Available variables: sender + + Map networkPageHtml; + Map serverNames; + try { + Database database = Database.getActive(); + networkPageHtml = database.transfer().getEncodedNetworkPageContent(); + serverNames = database.fetch().getServerNames(); + } catch (DBException e) { + throw new TransferDatabaseException(e); + } + + for (Map.Entry entry : networkPageHtml.entrySet()) { + UUID serverUUID = entry.getKey(); + String serverName = serverNames.getOrDefault(serverUUID, "Unknown"); + String html = entry.getValue(); + + NetworkPageContent networkPage = getNetworkPageContent(); + networkPage.addElement(serverName, html); + } + + InfoSystem.getInstance().updateNetworkPage(); + + return DefaultResponses.SUCCESS.get(); + } + + private NetworkPageContent getNetworkPageContent() { + return (NetworkPageContent) ResponseCache.loadResponse(PageId.NETWORK_CONTENT.id(), NetworkPageContent::new); + } + + @Override + public void runLocally() { + getNetworkPageContent().addElement(ServerInfo.getServerName(), html); + } + + public static CacheNetworkPageContentRequest createHandler() { + return new CacheNetworkPageContentRequest(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheRequest.java new file mode 100644 index 000000000..be2215dbc --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/CacheRequest.java @@ -0,0 +1,13 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +/** + * Interface for all InfoRequests that cache something into RequestCache. + * + * @author Rsl1122 + */ +public interface CacheRequest extends InfoRequest { +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateAnalysisPageRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateAnalysisPageRequest.java new file mode 100644 index 000000000..8790c3a18 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateAnalysisPageRequest.java @@ -0,0 +1,105 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import com.djrapitops.plan.api.exceptions.connection.BadRequestException; +import com.djrapitops.plan.api.exceptions.connection.InternalErrorException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.calculation.AnalysisData; +import com.djrapitops.plan.system.cache.DataCache; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.webserver.pages.parsing.AnalysisPage; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.utilities.analysis.Analysis; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.Map; +import java.util.UUID; + +/** + * InfoRequest to generate Analysis page HTML at the receiving end. + * + * @author Rsl1122 + */ +public class GenerateAnalysisPageRequest extends InfoRequestWithVariables implements GenerateRequest { + + private final UUID serverUUID; + + public GenerateAnalysisPageRequest(UUID serverUUID) { + Verify.nullCheck(serverUUID); + this.serverUUID = serverUUID; + variables.put("server", serverUUID.toString()); + } + + private GenerateAnalysisPageRequest() { + serverUUID = null; + } + + @Override + public void placeDataToDatabase() { + // No data required in a Generate request + } + + @Override + public Response handleRequest(Map variables) throws WebException { + // Variables available: sender, server + + String server = variables.get("server"); + Verify.nullCheck(server, () -> new BadRequestException("Server UUID 'server' variable not supplied in the request.")); + + UUID serverUUID = UUID.fromString(server); + if (!ServerInfo.getServerUUID().equals(serverUUID)) { + throw new BadRequestException("Requested Analysis page from wrong server."); + } + + generateAndCache(serverUUID); + + return DefaultResponses.SUCCESS.get(); + } + + private void generateAndCache(UUID serverUUID) throws WebException { + InfoSystem infoSystem = InfoSystem.getInstance(); + infoSystem.sendRequest(new CacheAnalysisPageRequest(serverUUID, AnalysisPage.getRefreshingHtml())); + infoSystem.sendRequest(new CacheAnalysisPageRequest(serverUUID, analyseAndGetHtml())); + infoSystem.updateNetworkPage(); + } + + @Override + public void runLocally() throws WebException { + generateAndCache(serverUUID); + } + + private String analyseAndGetHtml() throws InternalErrorException { + try { + UUID serverUUID = ServerInfo.getServerUUID(); + Database db = Database.getActive(); + DataCache dataCache = DataCache.getInstance(); + + AnalysisData analysisData = Analysis.runAnalysisFor(serverUUID, db, dataCache); + return new AnalysisPage(analysisData).toHtml(); + } catch (DBException e) { + if (!e.getCause().getMessage().contains("Connection is closed")) { + Log.toLog(this.getClass(), e); + } + throw new InternalErrorException("Analysis failed due to exception", e); + } catch (Exception e) { + Log.toLog(this.getClass(), e); + throw new InternalErrorException("Analysis failed due to exception", e); + } + } + + public static GenerateAnalysisPageRequest createHandler() { + return new GenerateAnalysisPageRequest(); + } + + public UUID getServerUUID() { + return serverUUID; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateInspectPageRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateInspectPageRequest.java new file mode 100644 index 000000000..786b1bea0 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateInspectPageRequest.java @@ -0,0 +1,98 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import com.djrapitops.plan.api.exceptions.ParseException; +import com.djrapitops.plan.api.exceptions.connection.*; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.webserver.pages.parsing.InspectPage; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.errors.NotFoundResponse; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.Map; +import java.util.UUID; + +/** + * InfoRequest for Generating Inspect page on receiving WebServer. + * + * @author Rsl1122 + */ +public class GenerateInspectPageRequest extends InfoRequestWithVariables implements GenerateRequest, WideRequest { + + private final UUID playerUUID; + + private GenerateInspectPageRequest() { + playerUUID = null; + } + + public GenerateInspectPageRequest(UUID uuid) { + Verify.nullCheck(uuid); + playerUUID = uuid; + variables.put("player", uuid.toString()); + } + + public static GenerateInspectPageRequest createHandler() { + return new GenerateInspectPageRequest(); + } + + @Override + public void placeDataToDatabase() { + // No data required in a Generate request + } + + @Override + public Response handleRequest(Map variables) throws WebException { + // Available variables: sender, player + + String player = variables.get("player"); + Verify.nullCheck(player, () -> new BadRequestException("Player UUID 'player' variable not supplied in the request.")); + + UUID uuid = UUID.fromString(player); + + generateAndCache(uuid); + + return DefaultResponses.SUCCESS.get(); + } + + private void generateAndCache(UUID uuid) throws WebException { + String html; + try { + html = getHtml(uuid); + InfoSystem.getInstance().getConnectionSystem().sendWideInfoRequest(new GenerateInspectPluginsTabRequest(uuid)); + } catch (NotFoundException e) { + html = new NotFoundResponse(e.getMessage()).getContent(); + } + InfoSystem.getInstance().sendRequest(new CacheInspectPageRequest(uuid, html)); + } + + @Override + public void runLocally() throws WebException { + generateAndCache(playerUUID); + } + + private String getHtml(UUID uuid) throws WebException { + try { + + return new InspectPage(uuid).toHtml(); + + } catch (ParseException e) { + Throwable cause = e.getCause(); + if (cause instanceof DBException) { + throw new TransferDatabaseException((DBException) cause); + } else if (cause instanceof IllegalStateException && "Player profile was null!".equals(cause.getMessage())) { + throw new NotFoundException("Player has not played on this server."); + } else { + throw new WebFailException("Exception during HTML Parsing", cause); + } + } + } + + public UUID getPlayerUUID() { + return playerUUID; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateInspectPluginsTabRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateInspectPluginsTabRequest.java new file mode 100644 index 000000000..cc0533389 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateInspectPluginsTabRequest.java @@ -0,0 +1,73 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import com.djrapitops.plan.api.exceptions.connection.BadRequestException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.pages.parts.InspectPagePluginsContent; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.Map; +import java.util.UUID; + +/** + * InfoRequest for Generating Inspect page plugins tab on receiving WebServer. + * + * @author Rsl1122 + */ +public class GenerateInspectPluginsTabRequest extends InfoRequestWithVariables implements GenerateRequest, WideRequest { + + private final UUID playerUUID; + + private GenerateInspectPluginsTabRequest() { + playerUUID = null; + } + + public GenerateInspectPluginsTabRequest(UUID uuid) { + Verify.nullCheck(uuid); + playerUUID = uuid; + variables.put("player", uuid.toString()); + } + + public static GenerateInspectPluginsTabRequest createHandler() { + return new GenerateInspectPluginsTabRequest(); + } + + @Override + public void placeDataToDatabase() { + // No data required in a Generate request + } + + @Override + public Response handleRequest(Map variables) throws WebException { + // Available variables: sender, player + + String player = variables.get("player"); + Verify.nullCheck(player, () -> new BadRequestException("Player UUID 'player' variable not supplied in the request.")); + + UUID uuid = UUID.fromString(player); + + generateAndCache(uuid); + + return DefaultResponses.SUCCESS.get(); + } + + private void generateAndCache(UUID uuid) throws WebException { + String[] navAndHtml = InspectPagePluginsContent.generateForThisServer(uuid).getContents(); + InfoSystem.getInstance().sendRequest(new CacheInspectPluginsTabRequest(uuid, navAndHtml[0], navAndHtml[1])); + } + + @Override + public void runLocally() throws WebException { + generateAndCache(playerUUID); + } + + public UUID getPlayerUUID() { + return playerUUID; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateNetworkPageContentRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateNetworkPageContentRequest.java new file mode 100644 index 000000000..33d83d865 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateNetworkPageContentRequest.java @@ -0,0 +1,40 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; + +import java.util.Map; + +/** + * InfoRequest for generating network page content of a Bukkit server. + * + * @author Rsl1122 + */ +public class GenerateNetworkPageContentRequest implements WideRequest, GenerateRequest { + + public static GenerateNetworkPageContentRequest createHandler() { + return new GenerateNetworkPageContentRequest(); + } + + @Override + public void placeDataToDatabase() { + /* No Data needed on a GenerateRequest.*/ + } + + @Override + public Response handleRequest(Map variables) throws WebException { + InfoSystem.getInstance().updateNetworkPage(); + return DefaultResponses.SUCCESS.get(); + } + + @Override + public void runLocally() throws WebException { + InfoSystem.getInstance().updateNetworkPage(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateRequest.java new file mode 100644 index 000000000..4221ccf50 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/GenerateRequest.java @@ -0,0 +1,13 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +/** + * Interface for all InfoRequests that generate something. + * + * @author Rsl1122 + */ +public interface GenerateRequest extends InfoRequest { +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/InfoRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/InfoRequest.java new file mode 100644 index 000000000..6484c7000 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/InfoRequest.java @@ -0,0 +1,25 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.webserver.response.Response; + +import java.util.Map; + +/** + * Represents a request that Plan servers can send each other. + * + * @author Rsl1122 + */ +public interface InfoRequest { + + void placeDataToDatabase() throws WebException; + + Response handleRequest(Map variables) throws WebException; + + void runLocally() throws WebException; + +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/InfoRequestWithVariables.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/InfoRequestWithVariables.java new file mode 100644 index 000000000..752ce9092 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/InfoRequestWithVariables.java @@ -0,0 +1,28 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import java.util.HashMap; +import java.util.Map; + +/** + * Abstract InfoRequest that contains variables in request body. + *

+ * Used to send request differently. + * + * @author Rsl1122 + */ +public abstract class InfoRequestWithVariables implements InfoRequest { + + protected final Map variables; + + public InfoRequestWithVariables() { + this.variables = new HashMap<>(); + } + + public Map getVariables() { + return variables; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/SaveDBSettingsRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/SaveDBSettingsRequest.java new file mode 100644 index 000000000..ef3b2a254 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/SaveDBSettingsRequest.java @@ -0,0 +1,103 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.connection.BadRequestException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.api.BadRequestResponse; +import com.djrapitops.plugin.api.Check; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.Map; + +/** + * InfoRequest for sending Database config settings to Bukkit servers. + * + * @author Rsl1122 + */ +public class SaveDBSettingsRequest extends InfoRequestWithVariables implements SetupRequest { + + public SaveDBSettingsRequest() { + variables.put("DB_TYPE", "mysql"); // Settings.DB_TYPE + variables.put("DB_HOST", Settings.DB_HOST.toString()); + variables.put("DB_USER", Settings.DB_USER.toString()); + variables.put("DB_PASS", Settings.DB_PASS.toString()); + variables.put("DB_DATABASE", Settings.DB_DATABASE.toString()); + variables.put("DB_PORT", Settings.DB_PORT.toString()); + } + + /** + * Private constructor for creating a handler. + */ + private SaveDBSettingsRequest(boolean b) { + } + + public static SaveDBSettingsRequest createHandler() { + return new SaveDBSettingsRequest(true); + } + + @Override + public void placeDataToDatabase() { + /* Not necessary */ + } + + @Override + public void runLocally() { + /* Won't be run */ + } + + @Override + public Response handleRequest(Map variables) throws WebException { + if (Check.isBungeeAvailable()) { + return new BadRequestResponse("Not supposed to be called on a Bungee server"); + } + if (Settings.BUNGEE_COPY_CONFIG.isFalse() || Settings.BUNGEE_OVERRIDE_STANDALONE_MODE.isTrue()) { + return new BadRequestResponse("Bungee config settings overridden on this server."); + } + + try { + setSettings(variables); + Log.info("----------------------------------"); + Log.info("The Received Bungee Database Settings, restarting Plan.."); + Log.info("----------------------------------"); + return DefaultResponses.SUCCESS.get(); + } finally { + Plan.getInstance().reloadPlugin(true); + } + } + + private void setSettings(Map variables) throws BadRequestException { + String type = variables.get("DB_TYPE"); + String host = variables.get("DB_HOST"); + String user = variables.get("DB_USER"); + String pass = variables.get("DB_PASS"); + String database = variables.get("DB_DATABASE"); + String portS = variables.get("DB_PORT"); + + Verify.nullCheck(type, () -> new BadRequestException("DB_TYPE not specified in the request.")); + Verify.nullCheck(host, () -> new BadRequestException("DB_HOST not specified in the request.")); + Verify.nullCheck(user, () -> new BadRequestException("DB_USER not specified in the request.")); + Verify.nullCheck(pass, () -> new BadRequestException("DB_PASS not specified in the request.")); + Verify.nullCheck(database, () -> new BadRequestException("DB_DATABASE not specified in the request.")); + Verify.nullCheck(portS, () -> new BadRequestException("DB_PORT not specified in the request.")); + + try { + Settings.DB_PORT.set(Integer.valueOf(portS)); + } catch (NumberFormatException e) { + throw new BadRequestException("DB_PORT was not a number."); + } + Settings.DB_TYPE.set(type); + Settings.DB_HOST.set(host); + Settings.DB_USER.set(user); + Settings.DB_PASS.set(pass); + Settings.DB_DATABASE.set(database); + Settings.save(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/SendDBSettingsRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/SendDBSettingsRequest.java new file mode 100644 index 000000000..8097da8a0 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/SendDBSettingsRequest.java @@ -0,0 +1,99 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +import com.djrapitops.plan.api.exceptions.connection.BadRequestException; +import com.djrapitops.plan.api.exceptions.connection.ConnectionFailException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.api.BadRequestResponse; +import com.djrapitops.plugin.api.Check; +import com.djrapitops.plugin.utilities.Verify; + +import java.net.SocketException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * InfoRequest used for requesting DB settings from Bungee. + * + * @author Rsl1122 + */ +public class SendDBSettingsRequest extends InfoRequestWithVariables implements SetupRequest { + + public SendDBSettingsRequest(String webServerAddress) { + Verify.nullCheck(webServerAddress, () -> new IllegalArgumentException("webServerAddress can not be null.")); + + variables.put("address", webServerAddress); + variables.put("WebServerPort", Integer.toString(Settings.WEBSERVER_PORT.getNumber())); + variables.put("ServerName", Settings.SERVER_NAME.toString().replaceAll("[^a-zA-Z0-9_\\s]", "_")); + variables.put("ThemeBase", Settings.THEME_BASE.toString()); + } + + private SendDBSettingsRequest() { + } + + public static SendDBSettingsRequest createHandler() { + return new SendDBSettingsRequest(); + } + + @Override + public void placeDataToDatabase() { + /* Not necessary */ + } + + @Override + public void runLocally() { + /* Won't be run */ + } + + @Override + public Response handleRequest(Map variables) throws WebException { + // Available variables: sender, address + if (Check.isBukkitAvailable()) { + return new BadRequestResponse("Not supposed to be called on a Bukkit server"); + } + + String address = variables.get("address"); + Verify.nullCheck(address, () -> new BadRequestException("WebServer Address ('address') not specified in the request.")); + + String webServerPortS = variables.get("WebServerPort"); + String serverName = variables.get("ServerName"); + String themeBase = variables.get("ThemeBase"); + Verify.nullCheck(webServerPortS, () -> new BadRequestException("WebServer Port ('WebServerPort') not specified in the request.")); + Verify.nullCheck(serverName, () -> new BadRequestException("Server Name ('ServerName') not specified in the request.")); + Verify.nullCheck(themeBase, () -> new BadRequestException("Theme Base ('ThemeBase') not specified in the request.")); + + UUID serverUUID = UUID.fromString(variables.get("sender")); + setOriginalSettings(serverUUID, webServerPortS, serverName, themeBase); + + Server bukkit = new Server(-1, serverUUID, serverName, address, -1); + + try { + InfoSystem.getInstance().getConnectionSystem().sendInfoRequest(new SaveDBSettingsRequest(), bukkit); + } catch (ConnectionFailException e) { + Throwable cause = e.getCause(); + if (!(cause instanceof SocketException) || !cause.getMessage().contains("Unexpected end of file from server")) { + throw e; + } + } + + return DefaultResponses.SUCCESS.get(); + } + + private void setOriginalSettings(UUID serverUUID, String webServerPortS, String serverName, String themeBase) { + Map settings = new HashMap<>(); + int webServerPort = Integer.parseInt(webServerPortS); + settings.put("WebServerPort", webServerPort); + settings.put("ServerName", serverName); + settings.put("ThemeBase", themeBase); + Settings.serverSpecific().addOriginalBukkitSettings(serverUUID, settings); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/data/HasDate.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/SetupRequest.java similarity index 54% rename from Plan/src/main/java/com/djrapitops/plan/data/HasDate.java rename to Plan/src/main/java/com/djrapitops/plan/system/info/request/SetupRequest.java index 5c4b03c63..f21e38fd2 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/HasDate.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/SetupRequest.java @@ -1,16 +1,14 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.data; +package com.djrapitops.plan.system.info.request; /** - * //TODO Class Javadoc Comment + * InfoRequest that is related to initial communications. * * @author Rsl1122 */ -public interface HasDate { +public interface SetupRequest extends InfoRequest { - long getDate(); - -} +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/request/WideRequest.java b/Plan/src/main/java/com/djrapitops/plan/system/info/request/WideRequest.java new file mode 100644 index 000000000..769950995 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/request/WideRequest.java @@ -0,0 +1,13 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.request; + +/** + * InfoRequest that should be relayed to all Bukkit servers. + * + * @author Rsl1122 + */ +public interface WideRequest extends InfoRequest { +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/server/BukkitServerInfo.java b/Plan/src/main/java/com/djrapitops/plan/system/info/server/BukkitServerInfo.java new file mode 100644 index 000000000..36111c66d --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/server/BukkitServerInfo.java @@ -0,0 +1,118 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.server; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.file.FileSystem; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.webserver.WebServerSystem; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.io.IOException; +import java.util.Optional; +import java.util.UUID; + +/** + * Manages the Server UUID for Bukkit servers. + *

+ * Also manages Server ID required for MySQL database independence. + * + * @author Rsl1122 + */ +public class BukkitServerInfo extends ServerInfo { + + private ServerInfoFile serverInfoFile; + private Database database; + + public BukkitServerInfo(Plan plugin) { + serverProperties = new ServerProperties(plugin.getServer()); + } + + @Override + public void enable() throws EnableException { + database = Database.getActive(); + + try { + serverInfoFile = new ServerInfoFile(FileSystem.getDataFolder()); + } catch (IOException e) { + throw new EnableException("Failed to read ServerInfoFile.yml", e); + } + super.enable(); + } + + @Override + protected Server loadServerInfo() throws EnableException { + Optional serverUUID = serverInfoFile.getUUID(); + try { + return serverUUID.isPresent() ? updateDbInfo(serverUUID.get()) : registerServer(); + } catch (DBException e) { + throw new EnableException("Failed to read Server information from Database", e); + } catch (IOException e) { + throw new EnableException("Failed to read ServerInfoFile.yml", e); + } + } + + private Server updateDbInfo(UUID serverUUID) throws IOException, DBException { + Optional serverID = database.fetch().getServerID(serverUUID); + if (!serverID.isPresent()) { + return registerServer(serverUUID); + } + String name = Settings.SERVER_NAME.toString().replaceAll("[^a-zA-Z0-9_\\s]", "_"); + String webAddress = WebServerSystem.getInstance().getWebServer().getAccessAddress(); + if ("plan".equalsIgnoreCase(name)) { + name = "Server " + serverID.get(); + } + int maxPlayers = serverProperties.getMaxPlayers(); + + Server server = new Server(serverID.get(), serverUUID, name, webAddress, maxPlayers); + database.save().serverInfoForThisServer(server); + return server; + } + + private Server registerServer() throws DBException, IOException { + return registerServer(generateNewUUID(serverProperties)); + } + + private Server registerServer(UUID serverUUID) throws DBException, IOException { + String webAddress = WebServerSystem.getInstance().getWebServer().getAccessAddress(); + String name = Settings.SERVER_NAME.toString().replaceAll("[^a-zA-Z0-9_\\s]", "_"); + int maxPlayers = ServerInfo.getServerProperties().getMaxPlayers(); + + Server server = new Server(-1, serverUUID, name, webAddress, maxPlayers); + database.save().serverInfoForThisServer(server); + + Optional serverID = database.fetch().getServerID(serverUUID); + if (!serverID.isPresent()) { + throw new IllegalStateException("Failed to Register Server (ID not found)"); + } + + int id = serverID.get(); + server.setId(id); + + serverInfoFile.saveServerUUID(serverUUID); + return server; + } + + private UUID generateNewUUID(ServerProperties serverProperties) { + String seed = serverProperties.getServerId() + serverProperties.getName() + serverProperties.getIp() + serverProperties.getPort() + serverProperties.getVersion() + serverProperties.getImplVersion(); + return UUID.nameUUIDFromBytes(seed.getBytes()); + } + + @Deprecated + public Optional getBungeeConnectionAddress() { + try { + Optional bungeeInfo = Database.getActive().fetch().getBungeeInformation(); + if (bungeeInfo.isPresent()) { + return Optional.of(bungeeInfo.get().getWebAddress()); + } + } catch (DBException e) { + Log.toLog(this.getClass(), e); + } + return Optional.empty(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/server/BungeeServerInfo.java b/Plan/src/main/java/com/djrapitops/plan/system/info/server/BungeeServerInfo.java new file mode 100644 index 000000000..f29091c83 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/server/BungeeServerInfo.java @@ -0,0 +1,83 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.server; + +import com.djrapitops.plan.PlanBungee; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.webserver.WebServerSystem; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.util.Optional; +import java.util.UUID; + +/** + * Manages Server information on the Bungee instance. + * + * @author Rsl1122 + */ +public class BungeeServerInfo extends ServerInfo { + + public BungeeServerInfo(PlanBungee plugin) { + serverProperties = new ServerProperties(plugin.getProxy()); + } + + @Override + public Server loadServerInfo() throws EnableException { + checkIfDefaultIP(); + + try { + Database db = Database.getActive(); + Optional bungeeInfo = db.fetch().getBungeeInformation(); + if (bungeeInfo.isPresent()) { + server = bungeeInfo.get(); + updateServerInfo(db); + } else { + server = registerBungeeInfo(db); + } + } catch (DBException e) { + throw new EnableException("Failed to read Database for Server"); + } + return server; + } + + private void updateServerInfo(Database db) throws DBException { + String accessAddress = WebServerSystem.getInstance().getWebServer().getAccessAddress(); + if (!accessAddress.equals(server.getWebAddress())) { + server.setWebAddress(accessAddress); + db.save().serverInfoForThisServer(server); + } + } + + private void checkIfDefaultIP() throws EnableException { + String ip = ServerInfo.getServerProperties().getIp(); + if ("0.0.0.0".equals(ip)) { + Log.error("IP setting still 0.0.0.0 - Configure AlternativeIP/IP that connects to the Proxy server."); + Log.info("Player Analytics partially enabled (Use /planbungee to reload config)"); + throw new EnableException("IP setting still 0.0.0.0 - Configure AlternativeIP/IP that connects to the Proxy server."); + } + } + + private Server registerBungeeInfo(Database db) throws DBException, EnableException { + ServerProperties properties = ServerInfo.getServerProperties(); + UUID serverUUID = generateNewUUID(properties); + String accessAddress = WebServerSystem.getInstance().getWebServer().getAccessAddress(); + + Server bungeeCord = new Server(-1, serverUUID, "BungeeCord", accessAddress, properties.getMaxPlayers()); + db.save().serverInfoForThisServer(bungeeCord); + + Optional bungeeInfo = db.fetch().getBungeeInformation(); + if (bungeeInfo.isPresent()) { + return bungeeInfo.get(); + } + throw new EnableException("BungeeCord registration failed (DB)"); + } + + private UUID generateNewUUID(ServerProperties properties) { + String seed = properties.getName() + properties.getIp() + properties.getPort() + properties.getVersion() + properties.getImplVersion(); + return UUID.nameUUIDFromBytes(seed.getBytes()); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/server/ServerInfo.java b/Plan/src/main/java/com/djrapitops/plan/system/info/server/Server.java similarity index 82% rename from Plan/src/main/java/com/djrapitops/plan/systems/info/server/ServerInfo.java rename to Plan/src/main/java/com/djrapitops/plan/system/info/server/Server.java index 59ca572e5..eea1046c6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/server/ServerInfo.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/server/Server.java @@ -1,8 +1,8 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.info.server; +package com.djrapitops.plan.system.info.server; import java.util.Objects; import java.util.UUID; @@ -12,14 +12,14 @@ import java.util.UUID; * * @author Rsl1122 */ -public class ServerInfo { +public class Server implements Comparable { private final UUID uuid; private int id; private String name; private String webAddress; - private int maxPlayers = -1; + private int maxPlayers; - public ServerInfo(int id, UUID uuid, String name, String webAddress, int maxPlayers) { + public Server(int id, UUID uuid, String name, String webAddress, int maxPlayers) { this.id = id; this.uuid = uuid; this.name = name; @@ -63,7 +63,7 @@ public class ServerInfo { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - ServerInfo that = (ServerInfo) o; + Server that = (Server) o; return id == that.id && Objects.equals(uuid, that.uuid) && Objects.equals(name, that.name) && @@ -77,7 +77,7 @@ public class ServerInfo { @Override public String toString() { - return "ServerInfo{" + + return "Server{" + "uuid=" + uuid + ", id=" + id + ", name='" + name + '\'' + @@ -85,4 +85,9 @@ public class ServerInfo { ", maxPlayers=" + maxPlayers + '}'; } + + @Override + public int compareTo(Server other) { + return Integer.compare(this.id, other.id); + } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/server/ServerInfo.java b/Plan/src/main/java/com/djrapitops/plan/system/info/server/ServerInfo.java new file mode 100644 index 000000000..28d996c23 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/server/ServerInfo.java @@ -0,0 +1,66 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.server; + +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.UUID; + +/** + * SubSystem for managing Server information. + *

+ * Most information is accessible via static methods. + * + * @author Rsl1122 + */ +public abstract class ServerInfo implements SubSystem { + + protected Server server; + protected ServerProperties serverProperties; + + public static ServerInfo getInstance() { + ServerInfo serverInfo = PlanSystem.getInstance().getServerInfo(); + Verify.nullCheck(serverInfo, () -> new IllegalStateException("ServerInfo was not initialized.")); + return serverInfo; + } + + public static Server getServer() { + return getInstance().server; + } + + public static ServerProperties getServerProperties() { + return getInstance().serverProperties; + } + + public static UUID getServerUUID() { + return getServer().getUuid(); + } + + public static String getServerName() { + return getServer().getName(); + } + + public static int getServerID() { + return getServer().getId(); + } + + @Override + public void enable() throws EnableException { + // ServerProperties are required when creating Server + Verify.nullCheck(serverProperties, () -> new IllegalStateException("Server Properties did not load!")); + server = loadServerInfo(); + Verify.nullCheck(server, () -> new IllegalStateException("Server information did not load!")); + } + + protected abstract Server loadServerInfo() throws EnableException; + + @Override + public void disable() { + + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/info/server/ServerInfoFile.java b/Plan/src/main/java/com/djrapitops/plan/system/info/server/ServerInfoFile.java new file mode 100644 index 000000000..b2dc6a15d --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/server/ServerInfoFile.java @@ -0,0 +1,44 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.info.server; + +import com.djrapitops.plan.system.file.FileSystem; +import com.djrapitops.plugin.api.config.Config; +import com.djrapitops.plugin.utilities.Verify; + +import java.io.File; +import java.io.IOException; +import java.util.Optional; +import java.util.UUID; + +/** + * Manages local server info file. + *

+ * Server.yml contains current server's ID, UUID and Bungee WebServer connection information. + * It + * + * @author Rsl1122 + */ +public class ServerInfoFile extends Config { + public ServerInfoFile(File dataFolder) throws IOException { + super(new File(dataFolder, "ServerInfoFile.yml")); + copyDefaults(FileSystem.readFromResource("DefaultServerInfoFile.yml")); + save(); + } + + public void saveServerUUID(UUID serverUUID) throws IOException { + set("Server.UUID", serverUUID.toString()); + save(); + } + + public Optional getUUID() { + String uuidString = getString("Server.UUID"); + if (Verify.isEmpty(uuidString)) { + return Optional.empty(); + } + return Optional.of(UUID.fromString(uuidString)); + } + +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/ServerVariableHolder.java b/Plan/src/main/java/com/djrapitops/plan/system/info/server/ServerProperties.java similarity index 56% rename from Plan/src/main/java/com/djrapitops/plan/ServerVariableHolder.java rename to Plan/src/main/java/com/djrapitops/plan/system/info/server/ServerProperties.java index 3b3ed362a..ad62df6a3 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ServerVariableHolder.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/info/server/ServerProperties.java @@ -1,6 +1,6 @@ -package com.djrapitops.plan; +package com.djrapitops.plan.system.info.server; -import com.djrapitops.plan.settings.Settings; +import com.djrapitops.plan.system.settings.Settings; import net.md_5.bungee.api.ProxyServer; import org.bukkit.Server; @@ -11,23 +11,21 @@ import org.bukkit.Server; * @author Rsl1122 * @since 3.4.1 */ -public class ServerVariableHolder { +public class ServerProperties { + private final String id; private final String name; private final int port; private final String version; private final String implVersion; - private final String ip; + private final IPWrapper ip; private final int maxPlayers; - private final boolean usingPaper; - /** - * Constructor, grabs the variables. - * - * @param server instance the plugin is running on. - */ - public ServerVariableHolder(Server server) { - ip = server.getIp(); + private final OnlinePlayersWrapper onlinePlayers; + + public ServerProperties(Server server) { + id = server.getServerId(); + ip = server::getIp; name = server.getName(); port = server.getPort(); version = server.getVersion(); @@ -35,17 +33,12 @@ public class ServerVariableHolder { maxPlayers = server.getMaxPlayers(); - usingPaper = name.equals("Paper") - || name.equals("TacoSpigot"); //Fork of Paper + onlinePlayers = () -> server.getOnlinePlayers().size(); } - /** - * Constructor, grabs the variables. - * - * @param server instance the plugin is running on. - */ - public ServerVariableHolder(ProxyServer server) { - ip = Settings.BUNGEE_IP.toString(); + public ServerProperties(ProxyServer server) { + id = server.getServers().toString(); + ip = Settings.BUNGEE_IP::toString; name = "BungeeCord"; port = -1; version = server.getVersion(); @@ -53,7 +46,7 @@ public class ServerVariableHolder { maxPlayers = server.getConfig().getPlayerLimit(); - usingPaper = false; + onlinePlayers = server::getOnlineCount; } /** @@ -62,16 +55,7 @@ public class ServerVariableHolder { * @return the ip. */ public String getIp() { - return ip; - } - - /** - * Returns if the server is using PaperSpigot. - * - * @return if the server is using PaperSpigot. - */ - public boolean isUsingPaper() { - return usingPaper; + return ip.getIP(); } public String getName() { @@ -93,4 +77,20 @@ public class ServerVariableHolder { public int getMaxPlayers() { return maxPlayers; } + + public String getServerId() { + return id; + } + + public int getOnlinePlayers() { + return onlinePlayers.getOnlinePlayers(); + } + + private interface OnlinePlayersWrapper { + int getOnlinePlayers(); + } + + private interface IPWrapper { + String getIP(); + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/listeners/BukkitListenerSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/BukkitListenerSystem.java new file mode 100644 index 000000000..1d2d4c107 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/BukkitListenerSystem.java @@ -0,0 +1,32 @@ +package com.djrapitops.plan.system.listeners; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.system.listeners.bukkit.*; +import org.bukkit.event.HandlerList; + +public class BukkitListenerSystem extends ListenerSystem { + + private final Plan plugin; + + public BukkitListenerSystem(Plan plugin) { + this.plugin = plugin; + } + + @Override + protected void registerListeners() { + plugin.registerListener( + new PlayerOnlineListener(), + new ChatListener(), + new GamemodeChangeListener(), + new WorldChangeListener(), + new CommandPreprocessListener(plugin), + new DeathEventListener() + ); + PlayerOnlineListener.setCountKicks(true); + } + + @Override + protected void unregisterListeners() { + HandlerList.unregisterAll(plugin); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/listeners/BungeeListenerSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/BungeeListenerSystem.java new file mode 100644 index 000000000..99e4f6abc --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/BungeeListenerSystem.java @@ -0,0 +1,23 @@ +package com.djrapitops.plan.system.listeners; + +import com.djrapitops.plan.PlanBungee; +import com.djrapitops.plan.system.listeners.bungee.PlayerOnlineListener; + +public class BungeeListenerSystem extends ListenerSystem { + + private final PlanBungee plugin; + + public BungeeListenerSystem(PlanBungee plugin) { + this.plugin = plugin; + } + + @Override + protected void registerListeners() { + plugin.registerListener(new PlayerOnlineListener(plugin)); + } + + @Override + protected void unregisterListeners() { + plugin.getProxy().getPluginManager().unregisterListeners(plugin); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/listeners/ListenerSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/ListenerSystem.java new file mode 100644 index 000000000..4b4e717d1 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/ListenerSystem.java @@ -0,0 +1,25 @@ +package com.djrapitops.plan.system.listeners; + +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plugin.api.Benchmark; + +public abstract class ListenerSystem implements SubSystem { + + @Override + public void enable() { + Benchmark.start("Register Listeners"); + registerListeners(); + Benchmark.stop("Enable", "Register Listeners"); + } + + @Override + public void disable() { + unregisterListeners(); + } + + protected abstract void registerListeners(); + + protected abstract void unregisterListeners(); + + +} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanChatListener.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/ChatListener.java similarity index 55% rename from Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanChatListener.java rename to Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/ChatListener.java index d965a499f..3de3b38ba 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanChatListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/ChatListener.java @@ -1,8 +1,7 @@ -package com.djrapitops.plan.systems.listeners; +package com.djrapitops.plan.system.listeners.bukkit; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.processing.player.NameProcessor; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.processing.processors.player.NameProcessor; import com.djrapitops.plugin.api.utility.log.Log; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -17,20 +16,7 @@ import java.util.UUID; * * @author Rsl1122 */ -public class PlanChatListener implements Listener { - - private final Plan plugin; - private final DataCache dataCache; - - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public PlanChatListener(Plan plugin) { - this.plugin = plugin; - dataCache = plugin.getDataCache(); - } +public class ChatListener implements Listener { /** * ChatEvent listener. @@ -49,11 +35,12 @@ public class PlanChatListener implements Listener { String name = p.getName(); String displayName = p.getDisplayName(); - if (dataCache.isFirstSession(uuid)) { - dataCache.firstSessionMessageSent(uuid); + SessionCache sessionCache = SessionCache.getInstance(); + if (sessionCache.isFirstSession(uuid)) { + sessionCache.firstSessionMessageSent(uuid); } - plugin.addToProcessQueue(new NameProcessor(uuid, name, displayName)); + new NameProcessor(uuid, name, displayName).queue(); } catch (Exception e) { Log.toLog(this.getClass(), e); } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanCommandPreprocessListener.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/CommandPreprocessListener.java similarity index 58% rename from Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanCommandPreprocessListener.java rename to Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/CommandPreprocessListener.java index 9d83293a7..0db8038e3 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanCommandPreprocessListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/CommandPreprocessListener.java @@ -1,12 +1,11 @@ -package com.djrapitops.plan.systems.listeners; +package com.djrapitops.plan.system.listeners.bukkit; import com.djrapitops.plan.Plan; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.processing.CommandProcessor; +import com.djrapitops.plan.system.processing.processors.CommandProcessor; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.Settings; import com.djrapitops.plugin.api.utility.log.Log; import org.bukkit.command.Command; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -17,7 +16,7 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent; * * @author Rsl1122 */ -public class PlanCommandPreprocessListener implements Listener { +public class CommandPreprocessListener implements Listener { private final Plan plugin; @@ -26,7 +25,7 @@ public class PlanCommandPreprocessListener implements Listener { * * @param plugin Current instance of Plan */ - public PlanCommandPreprocessListener(Plan plugin) { + public CommandPreprocessListener(Plan plugin) { this.plugin = plugin; } @@ -37,30 +36,19 @@ public class PlanCommandPreprocessListener implements Listener { */ @EventHandler(priority = EventPriority.MONITOR) public void onPlayerCommand(PlayerCommandPreprocessEvent event) { - if (event.isCancelled()) { + boolean hasIgnorePermission = event.getPlayer().hasPermission(Permissions.IGNORE_COMMANDUSE.getPermission()); + if (event.isCancelled() || hasIgnorePermission) { return; } - Player player = event.getPlayer(); try { - if (player.hasPermission(Permissions.IGNORE_COMMANDUSE.getPermission())) { - return; - } - String commandName = event.getMessage().substring(1).split(" ")[0].toLowerCase(); boolean logUnknownCommands = Settings.LOG_UNKNOWN_COMMANDS.isTrue(); boolean combineCommandAliases = Settings.COMBINE_COMMAND_ALIASES.isTrue(); if (!logUnknownCommands || combineCommandAliases) { - Command command = plugin.getServer().getPluginCommand(commandName); - if (command == null) { - try { - command = plugin.getServer().getCommandMap().getCommand(commandName); - } catch (NoSuchMethodError ignored) { - /* Ignored, Bukkit 1.8 has no such method */ - } - } + Command command = getBukkitCommand(commandName); if (command == null) { if (!logUnknownCommands) { return; @@ -69,9 +57,21 @@ public class PlanCommandPreprocessListener implements Listener { commandName = command.getName(); } } - plugin.addToProcessQueue(new CommandProcessor(commandName)); + new CommandProcessor(commandName).queue(); } catch (Exception e) { Log.toLog(this.getClass(), e); } } + + private Command getBukkitCommand(String commandName) { + Command command = plugin.getServer().getPluginCommand(commandName); + if (command == null) { + try { + command = plugin.getServer().getCommandMap().getCommand(commandName); + } catch (NoSuchMethodError ignored) { + /* Ignored, Bukkit 1.8 has no such method */ + } + } + return command; + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanDeathEventListener.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/DeathEventListener.java similarity index 62% rename from Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanDeathEventListener.java rename to Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/DeathEventListener.java index 5be636f7a..6f5805072 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanDeathEventListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/DeathEventListener.java @@ -1,8 +1,9 @@ -package com.djrapitops.plan.systems.listeners; +package com.djrapitops.plan.system.listeners.bukkit; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.systems.processing.player.DeathProcessor; -import com.djrapitops.plan.systems.processing.player.KillProcessor; +import com.djrapitops.plan.data.container.Session; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.processing.processors.player.KillProcessor; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.utilities.Format; @@ -21,18 +22,7 @@ import org.bukkit.projectiles.ProjectileSource; * * @author Rsl1122 */ -public class PlanDeathEventListener implements Listener { - - private final Plan plugin; - - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public PlanDeathEventListener(Plan plugin) { - this.plugin = plugin; - } +public class DeathEventListener implements Listener { /** * Command use listener. @@ -46,7 +36,8 @@ public class PlanDeathEventListener implements Listener { LivingEntity dead = event.getEntity(); if (dead instanceof Player) { - plugin.addToProcessQueue(new DeathProcessor(dead.getUniqueId())); + // Process Death + Processor.queue(() -> SessionCache.getCachedSession(dead.getUniqueId()).ifPresent(Session::died)); } try { @@ -58,19 +49,27 @@ public class PlanDeathEventListener implements Listener { EntityDamageByEntityEvent entityDamageByEntityEvent = (EntityDamageByEntityEvent) entityDamageEvent; Entity killerEntity = entityDamageByEntityEvent.getDamager(); - if (killerEntity instanceof Player) { - handlePlayerKill(time, dead, (Player) killerEntity); - } else if (killerEntity instanceof Wolf) { - handleWolfKill(time, dead, (Wolf) killerEntity); - } else if (killerEntity instanceof Arrow) { - handleArrowKill(time, dead, (Arrow) killerEntity); - } + handleKill(time, dead, killerEntity); } catch (Exception e) { Log.toLog(this.getClass(), e); } } - private void handlePlayerKill(long time, LivingEntity dead, Player killer) { + private void handleKill(long time, LivingEntity dead, Entity killerEntity) { + KillProcessor processor = null; + if (killerEntity instanceof Player) { + processor = handlePlayerKill(time, dead, (Player) killerEntity); + } else if (killerEntity instanceof Wolf) { + processor = handleWolfKill(time, dead, (Wolf) killerEntity); + } else if (killerEntity instanceof Arrow) { + processor = handleArrowKill(time, dead, (Arrow) killerEntity); + } + if (processor != null) { + processor.queue(); + } + } + + private KillProcessor handlePlayerKill(long time, LivingEntity dead, Player killer) { Material itemInHand; try { itemInHand = killer.getInventory().getItemInMainHand().getType(); @@ -82,31 +81,31 @@ public class PlanDeathEventListener implements Listener { } } - plugin.addToProcessQueue(new KillProcessor(killer.getUniqueId(), time, dead, normalizeMaterialName(itemInHand))); + return new KillProcessor(killer.getUniqueId(), time, dead, normalizeMaterialName(itemInHand)); } - private void handleWolfKill(long time, LivingEntity dead, Wolf wolf) { + private KillProcessor handleWolfKill(long time, LivingEntity dead, Wolf wolf) { if (!wolf.isTamed()) { - return; + return null; } AnimalTamer owner = wolf.getOwner(); if (!(owner instanceof Player)) { - return; + return null; } - plugin.addToProcessQueue(new KillProcessor(owner.getUniqueId(), time, dead, "Wolf")); + return new KillProcessor(owner.getUniqueId(), time, dead, "Wolf"); } - private void handleArrowKill(long time, LivingEntity dead, Arrow arrow) { + private KillProcessor handleArrowKill(long time, LivingEntity dead, Arrow arrow) { ProjectileSource source = arrow.getShooter(); if (!(source instanceof Player)) { - return; + return null; } Player player = (Player) source; - plugin.addToProcessQueue(new KillProcessor(player.getUniqueId(), time, dead, "Bow")); + return new KillProcessor(player.getUniqueId(), time, dead, "Bow"); } /** diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanGamemodeChangeListener.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/GamemodeChangeListener.java similarity index 71% rename from Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanGamemodeChangeListener.java rename to Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/GamemodeChangeListener.java index 26c94492c..3e04d6a62 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanGamemodeChangeListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/GamemodeChangeListener.java @@ -1,8 +1,8 @@ -package com.djrapitops.plan.systems.listeners; +package com.djrapitops.plan.system.listeners.bukkit; -import com.djrapitops.plan.Plan; import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.settings.WorldAliasSettings; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.settings.WorldAliasSettings; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.api.utility.log.Log; import org.bukkit.entity.Player; @@ -19,18 +19,7 @@ import java.util.UUID; * * @author Rsl1122 */ -public class PlanGamemodeChangeListener implements Listener { - - private final Plan plugin; - - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public PlanGamemodeChangeListener(Plan plugin) { - this.plugin = plugin; - } +public class GamemodeChangeListener implements Listener { /** * GM Change Event Listener. @@ -51,7 +40,7 @@ public class PlanGamemodeChangeListener implements Listener { new WorldAliasSettings().addWorld(worldName); - Optional cachedSession = plugin.getDataCache().getCachedSession(uuid); + Optional cachedSession = SessionCache.getCachedSession(uuid); cachedSession.ifPresent(session -> session.changeState(worldName, gameMode, time)); } catch (Exception e) { Log.toLog(this.getClass(), e); diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanPlayerListener.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/PlayerOnlineListener.java similarity index 71% rename from Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanPlayerListener.java rename to Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/PlayerOnlineListener.java index 7ddbfbab1..d69935576 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanPlayerListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/PlayerOnlineListener.java @@ -1,11 +1,11 @@ -package com.djrapitops.plan.systems.listeners; +package com.djrapitops.plan.system.listeners.bukkit; -import com.djrapitops.plan.Plan; import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.processing.info.NetworkPageUpdateProcessor; -import com.djrapitops.plan.systems.processing.player.*; -import com.djrapitops.plan.systems.tasks.TaskSystem; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.processing.processors.info.NetworkPageUpdateProcessor; +import com.djrapitops.plan.system.processing.processors.player.*; +import com.djrapitops.plan.system.tasks.TaskSystem; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.api.systems.NotificationCenter; import com.djrapitops.plugin.api.utility.log.Log; @@ -26,21 +26,12 @@ import java.util.UUID; * @author Rsl1122 * @since 2.0.0 */ -public class PlanPlayerListener implements Listener { +public class PlayerOnlineListener implements Listener { private static boolean countKicks = true; - private final Plan plugin; - private final DataCache cache; - - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public PlanPlayerListener(Plan plugin) { - this.plugin = plugin; - cache = plugin.getDataCache(); + public static void setCountKicks(boolean value) { + countKicks = value; } @EventHandler(priority = EventPriority.MONITOR) @@ -49,11 +40,8 @@ public class PlanPlayerListener implements Listener { PlayerLoginEvent.Result result = event.getResult(); UUID uuid = event.getPlayer().getUniqueId(); boolean op = event.getPlayer().isOp(); - if (result == PlayerLoginEvent.Result.KICK_BANNED) { - plugin.addToProcessQueue(new BanAndOpProcessor(uuid, true, op)); - } else { - plugin.addToProcessQueue(new BanAndOpProcessor(uuid, false, op)); - } + boolean banned = result == PlayerLoginEvent.Result.KICK_BANNED; + new BanAndOpProcessor(uuid, banned, op).queue(); } catch (Exception e) { Log.toLog(this.getClass(), e); } @@ -74,7 +62,7 @@ public class PlanPlayerListener implements Listener { return; } UUID uuid = event.getPlayer().getUniqueId(); - plugin.addToProcessQueue(new KickProcessor(uuid)); + new KickProcessor(uuid).queue(); } catch (Exception e) { Log.toLog(this.getClass(), e); } @@ -106,13 +94,14 @@ public class PlanPlayerListener implements Listener { int playersOnline = TaskSystem.getInstance().getTpsCountTimer().getLatestPlayersOnline(); - cache.cacheSession(uuid, Session.start(time, world, gm)); - plugin.addToProcessQueue( + SessionCache.getInstance().cacheSession(uuid, new Session(time, world, gm)); + + Processor.queueMany( new RegisterProcessor(uuid, player.getFirstPlayed(), time, playerName, playersOnline, new IPUpdateProcessor(uuid, ip, time), new NameProcessor(uuid, playerName, displayName) ), - new NetworkPageUpdateProcessor(plugin.getInfoManager()) + new NetworkPageUpdateProcessor() ); } catch (Exception e) { Log.toLog(this.getClass(), e); @@ -133,22 +122,19 @@ public class PlanPlayerListener implements Listener { Player player = event.getPlayer(); UUID uuid = player.getUniqueId(); - plugin.addToProcessQueue( + Processor.queueMany( new BanAndOpProcessor(uuid, player.isBanned(), player.isOp()), new EndSessionProcessor(uuid, time), - new NetworkPageUpdateProcessor(plugin.getInfoManager()) + new NetworkPageUpdateProcessor() ); - if (cache.isFirstSession(uuid)) { - int messagesSent = plugin.getDataCache().getFirstSessionMsgCount(uuid); - plugin.addToProcessQueue(new FirstLeaveProcessor(uuid, time, messagesSent)); + SessionCache sessionCache = SessionCache.getInstance(); + if (sessionCache.isFirstSession(uuid)) { + int messagesSent = sessionCache.getFirstSessionMsgCount(uuid); + new FirstLeaveProcessor(uuid, time, messagesSent).queue(); } } catch (Exception e) { Log.toLog(this.getClass(), e); } } - - public static void setCountKicks(boolean value) { - countKicks = value; - } } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanWorldChangeListener.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/WorldChangeListener.java similarity index 71% rename from Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanWorldChangeListener.java rename to Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/WorldChangeListener.java index e23e5abaf..18a038218 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/PlanWorldChangeListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bukkit/WorldChangeListener.java @@ -1,8 +1,8 @@ -package com.djrapitops.plan.systems.listeners; +package com.djrapitops.plan.system.listeners.bukkit; -import com.djrapitops.plan.Plan; import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.settings.WorldAliasSettings; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.settings.WorldAliasSettings; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.api.utility.log.Log; import org.bukkit.entity.Player; @@ -14,12 +14,7 @@ import org.bukkit.event.player.PlayerChangedWorldEvent; import java.util.Optional; import java.util.UUID; -public class PlanWorldChangeListener implements Listener { - private final Plan plugin; - - public PlanWorldChangeListener(Plan plugin) { - this.plugin = plugin; - } +public class WorldChangeListener implements Listener { @EventHandler(priority = EventPriority.MONITOR) public void onWorldChange(PlayerChangedWorldEvent event) { @@ -33,7 +28,7 @@ public class PlanWorldChangeListener implements Listener { new WorldAliasSettings().addWorld(worldName); - Optional cachedSession = plugin.getDataCache().getCachedSession(uuid); + Optional cachedSession = SessionCache.getCachedSession(uuid); cachedSession.ifPresent(session -> session.changeState(worldName, gameMode, time)); } catch (Exception e) { Log.toLog(this.getClass(), e); diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/BungeePlayerListener.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bungee/PlayerOnlineListener.java similarity index 73% rename from Plan/src/main/java/com/djrapitops/plan/systems/listeners/BungeePlayerListener.java rename to Plan/src/main/java/com/djrapitops/plan/system/listeners/bungee/PlayerOnlineListener.java index c5f728c15..bdcc5bac3 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/listeners/BungeePlayerListener.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/bungee/PlayerOnlineListener.java @@ -2,10 +2,10 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.listeners; +package com.djrapitops.plan.system.listeners.bungee; import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.systems.processing.player.BungeePlayerRegisterProcessor; +import com.djrapitops.plan.system.processing.processors.player.BungeePlayerRegisterProcessor; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.api.utility.log.Log; import net.md_5.bungee.api.connection.ProxiedPlayer; @@ -20,11 +20,11 @@ import java.util.UUID; * * @author Rsl1122 */ -public class BungeePlayerListener implements Listener { +public class PlayerOnlineListener implements Listener { private final PlanBungee plugin; - public BungeePlayerListener(PlanBungee plugin) { + public PlayerOnlineListener(PlanBungee plugin) { this.plugin = plugin; } @@ -36,7 +36,7 @@ public class BungeePlayerListener implements Listener { String name = player.getName(); long now = MiscUtils.getTime(); - plugin.getProcessingQueue().addToQueue(new BungeePlayerRegisterProcessor(uuid, name, now)); + plugin.getSystem().getProcessingQueue().queue(new BungeePlayerRegisterProcessor(uuid, name, now)); } catch (Exception e) { Log.toLog(this.getClass(), e); } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/queue/ProcessingQueue.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/ProcessingQueue.java similarity index 55% rename from Plan/src/main/java/com/djrapitops/plan/systems/queue/ProcessingQueue.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/ProcessingQueue.java index ea95fe833..f46b32f12 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/queue/ProcessingQueue.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/ProcessingQueue.java @@ -1,9 +1,15 @@ -package com.djrapitops.plan.systems.queue; +package com.djrapitops.plan.system.processing; -import com.djrapitops.plan.systems.processing.Processor; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plan.utilities.queue.Consumer; +import com.djrapitops.plan.utilities.queue.Queue; +import com.djrapitops.plan.utilities.queue.Setup; import com.djrapitops.plugin.api.Benchmark; import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; +import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; @@ -14,32 +20,51 @@ import java.util.concurrent.BlockingQueue; * @author Rsl1122 * @since 3.0.0 */ -public class ProcessingQueue extends Queue { +public class ProcessingQueue extends Queue implements SubSystem { - /** - * Class constructor, starts the new Thread for processing. - */ public ProcessingQueue() { super(new ArrayBlockingQueue<>(20000)); setup = new ProcessSetup(queue); + } + + public static ProcessingQueue getInstance() { + ProcessingQueue processingQueue = PlanSystem.getInstance().getProcessingQueue(); + Verify.nullCheck(processingQueue, () -> new IllegalStateException("ProcessingQueue has not been initialized.")); + return processingQueue; + } + + @Override + public void enable() { setup.go(); } + @Override + public void disable() { + List processors = stopAndReturnLeftovers(); + Log.info("Processing unprocessed processors. (" + processors.size() + ")"); + for (Processor processor : processors) { + try { + processor.process(); + } catch (Exception e) { + Log.toLog(this.getClass(), e); + } + } + } + /** * Used to add Processor object to be processed. * * @param processor processing object. */ - public void addToQueue(Processor processor) { + public void queue(Processor processor) { if (!queue.offer(processor)) { - Log.toLog("ProcessingQueue.addToQueue", new IllegalStateException("Processor was not added to Queue")); + Log.toLog(Processor.class, new IllegalStateException("Processor was not added to Queue")); } } } class ProcessConsumer extends Consumer { - ProcessConsumer(BlockingQueue q) { super(q, "ProcessQueueConsumer"); } @@ -55,13 +80,9 @@ class ProcessConsumer extends Consumer { process.process(); Benchmark.stop(benchName); } catch (Exception | NoClassDefFoundError | NoSuchFieldError | NoSuchMethodError e) { - Log.toLog(this.getTaskName() + ":" + process.getClass().getSimpleName(), e); + Log.toLog(process.getClass(), e); } } - - @Override - protected void clearVariables() { - } } class ProcessSetup extends Setup { diff --git a/Plan/src/main/java/com/djrapitops/plan/system/processing/Processor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/Processor.java new file mode 100644 index 000000000..d65f6d724 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/Processor.java @@ -0,0 +1,36 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.processing; + +/** + * Interface for ProcessingQueue. + *

+ * Allows lambda Processor creation. + * + * @author Rsl1122 + */ +public interface Processor { + + static void queueMany(Processor... processors) { + ProcessingQueue processingQueue = ProcessingQueue.getInstance(); + for (Processor processor : processors) { + processingQueue.queue(processor); + } + } + + /** + * A way to run code Async in ProcessingQueue. + *

+ * Good for lambdas. + * + * @param processor Processor. + */ + static void queue(Processor processor) { + ProcessingQueue.getInstance().queue(processor); + } + + void process(); + +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/ImporterManager.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/ImporterManager.java similarity index 91% rename from Plan/src/main/java/com/djrapitops/plan/systems/info/ImporterManager.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/importing/ImporterManager.java index 934341f79..581430d5c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/ImporterManager.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/ImporterManager.java @@ -1,10 +1,10 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.info; +package com.djrapitops.plan.system.processing.importing; -import com.djrapitops.plan.systems.processing.importing.importers.Importer; +import com.djrapitops.plan.system.processing.importing.importers.Importer; import java.util.ArrayList; import java.util.List; diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/ServerImportData.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/ServerImportData.java similarity index 82% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/ServerImportData.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/importing/ServerImportData.java index f99196d5a..aff69e64a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/ServerImportData.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/ServerImportData.java @@ -1,10 +1,11 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.importing; +package com.djrapitops.plan.system.processing.importing; import com.djrapitops.plan.data.container.TPS; +import com.djrapitops.plan.data.container.builders.TPSBuilder; import java.util.*; @@ -61,7 +62,15 @@ public class ServerImportData { } public ServerImportDataBuilder tpsData(long date, double ticksPerSecond, int players, double cpuUsage, long usedMemory, int entityCount, int chunksLoaded) { - TPS tps = new TPS(date, ticksPerSecond, players, cpuUsage, usedMemory, entityCount, chunksLoaded); + TPS tps = TPSBuilder.get() + .date(date) + .tps(ticksPerSecond) + .playersOnline(players) + .usedCPU(cpuUsage) + .usedMemory(usedMemory) + .entities(entityCount) + .chunksLoaded(chunksLoaded) + .toTPS(); this.tpsData.add(tps); return this; } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/UserImportData.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/UserImportData.java similarity index 99% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/UserImportData.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/importing/UserImportData.java index 3941da6a9..450e9d6cd 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/UserImportData.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/UserImportData.java @@ -1,8 +1,8 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.importing; +package com.djrapitops.plan.system.processing.importing; import com.djrapitops.plan.data.container.PlayerKill; import com.djrapitops.plan.data.time.GMTimes; diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/UserImportRefiner.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/UserImportRefiner.java similarity index 92% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/UserImportRefiner.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/importing/UserImportRefiner.java index 955ea3c5c..dcfde5fa9 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/UserImportRefiner.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/UserImportRefiner.java @@ -1,8 +1,8 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.importing; +package com.djrapitops.plan.system.processing.importing; import com.djrapitops.plan.Plan; import com.djrapitops.plugin.api.Benchmark; @@ -27,15 +27,15 @@ public class UserImportRefiner { private final Plan plugin; private final boolean onlineMode; - private final List importers = new Vector<>(); + private final List importers = new ArrayList<>(); - private final Map worlds = new Hashtable<>(); + private final Map worlds = new HashMap<>(); - private final Map uuidsMissing = new Hashtable<>(); - private final Map namesMissing = new Hashtable<>(); + private final Map uuidsMissing = new HashMap<>(); + private final Map namesMissing = new HashMap<>(); - private final Map foundUUIDs = new Hashtable<>(); - private final Map foundNames = new Hashtable<>(); + private final Map foundUUIDs = new HashMap<>(); + private final Map foundNames = new HashMap<>(); public UserImportRefiner(Plan plugin, List importers) { this.plugin = plugin; @@ -92,7 +92,7 @@ public class UserImportRefiner { Benchmark.start(benchmarkName); - List invalidData = new Vector<>(); + List invalidData = new ArrayList<>(); importers.parallelStream().forEach(importer -> { String name = importer.getName(); @@ -153,7 +153,7 @@ public class UserImportRefiner { result = uuidFetcher.call().entrySet().parallelStream() .collect(Collectors.toMap(entry -> entry.getValue().toString(), Map.Entry::getKey)); } catch (Exception e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); return; } @@ -161,7 +161,7 @@ public class UserImportRefiner { } private void addMissingUUIDsOverOfflinePlayer() { - Map result = new Hashtable<>(); + Map result = new HashMap<>(); for (String name : uuidsMissing.values()) { String uuid = getUuidByOfflinePlayer(name); @@ -177,7 +177,7 @@ public class UserImportRefiner { } private void addFoundUUIDs(Map foundUUIDs) { - List found = new Vector<>(); + List found = new ArrayList<>(); uuidsMissing.entrySet().parallelStream().forEach((entry) -> { UserImportData importer = entry.getKey(); @@ -218,7 +218,7 @@ public class UserImportRefiner { } private void addMissingNames() { - Map result = new Hashtable<>(); + Map result = new HashMap<>(); namesMissing.values().parallelStream().forEach(uuid -> { String name = getNameByOfflinePlayer(uuid); @@ -230,7 +230,7 @@ public class UserImportRefiner { } private void addFoundNames(Map foundNames) { - List found = new Vector<>(); + List found = new ArrayList<>(); namesMissing.entrySet().parallelStream().forEach(entry -> { UserImportData importer = entry.getKey(); diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/importers/Importer.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/importers/Importer.java similarity index 59% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/importers/Importer.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/importing/importers/Importer.java index dc1665cde..b564c9f81 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/importers/Importer.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/importers/Importer.java @@ -1,26 +1,28 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.importing.importers; +package com.djrapitops.plan.system.processing.importing.importers; import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.database.DBException; import com.djrapitops.plan.data.container.GeoInfo; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.container.UserInfo; import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.systems.cache.GeolocationCache; -import com.djrapitops.plan.systems.processing.importing.ServerImportData; -import com.djrapitops.plan.systems.processing.importing.UserImportData; -import com.djrapitops.plan.systems.processing.importing.UserImportRefiner; +import com.djrapitops.plan.system.cache.GeolocationCache; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.database.databases.operation.SaveOperations; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.processing.importing.ServerImportData; +import com.djrapitops.plan.system.processing.importing.UserImportData; +import com.djrapitops.plan.system.processing.importing.UserImportRefiner; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.api.Benchmark; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.utilities.Verify; import com.google.common.collect.ImmutableMap; -import java.sql.SQLException; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -48,30 +50,25 @@ public abstract class Importer { ExecutorService service = Executors.newCachedThreadPool(); - new ImportExecutorHelper() { - @Override - void execute() { - Benchmark.start(serverBenchmarkName); - processServerData(); - Benchmark.stop(serverBenchmarkName); - } - }.submit(service); + submitTo(service, () -> { + Benchmark.start(serverBenchmarkName); + processServerData(); + Benchmark.stop(serverBenchmarkName); + }); - new ImportExecutorHelper() { - @Override - void execute() throws SQLException { - Benchmark.start(userDataBenchmarkName); - processUserData(); - Benchmark.stop(userDataBenchmarkName); - } - }.submit(service); + submitTo(service, () -> { + Benchmark.start(userDataBenchmarkName); + processUserData(); + Benchmark.stop(userDataBenchmarkName); + }); service.shutdown(); try { service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); + Thread.currentThread().interrupt(); } Benchmark.stop(benchmarkName); @@ -94,27 +91,16 @@ public abstract class Importer { return; } - Plan plugin = Plan.getInstance(); - UUID uuid = plugin.getServerInfoManager().getServerUUID(); - Database db = plugin.getDB(); + UUID uuid = ServerInfo.getServerUUID(); + Database db = Database.getActive(); ExecutorService service = Executors.newCachedThreadPool(); Benchmark.start(insertDataIntoDatabaseBenchmarkName); - new ImportExecutorHelper() { - @Override - void execute() throws SQLException { - db.getTpsTable().insertAllTPS(ImmutableMap.of(uuid, serverImportData.getTpsData())); - } - }.submit(service); - - new ImportExecutorHelper() { - @Override - void execute() throws SQLException { - db.getCommandUseTable().insertCommandUsage(ImmutableMap.of(uuid, serverImportData.getCommandUsages())); - } - }.submit(service); + SaveOperations save = db.save(); + submitTo(service, () -> save.insertTPS(ImmutableMap.of(uuid, serverImportData.getTpsData()))); + submitTo(service, () -> save.insertCommandUsage(ImmutableMap.of(uuid, serverImportData.getCommandUsages()))); service.shutdown(); @@ -122,14 +108,14 @@ public abstract class Importer { service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } Benchmark.stop(insertDataIntoDatabaseBenchmarkName); Benchmark.stop(benchmarkName); } - private void processUserData() throws SQLException { + private void processUserData() throws DBException { String benchmarkName = "Processing User Data"; String getDataBenchmarkName = "Getting User Data"; String insertDataIntoCollectionsBenchmarkName = "Insert User Data into Collections"; @@ -146,25 +132,23 @@ public abstract class Importer { return; } - Plan plugin = Plan.getInstance(); - - UserImportRefiner userImportRefiner = new UserImportRefiner(plugin, userImportData); + UserImportRefiner userImportRefiner = new UserImportRefiner(Plan.getInstance(), userImportData); userImportData = userImportRefiner.refineData(); - UUID serverUUID = plugin.getServerInfoManager().getServerUUID(); - Database db = plugin.getDB(); + UUID serverUUID = ServerInfo.getServerUUID(); + Database db = Database.getActive(); - Set existingUUIDs = db.getSavedUUIDs(); - Set existingUserInfoTableUUIDs = db.getUserInfoTable().getSavedUUIDs().get(serverUUID); + Set existingUUIDs = db.fetch().getSavedUUIDs(); + Set existingUserInfoTableUUIDs = db.fetch().getSavedUUIDs(serverUUID); Benchmark.start(insertDataIntoCollectionsBenchmarkName); - Map users = new Hashtable<>(); - List userInfo = new Vector<>(); - Map> nickNames = new Hashtable<>(); - Map> sessions = new Hashtable<>(); - Map> geoInfo = new Hashtable<>(); - Map timesKicked = new Hashtable<>(); + Map users = new HashMap<>(); + List userInfo = new ArrayList<>(); + Map> nickNames = new HashMap<>(); + Map> sessions = new HashMap<>(); + Map> geoInfo = new HashMap<>(); + Map timesKicked = new HashMap<>(); userImportData.parallelStream().forEach(data -> { UUID uuid = data.getUuid(); @@ -190,42 +174,14 @@ public abstract class Importer { Benchmark.start(insertDataIntoDatabaseBenchmarkName); - db.getUsersTable().insertUsers(users); + SaveOperations save = db.save(); - new ImportExecutorHelper() { - @Override - void execute() throws SQLException { - db.getSessionsTable().insertSessions(ImmutableMap.of(serverUUID, sessions), true); - } - }.submit(service); - - new ImportExecutorHelper() { - @Override - void execute() throws SQLException { - db.getUsersTable().updateKicked(timesKicked); - } - }.submit(service); - - new ImportExecutorHelper() { - @Override - void execute() throws SQLException { - db.getUserInfoTable().insertUserInfo(ImmutableMap.of(serverUUID, userInfo)); - } - }.submit(service); - - new ImportExecutorHelper() { - @Override - void execute() throws SQLException { - db.getNicknamesTable().insertNicknames(ImmutableMap.of(serverUUID, nickNames)); - } - }.submit(service); - - new ImportExecutorHelper() { - @Override - void execute() throws SQLException { - db.getIpsTable().insertAllGeoInfo(geoInfo); - } - }.submit(service); + save.insertUsers(users); + submitTo(service, () -> save.insertSessions(ImmutableMap.of(serverUUID, sessions), true)); + submitTo(service, () -> save.kickAmount(timesKicked)); + submitTo(service, () -> save.insertUserInfo(ImmutableMap.of(serverUUID, userInfo))); + submitTo(service, () -> save.insertNicknames(ImmutableMap.of(serverUUID, nickNames))); + submitTo(service, () -> save.insertAllGeoInfo(geoInfo)); service.shutdown(); @@ -233,13 +189,17 @@ public abstract class Importer { service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } Benchmark.stop(insertDataIntoDatabaseBenchmarkName); Benchmark.stop(benchmarkName); } + private void submitTo(ExecutorService service, ImportExecutorHelper helper) { + helper.submit(service); + } + private UserInfo toUserInfo(UserImportData userImportData) { UUID uuid = userImportData.getUuid(); String name = userImportData.getName(); @@ -272,17 +232,17 @@ public abstract class Importer { }).collect(Collectors.toList()); } - private abstract class ImportExecutorHelper { - abstract void execute() throws SQLException; + private interface ImportExecutorHelper { + void execute() throws DBException; - void submit(ExecutorService service) { + default void submit(ExecutorService service) { service.submit(new Runnable() { @Override public void run() { try { execute(); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } }); diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/importers/OfflinePlayerImporter.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/importers/OfflinePlayerImporter.java similarity index 82% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/importers/OfflinePlayerImporter.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/importing/importers/OfflinePlayerImporter.java index 439db70db..527aeb8e7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/importing/importers/OfflinePlayerImporter.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/importing/importers/OfflinePlayerImporter.java @@ -1,18 +1,18 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.importing.importers; +package com.djrapitops.plan.system.processing.importing.importers; -import com.djrapitops.plan.systems.processing.importing.ServerImportData; -import com.djrapitops.plan.systems.processing.importing.UserImportData; +import com.djrapitops.plan.system.processing.importing.ServerImportData; +import com.djrapitops.plan.system.processing.importing.UserImportData; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; -import java.util.Vector; /** * @author Fuzzlemann @@ -32,7 +32,7 @@ public class OfflinePlayerImporter extends Importer { @Override public List getUserImportData() { - List dataList = new Vector<>(); + List dataList = new ArrayList<>(); Set operators = Bukkit.getOperators(); Set banned = Bukkit.getBannedPlayers(); diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/CommandProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/CommandProcessor.java similarity index 53% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/CommandProcessor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/CommandProcessor.java index 585b95243..05ed0a7bb 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/CommandProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/CommandProcessor.java @@ -1,20 +1,19 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing; +package com.djrapitops.plan.system.processing.processors; -import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; import com.djrapitops.plugin.api.utility.log.Log; -import java.sql.SQLException; - /** * Updates Command usage amount in the database. * * @author Rsl1122 */ -public class CommandProcessor extends Processor { +public class CommandProcessor extends ObjectProcessor { public CommandProcessor(String object) { super(object); @@ -23,9 +22,9 @@ public class CommandProcessor extends Processor { @Override public void process() { try { - Plan.getInstance().getDB().getCommandUseTable().commandUsed(object); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + Database.getActive().save().commandUsed(object); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/Processor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/ObjectProcessor.java similarity index 54% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/Processor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/ObjectProcessor.java index 6529d5ddd..c499b6611 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/Processor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/ObjectProcessor.java @@ -1,24 +1,31 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing; +package com.djrapitops.plan.system.processing.processors; + +import com.djrapitops.plan.system.processing.Processor; /** * Abstract class for processing different objects using Generics. * * @author Rsl1122 */ -public abstract class Processor { +public abstract class ObjectProcessor implements Processor { protected final T object; - public Processor(T object) { + public ObjectProcessor(T object) { this.object = object; } + @Override public abstract void process(); - public T getObject() { + protected T getObject() { return object; } + + public void queue() { + Processor.queue(this); + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/TPSInsertProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/TPSInsertProcessor.java similarity index 57% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/TPSInsertProcessor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/TPSInsertProcessor.java index 2d00ca66d..507edeed0 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/TPSInsertProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/TPSInsertProcessor.java @@ -1,15 +1,16 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing; +package com.djrapitops.plan.system.processing.processors; +import com.djrapitops.plan.api.exceptions.database.DBException; import com.djrapitops.plan.data.container.TPS; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.data.container.builders.TPSBuilder; +import com.djrapitops.plan.system.database.databases.Database; import com.djrapitops.plan.utilities.analysis.MathUtils; import com.djrapitops.plugin.api.utility.log.Log; -import java.sql.SQLException; import java.util.List; /** @@ -17,7 +18,7 @@ import java.util.List; * * @author Rsl1122 */ -public class TPSInsertProcessor extends Processor> { +public class TPSInsertProcessor extends ObjectProcessor> { public TPSInsertProcessor(List object) { super(object); @@ -28,17 +29,26 @@ public class TPSInsertProcessor extends Processor> { List history = object; final long lastDate = history.get(history.size() - 1).getDate(); final double averageTPS = MathUtils.round(MathUtils.averageDouble(history.stream().map(TPS::getTicksPerSecond))); - final int averagePlayersOnline = (int) MathUtils.averageInt(history.stream().map(TPS::getPlayers)); + final int peakPlayersOnline = history.stream().mapToInt(TPS::getPlayers).max().orElse(0); final double averageCPUUsage = MathUtils.round(MathUtils.averageDouble(history.stream().map(TPS::getCPUUsage))); final long averageUsedMemory = MathUtils.averageLong(history.stream().map(TPS::getUsedMemory)); final int averageEntityCount = (int) MathUtils.averageInt(history.stream().map(TPS::getEntityCount)); final int averageChunksLoaded = (int) MathUtils.averageInt(history.stream().map(TPS::getChunksLoaded)); - TPS tps = new TPS(lastDate, averageTPS, averagePlayersOnline, averageCPUUsage, averageUsedMemory, averageEntityCount, averageChunksLoaded); + TPS tps = TPSBuilder.get() + .date(lastDate) + .tps(averageTPS) + .playersOnline(peakPlayersOnline) + .usedCPU(averageCPUUsage) + .usedMemory(averageUsedMemory) + .entities(averageEntityCount) + .chunksLoaded(averageChunksLoaded) + .toTPS(); + try { - MiscUtils.getIPlan().getDB().getTpsTable().insertTPS(tps); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + Database.getActive().save().insertTPSforThisServer(tps); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/info/InspectCacheRequestProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/info/InspectCacheRequestProcessor.java similarity index 50% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/info/InspectCacheRequestProcessor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/info/InspectCacheRequestProcessor.java index 506fb4808..d2782265a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/info/InspectCacheRequestProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/info/InspectCacheRequestProcessor.java @@ -1,23 +1,24 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.info; +package com.djrapitops.plan.system.processing.processors.info; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.processing.player.PlayerProcessor; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.api.exceptions.connection.*; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.processing.processors.player.PlayerProcessor; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.command.CommandUtils; import com.djrapitops.plugin.command.ISender; import java.util.UUID; /** - * Sends a request to cache players inspect page to the PageCache on the appropriate WebServer. + * Sends a request to cache players inspect page to the ResponseCache on the appropriate WebServer. * * @author Rsl1122 */ @@ -34,19 +35,23 @@ public class InspectCacheRequestProcessor extends PlayerProcessor { @Override public void process() { - IPlan plugin = MiscUtils.getIPlan(); - plugin.getInfoManager().cachePlayer(getUUID()); - DataCache dataCache = plugin.getInfoManager().getDataCache(); - if (dataCache != null) { - dataCache.refreshActiveSessionsState(); + SessionCache.refreshActiveSessionsState(); + try { + InfoSystem.getInstance().generateAndCachePlayerPage(getUUID()); + sendInspectMsg(sender, playerName); + } catch (ConnectionFailException | UnsupportedTransferDatabaseException | UnauthorizedServerException + | NotFoundException | NoServersException e) { + // TODO Test if this is appropriate + sender.sendMessage("§c" + e.getMessage()); + } catch (WebException e) { + Log.toLog(this.getClass(), e); } - sendInspectMsg(sender, playerName); } private void sendInspectMsg(ISender sender, String playerName) { sender.sendMessage(Locale.get(Msg.CMD_HEADER_INSPECT) + " " + playerName); // Link - String url = Plan.getInstance().getInfoManager().getLinkTo("/player/" + playerName); + String url = ConnectionSystem.getInstance().getMainAddress() + "/player/" + playerName; String message = Locale.get(Msg.CMD_INFO_LINK).toString(); boolean console = !CommandUtils.isPlayer(sender); if (console) { diff --git a/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/info/NetworkPageUpdateProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/info/NetworkPageUpdateProcessor.java new file mode 100644 index 000000000..cbbf385d1 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/info/NetworkPageUpdateProcessor.java @@ -0,0 +1,27 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.processing.processors.info; + +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plugin.api.utility.log.Log; + +/** + * Processor for updating the network page. + * + * @author Rsl1122 + */ +public class NetworkPageUpdateProcessor implements Processor { + + @Override + public void process() { + try { + InfoSystem.getInstance().updateNetworkPage(); + } catch (WebException e) { + Log.toLog(this.getClass(), e); + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/BanAndOpProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/BanAndOpProcessor.java similarity index 58% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/player/BanAndOpProcessor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/BanAndOpProcessor.java index a008bd378..9d9cb350a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/BanAndOpProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/BanAndOpProcessor.java @@ -1,13 +1,14 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.player; +package com.djrapitops.plan.system.processing.processors.player; -import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.database.databases.operation.SaveOperations; import com.djrapitops.plugin.api.utility.log.Log; -import java.sql.SQLException; import java.util.UUID; /** @@ -30,9 +31,11 @@ public class BanAndOpProcessor extends PlayerProcessor { public void process() { UUID uuid = getUUID(); try { - Plan.getInstance().getDB().getUserInfoTable().updateOpAndBanStatus(uuid, opped, banned); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + SaveOperations save = Database.getActive().save(); + save.banStatus(uuid, banned); + save.opStatus(uuid, opped); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/BungeePlayerRegisterProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/BungeePlayerRegisterProcessor.java similarity index 63% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/player/BungeePlayerRegisterProcessor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/BungeePlayerRegisterProcessor.java index 9b1505836..9e2e3385d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/BungeePlayerRegisterProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/BungeePlayerRegisterProcessor.java @@ -1,14 +1,13 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.player; +package com.djrapitops.plan.system.processing.processors.player; -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.database.tables.UsersTable; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; import com.djrapitops.plugin.api.utility.log.Log; -import java.sql.SQLException; import java.util.UUID; /** @@ -30,14 +29,14 @@ public class BungeePlayerRegisterProcessor extends PlayerProcessor { @Override public void process() { UUID uuid = getUUID(); - UsersTable usersTable = PlanBungee.getInstance().getDB().getUsersTable(); + Database database = Database.getActive(); try { - if (usersTable.isRegistered(uuid)) { + if (database.check().isPlayerRegistered(uuid)) { return; } - usersTable.registerUser(uuid, registered, name); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + database.save().registerNewUser(uuid, registered, name); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/EndSessionProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/EndSessionProcessor.java similarity index 75% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/player/EndSessionProcessor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/EndSessionProcessor.java index 410d734a5..0fd989ffe 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/EndSessionProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/EndSessionProcessor.java @@ -1,10 +1,10 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.player; +package com.djrapitops.plan.system.processing.processors.player; -import com.djrapitops.plan.Plan; +import com.djrapitops.plan.system.cache.SessionCache; import java.util.UUID; @@ -25,6 +25,6 @@ public class EndSessionProcessor extends PlayerProcessor { @Override public void process() { UUID uuid = getUUID(); - Plan.getInstance().getDataCache().endSession(uuid, time); + SessionCache.getInstance().endSession(uuid, time); } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/FirstLeaveProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/FirstLeaveProcessor.java similarity index 61% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/player/FirstLeaveProcessor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/FirstLeaveProcessor.java index 68751ba95..088d7a0fb 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/FirstLeaveProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/FirstLeaveProcessor.java @@ -1,15 +1,16 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.player; +package com.djrapitops.plan.system.processing.processors.player; -import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.Actions; import com.djrapitops.plan.data.container.Action; -import com.djrapitops.plan.database.tables.Actions; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.databases.Database; import com.djrapitops.plugin.api.utility.log.Log; -import java.sql.SQLException; import java.util.UUID; /** @@ -29,14 +30,13 @@ public class FirstLeaveProcessor extends PlayerProcessor { @Override public void process() { - Plan plugin = Plan.getInstance(); UUID uuid = getUUID(); try { - plugin.getDB().getActionsTable().insertAction(uuid, leaveAction); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + Database.getActive().save().action(uuid, leaveAction); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } finally { - plugin.getDataCache().endFirstSessionActionTracking(uuid); + SessionCache.getInstance().endFirstSessionActionTracking(uuid); } } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/IPUpdateProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/IPUpdateProcessor.java similarity index 65% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/player/IPUpdateProcessor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/IPUpdateProcessor.java index 36b16b395..b5832411e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/IPUpdateProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/IPUpdateProcessor.java @@ -1,15 +1,15 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.player; +package com.djrapitops.plan.system.processing.processors.player; -import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.database.DBException; import com.djrapitops.plan.data.container.GeoInfo; -import com.djrapitops.plan.systems.cache.GeolocationCache; +import com.djrapitops.plan.system.cache.GeolocationCache; +import com.djrapitops.plan.system.database.databases.Database; import com.djrapitops.plugin.api.utility.log.Log; -import java.sql.SQLException; import java.util.UUID; /** @@ -33,9 +33,9 @@ public class IPUpdateProcessor extends PlayerProcessor { UUID uuid = getUUID(); String country = GeolocationCache.getCountry(ip); try { - Plan.getInstance().getDB().getIpsTable().saveGeoInfo(uuid, new GeoInfo(ip, country, time)); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + Database.getActive().save().geoInfo(uuid, new GeoInfo(ip, country, time)); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/KickProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/KickProcessor.java similarity index 61% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/player/KickProcessor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/KickProcessor.java index a3d3de46f..bccb6970f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/KickProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/KickProcessor.java @@ -1,13 +1,13 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.player; +package com.djrapitops.plan.system.processing.processors.player; -import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; import com.djrapitops.plugin.api.utility.log.Log; -import java.sql.SQLException; import java.util.UUID; /** @@ -24,9 +24,9 @@ public class KickProcessor extends PlayerProcessor { public void process() { UUID uuid = getUUID(); try { - Plan.getInstance().getDB().getUsersTable().kicked(uuid); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + Database.getActive().save().playerWasKicked(uuid); + } catch (DBException e) { + Log.toLog(this.getClass(), e); } } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/KillProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/KillProcessor.java similarity index 86% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/player/KillProcessor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/KillProcessor.java index ceffd2a07..95ede6639 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/KillProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/KillProcessor.java @@ -1,8 +1,8 @@ -package com.djrapitops.plan.systems.processing.player; +package com.djrapitops.plan.system.processing.processors.player; -import com.djrapitops.plan.Plan; import com.djrapitops.plan.data.container.PlayerKill; import com.djrapitops.plan.data.container.Session; +import com.djrapitops.plan.system.cache.SessionCache; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -43,9 +43,7 @@ public class KillProcessor extends PlayerProcessor { public void process() { UUID uuid = getUUID(); - Plan plugin = Plan.getInstance(); - - Optional cachedSession = plugin.getDataCache().getCachedSession(uuid); + Optional cachedSession = SessionCache.getCachedSession(uuid); if (!cachedSession.isPresent()) { return; } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/NameProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/NameProcessor.java new file mode 100644 index 000000000..26d727c75 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/NameProcessor.java @@ -0,0 +1,83 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.processing.processors.player; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.Actions; +import com.djrapitops.plan.data.container.Action; +import com.djrapitops.plan.system.cache.DataCache; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.utilities.html.HtmlUtils; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.util.List; +import java.util.UUID; + +/** + * Processor for updating name in the database if the player has changed it. + * + * @author Rsl1122 + * @since 4.0.0 + */ +public class NameProcessor extends PlayerProcessor { + + private final String playerName; + private final String displayName; + + public NameProcessor(UUID uuid, String playerName, String displayName) { + super(uuid); + this.playerName = playerName; + this.displayName = displayName; + } + + @Override + public void process() { + UUID uuid = getUUID(); + DataCache dataCache = DataCache.getInstance(); + String cachedName = dataCache.getName(uuid); + String cachedDisplayName = dataCache.getDisplayName(uuid); + + boolean sameAsCached = displayName.equals(cachedDisplayName); + if (playerName.equals(cachedName) && sameAsCached) { + return; + } + + Database database = Database.getActive(); + try { + cueNameChangeActionProcessor(uuid, database); + database.save().playerName(uuid, playerName); + + database.save().playerDisplayName(uuid, displayName); + } catch (DBException e) { + Log.toLog(this.getClass(), e); + } + + dataCache.updateNames(uuid, playerName, displayName); + } + + private void cueNameChangeActionProcessor(UUID uuid, Database db) throws DBException { + List nicknames = db.fetch().getNicknamesOfPlayerOnServer(uuid, ServerInfo.getServerUUID()); + if (nicknames.contains(displayName)) { + return; + } + + long time = MiscUtils.getTime(); + + Processor.queue(() -> { + String info = HtmlUtils.removeXSS(displayName); + + Action action = new Action(time, Actions.NEW_NICKNAME, info); + + try { + Database.getActive().save().action(uuid, action); + } catch (DBException e) { + Log.toLog(this.getClass(), e); + } + }); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/PlayerProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/PlayerProcessor.java similarity index 71% rename from Plan/src/main/java/com/djrapitops/plan/systems/processing/player/PlayerProcessor.java rename to Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/PlayerProcessor.java index 628c88c42..006e78218 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/PlayerProcessor.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/PlayerProcessor.java @@ -1,10 +1,10 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.processing.player; +package com.djrapitops.plan.system.processing.processors.player; -import com.djrapitops.plan.systems.processing.Processor; +import com.djrapitops.plan.system.processing.processors.ObjectProcessor; import java.util.UUID; @@ -15,7 +15,7 @@ import java.util.UUID; * * @author Rsl1122 */ -public abstract class PlayerProcessor extends Processor { +public abstract class PlayerProcessor extends ObjectProcessor { public PlayerProcessor(UUID uuid) { super(uuid); diff --git a/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/RegisterProcessor.java b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/RegisterProcessor.java new file mode 100644 index 000000000..a7ced4c86 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/processing/processors/player/RegisterProcessor.java @@ -0,0 +1,64 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.processing.processors.player; + +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.Actions; +import com.djrapitops.plan.data.container.Action; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.processing.processors.ObjectProcessor; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.UUID; + +/** + * Registers the user to the database and marks first session if the user has no actions. + * + * @author Rsl1122 + */ +public class RegisterProcessor extends PlayerProcessor { + + private final long registered; + private final long time; + private final int playersOnline; + private final String name; + private final ObjectProcessor[] afterProcess; + + public RegisterProcessor(UUID uuid, long registered, long time, String name, int playersOnline, ObjectProcessor... afterProcess) { + super(uuid); + this.registered = registered; + this.time = time; + this.playersOnline = playersOnline; + this.name = name; + this.afterProcess = afterProcess; + } + + @Override + public void process() { + UUID uuid = getUUID(); + Database db = Database.getActive(); + Verify.nullCheck(uuid, () -> new IllegalStateException("UUID was null")); + try { + if (!db.check().isPlayerRegistered(uuid)) { + db.save().registerNewUser(uuid, registered, name); + } + if (!db.check().isPlayerRegisteredOnThisServer(uuid)) { + db.save().registerNewUserOnThisServer(uuid, registered); + } + if (db.fetch().getActions(uuid).size() > 0) { + return; + } + SessionCache.getInstance().markFirstSession(uuid); + db.save().action(uuid, new Action(time, Actions.FIRST_SESSION, "Online: " + playersOnline + " Players")); + } catch (DBException e) { + Log.toLog(this.getClass(), e); + } finally { + Processor.queueMany(afterProcess); + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/settings/Permissions.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/Permissions.java similarity index 96% rename from Plan/src/main/java/com/djrapitops/plan/settings/Permissions.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/Permissions.java index 05eb804c7..8bba3e14a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/settings/Permissions.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/Permissions.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.settings; +package com.djrapitops.plan.system.settings; /** * Permissions class is used easily check every permission node. diff --git a/Plan/src/main/java/com/djrapitops/plan/system/settings/PlanErrorManager.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/PlanErrorManager.java new file mode 100644 index 000000000..8d16f3495 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/PlanErrorManager.java @@ -0,0 +1,51 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.settings; + +import com.djrapitops.plan.system.webserver.WebServer; +import com.djrapitops.plan.system.webserver.WebServerSystem; +import com.djrapitops.plugin.api.Check; +import com.djrapitops.plugin.api.utility.log.ErrorLogger; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.api.utility.log.errormanager.ErrorManager; + +import java.io.File; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Abstract Plugin Framework ErrorManager for logging Errors properly instead of a vague message. + * + * @author Rsl1122 + */ +public class PlanErrorManager extends ErrorManager { + + @Override + public void toLog(String source, Throwable e, Class callingPlugin) { + try { + File logsFolder = Log.getLogsFolder(callingPlugin); + Log.warn(source + " Caught: " + e, callingPlugin); + if (WebServerSystem.isWebServerEnabled()) { + Log.warn("Exception can be viewed at " + WebServer.getInstance().getAccessAddress() + "/debug"); + } else { + Log.warn("It has been logged to ErrorLog.txt"); + } + try { + if ((Check.isBukkitAvailable() && Check.isBungeeAvailable()) || Settings.DEV_MODE.isTrue()) { + Logger.getGlobal().log(Level.WARNING, source, e); + } + } catch (IllegalStateException ignored) { + /* Config system not initialized */ + } + ErrorLogger.logThrowable(e, logsFolder); + } catch (Exception exception) { + System.out.println("Failed to log error to file because of " + exception); + System.out.println("Error:"); + // Fallback + System.out.println("Fail Reason:"); + Logger.getGlobal().log(Level.WARNING, source, e); + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/settings/ServerSpecificSettings.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/ServerSpecificSettings.java similarity index 81% rename from Plan/src/main/java/com/djrapitops/plan/settings/ServerSpecificSettings.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/ServerSpecificSettings.java index 416894c33..006290806 100644 --- a/Plan/src/main/java/com/djrapitops/plan/settings/ServerSpecificSettings.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/ServerSpecificSettings.java @@ -1,11 +1,11 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.settings; +package com.djrapitops.plan.system.settings; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.PlanBungee; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.system.settings.config.ConfigSystem; import com.djrapitops.plugin.api.config.Config; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.utilities.Verify; @@ -24,24 +24,9 @@ import java.util.UUID; */ public class ServerSpecificSettings { - public void addOriginalBukkitSettings(PlanBungee plugin, UUID serverUUID, Map settings) { - try { - Config config = plugin.getMainConfig(); - if (!Verify.isEmpty(config.getString("Servers." + serverUUID + ".ServerName"))) { - return; - } - for (Map.Entry entry : settings.entrySet()) { - config.set("Servers." + serverUUID + "." + entry.getKey(), entry.getValue()); - } - config.save(); - } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); - } - } - - public static void updateSettings(Plan plugin, Map settings) { + public static void updateSettings(Map settings) { Log.debug("Checking new settings.."); - Config config = plugin.getMainConfig(); + Config config = ConfigSystem.getConfig(); boolean changedSomething = false; for (Map.Entry setting : settings.entrySet()) { @@ -67,12 +52,12 @@ public class ServerSpecificSettings { try { config.save(); } catch (IOException e) { - Log.toLog("ServerSpecificSettings / ConfigSave", e); + Log.toLog(ServerSpecificSettings.class, e); } Log.info("----------------------------------"); Log.info("The Received Bungee Settings changed the config values, restarting Plan.."); Log.info("----------------------------------"); - plugin.reloadPlugin(true); + PlanPlugin.getInstance().reloadPlugin(true); } else { Log.debug("Settings up to date"); } @@ -88,9 +73,25 @@ public class ServerSpecificSettings { } else if ("false".equalsIgnoreCase(value)) { return false; } + // Value is a string return value; } + public void addOriginalBukkitSettings(UUID serverUUID, Map settings) { + try { + Config config = ConfigSystem.getConfig(); + if (!Verify.isEmpty(config.getString("Servers." + serverUUID + ".ServerName"))) { + return; + } + for (Map.Entry entry : settings.entrySet()) { + config.set("Servers." + serverUUID + "." + entry.getKey(), entry.getValue()); + } + config.save(); + } catch (IOException e) { + Log.toLog(this.getClass(), e); + } + } + private String getPath(UUID serverUUID, Settings setting) { String path = "Servers." + serverUUID; switch (setting) { @@ -110,25 +111,25 @@ public class ServerSpecificSettings { } public boolean getBoolean(UUID serverUUID, Settings setting) { - Config config = PlanBungee.getInstance().getMainConfig(); + Config config = ConfigSystem.getConfig(); String path = getPath(serverUUID, setting); return config.getBoolean(path); } public String getString(UUID serverUUID, Settings setting) { - Config config = PlanBungee.getInstance().getMainConfig(); + Config config = ConfigSystem.getConfig(); String path = getPath(serverUUID, setting); return config.getString(path); } public Integer getInt(UUID serverUUID, Settings setting) { - Config config = PlanBungee.getInstance().getMainConfig(); + Config config = ConfigSystem.getConfig(); String path = getPath(serverUUID, setting); return config.getInt(path); } public void set(UUID serverUUID, Settings setting, Object value) throws IOException { - Config config = PlanBungee.getInstance().getMainConfig(); + Config config = ConfigSystem.getConfig(); String path = getPath(serverUUID, setting); config.set(path, value); config.save(); diff --git a/Plan/src/main/java/com/djrapitops/plan/settings/Settings.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/Settings.java similarity index 78% rename from Plan/src/main/java/com/djrapitops/plan/settings/Settings.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/Settings.java index ae1eeca8b..1b6c84345 100644 --- a/Plan/src/main/java/com/djrapitops/plan/settings/Settings.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/Settings.java @@ -1,9 +1,12 @@ -package com.djrapitops.plan.settings; +package com.djrapitops.plan.system.settings; -import com.djrapitops.plan.systems.file.config.ConfigSystem; +import com.djrapitops.plan.system.settings.config.ConfigSystem; import com.djrapitops.plugin.api.Check; import com.djrapitops.plugin.api.config.Config; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; +import java.io.IOException; import java.util.List; /** @@ -30,6 +33,7 @@ public enum Settings { ORDER_WORLD_PIE_BY_PERC("Customization.Display.OrderWorldPieByPercentage"), PLAYERTABLE_FOOTER("Customization.Display.PlayerTableFooter"), WEBSERVER_DISABLED("WebServer.DisableWebServer"), + FORMAT_DATE_RECENT_DAYS("Customization.Formatting.Dates.RecentDays"), // Integer WEBSERVER_PORT("WebServer.Port"), @@ -58,9 +62,14 @@ public enum Settings { WEBSERVER_CERTIFICATE_STOREPASS("WebServer.Security.SSL-Certificate.StorePass"), WEBSERVER_CERTIFICATE_ALIAS("WebServer.Security.SSL-Certificate.Alias"), EXTERNAL_WEBSERVER_LINK("WebServer.ExternalWebServerAddress"), + PLUGIN_BUYCRAFT_SECRET("Plugins.BuyCraft.Secret"), // SERVER_NAME("Server.ServerName"), // + FORMAT_DATE_FULL("Customization.Formatting.Dates.Full"), + FORMAT_DATE_NO_SECONDS("Customization.Formatting.Dates.NoSeconds"), + FORMAT_DATE_CLOCK("Customization.Formatting.Dates.JustClock"), + FORMAT_DATE_RECENT_DAYS_PATTERN("Customization.Formatting.Dates.RecentDays.DatePattern"), FORMAT_YEAR("Customization.Formatting.TimeAmount.Year"), FORMAT_YEARS("Customization.Formatting.TimeAmount.Years"), FORMAT_MONTH("Customization.Formatting.TimeAmount.Month"), @@ -94,20 +103,28 @@ public enum Settings { private static final ServerSpecificSettings serverSpecificSettings = new ServerSpecificSettings(); private final String configPath; - private Boolean value; + private Object tempValue; Settings(String path) { this.configPath = path; } + public static ServerSpecificSettings serverSpecific() { + if (!Check.isBungeeAvailable()) { + throw new IllegalStateException("Not supposed to call this method on Bukkit"); + } + + return serverSpecificSettings; + } + /** * If the settings is a boolean, this method should be used. * * @return Boolean value of the config setting, false if not boolean. */ public boolean isTrue() { - if (value != null) { - return value; + if (tempValue != null) { + return (Boolean) tempValue; } return getConfig().getBoolean(configPath); } @@ -116,8 +133,12 @@ public enum Settings { return !isTrue(); } - public void setValue(Boolean value) { - this.value = value; + public static void save() { + try { + ConfigSystem.getConfig().save(); + } catch (IOException e) { + Log.toLog(Settings.class, e); + } } /** @@ -127,6 +148,9 @@ public enum Settings { */ @Override public String toString() { + if (tempValue != null) { + return String.valueOf(tempValue); + } return getConfig().getString(configPath); } @@ -136,6 +160,9 @@ public enum Settings { * @return Integer value of the config setting */ public int getNumber() { + if (tempValue != null) { + return (Integer) tempValue; + } return getConfig().getInt(configPath); } @@ -153,15 +180,17 @@ public enum Settings { return configPath; } - private Config getConfig() { - return ConfigSystem.getInstance().getConfig(); + public void setTemporaryValue(Object value) { + this.tempValue = value; } - public static ServerSpecificSettings serverSpecific() { - if (!Check.isBungeeAvailable()) { - throw new IllegalStateException("Not supposed to call this method on Bukkit"); - } + public void set(Object value) { + getConfig().set(getPath(), value); + } - return serverSpecificSettings; + private Config getConfig() { + Config config = ConfigSystem.getConfig(); + Verify.nullCheck(config, () -> new IllegalStateException("Settings are not supposed to be called before ConfigSystem is Enabled!")); + return config; } } diff --git a/Plan/src/main/java/com/djrapitops/plan/settings/WorldAliasSettings.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/WorldAliasSettings.java similarity index 80% rename from Plan/src/main/java/com/djrapitops/plan/settings/WorldAliasSettings.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/WorldAliasSettings.java index fcc51ecce..544d54a0c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/settings/WorldAliasSettings.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/WorldAliasSettings.java @@ -1,10 +1,11 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.settings; +package com.djrapitops.plan.system.settings; -import com.djrapitops.plan.systems.file.config.ConfigSystem; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.settings.config.ConfigSystem; import com.djrapitops.plugin.api.config.Config; import com.djrapitops.plugin.api.config.ConfigNode; import com.djrapitops.plugin.api.utility.log.Log; @@ -37,7 +38,7 @@ public class WorldAliasSettings { } private ConfigNode getAliasSection() { - Config config = ConfigSystem.getInstance().getConfig(); + Config config = ConfigSystem.getConfig(); return config.getConfigNode(Settings.WORLD_ALIASES.getPath()); } @@ -54,11 +55,13 @@ public class WorldAliasSettings { String previousValue = aliasSect.getConfigNode(world).getValue(); if (Verify.isEmpty(previousValue)) { aliasSect.set(world, world); - } - try { - aliasSect.save(); - } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); + Processor.queue(() -> { + try { + aliasSect.save(); + } catch (IOException e) { + Log.toLog(this.getClass(), e); + } + }); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/file/config/PlanConfigSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/config/BukkitConfigSystem.java similarity index 58% rename from Plan/src/main/java/com/djrapitops/plan/systems/file/config/PlanConfigSystem.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/config/BukkitConfigSystem.java index 61959f718..c9d9f6849 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/file/config/PlanConfigSystem.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/config/BukkitConfigSystem.java @@ -2,18 +2,20 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.file.config; +package com.djrapitops.plan.system.settings.config; -import com.djrapitops.plan.systems.file.FileSystem; +import com.djrapitops.plan.system.file.FileSystem; import java.io.IOException; /** - * //TODO Class Javadoc Comment + * ConfigSystem for Bukkit. + *

+ * Bukkit and Bungee have different default config file inside the jar. * * @author Rsl1122 */ -public class PlanConfigSystem extends ConfigSystem { +public class BukkitConfigSystem extends ConfigSystem { @Override protected void copyDefaults() throws IOException { diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/file/config/PlanBungeeConfigSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/config/BungeeConfigSystem.java similarity index 59% rename from Plan/src/main/java/com/djrapitops/plan/systems/file/config/PlanBungeeConfigSystem.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/config/BungeeConfigSystem.java index 50b925f7a..f7efdf6ac 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/file/config/PlanBungeeConfigSystem.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/config/BungeeConfigSystem.java @@ -2,18 +2,20 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.file.config; +package com.djrapitops.plan.system.settings.config; -import com.djrapitops.plan.systems.file.FileSystem; +import com.djrapitops.plan.system.file.FileSystem; import java.io.IOException; /** - * //TODO Class Javadoc Comment + * ConfigSystem for Bungee. + *

+ * Bukkit and Bungee have different default config file inside the jar. * * @author Rsl1122 */ -public class PlanBungeeConfigSystem extends ConfigSystem { +public class BungeeConfigSystem extends ConfigSystem { @Override protected void copyDefaults() throws IOException { diff --git a/Plan/src/main/java/com/djrapitops/plan/system/settings/config/ConfigSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/config/ConfigSystem.java new file mode 100644 index 000000000..2cbcbe357 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/config/ConfigSystem.java @@ -0,0 +1,88 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.settings.config; + +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plan.system.file.FileSystem; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plugin.api.config.Config; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +import java.io.IOException; + +/** + * System for Config and other user customizable options. + * + * @author Rsl1122 + */ +public abstract class ConfigSystem implements SubSystem { + + protected Config config; + protected final Locale locale; + protected final Theme theme; + + public ConfigSystem() { + locale = new Locale(); + theme = new Theme(); + } + + public static ConfigSystem getInstance() { + ConfigSystem configSystem = PlanSystem.getInstance().getConfigSystem(); + Verify.nullCheck(configSystem, () -> new IllegalStateException("Config System has not been initialized.")); + return configSystem; + } + + public static Config getConfig() { + return getInstance().config; + } + + public Theme getThemeSystem() { + return getInstance().theme; + } + + @Override + public void enable() throws EnableException { + config = new Config(FileSystem.getConfigFile()); + try { + copyDefaults(); + config.save(); + Log.setDebugMode(Settings.DEBUG.toString()); + } catch (IOException e) { + throw new EnableException("Failed to save default config.", e); + } + locale.loadLocale(); + theme.enable(); + } + + /** + * Copies default values from file in jar to Config. + * + * @throws IOException If file can't be read or written. + */ + protected abstract void copyDefaults() throws IOException; + + @Override + public void disable() { + theme.disable(); + locale.unload(); + } + + public void reload() { + try { + config.read(); + } catch (IOException e) { + Log.toLog(ConfigSystem.class, e); + } + } + + public Locale getLocale() { + return getInstance().locale; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/settings/locale/Locale.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/locale/Locale.java similarity index 92% rename from Plan/src/main/java/com/djrapitops/plan/settings/locale/Locale.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/locale/Locale.java index edba74446..1080ab38d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/settings/locale/Locale.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/locale/Locale.java @@ -1,10 +1,10 @@ -package com.djrapitops.plan.settings.locale; +package com.djrapitops.plan.system.settings.locale; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.file.FileSystem; -import com.djrapitops.plan.systems.file.config.ConfigSystem; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.system.file.FileSystem; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.config.ConfigSystem; import com.djrapitops.plan.utilities.comparators.LocaleEntryComparator; import com.djrapitops.plan.utilities.comparators.StringLengthComparator; import com.djrapitops.plan.utilities.file.FileUtil; @@ -40,24 +40,21 @@ public class Locale { private final Map messages; public Locale() { - LocaleHolder.setLocale(this); messages = new EnumMap<>(Msg.class); } - public static void unload() { - Locale locale = LocaleHolder.getLocale(); - if (locale != null) { - locale.messages.clear(); - LocaleHolder.locale = null; - } + public static Locale getInstance() { + Locale locale = ConfigSystem.getInstance().getLocale(); + Verify.nullCheck(locale, () -> new IllegalStateException("Locale has not been initialized.")); + return locale; } public static Message get(Msg msg) { - Locale locale = LocaleHolder.getLocale(); - if (locale == null) { - throw new IllegalStateException("Locale has not been initialized."); - } - return locale.getMessage(msg); + return getInstance().getMessage(msg); + } + + public void unload() { + messages.clear(); } public void loadLocale() { @@ -77,7 +74,7 @@ public class Locale { loadFromResource("locale_" + locale + ".txt"); } } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } finally { Benchmark.stop("Enable", "Initializing locale"); } @@ -98,7 +95,7 @@ public class Locale { .collect(Collectors.toList()); Files.write(FileSystem.getLocaleFile().toPath(), lines, StandardCharsets.UTF_8); - Config config = ConfigSystem.getInstance().getConfig(); + Config config = ConfigSystem.getConfig(); config.set(Settings.WRITE_NEW_LOCALE.getPath(), false); config.save(); } @@ -120,7 +117,7 @@ public class Locale { String yellow = "§e"; String red = "§c"; String arrowsRight = DefaultMessages.ARROWS_RIGHT.parse(); - ColorScheme cs = MiscUtils.getIPlan().getColorScheme(); + ColorScheme cs = PlanPlugin.getInstance().getColorScheme(); String mCol = cs.getMainColor(); String sCol = cs.getSecondaryColor(); String tCol = cs.getTertiaryColor(); @@ -319,7 +316,7 @@ public class Locale { Log.error("Could not find file inside the jar: " + fileName); Log.info("Using Locale: Default (EN)"); } catch (Exception e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); Log.info("Using Locale: Default (EN)"); } } @@ -342,21 +339,4 @@ public class Locale { public Message getMessage(Msg msg) { return messages.getOrDefault(msg, new Message("")); } - - private static class LocaleHolder { - - private static Locale locale; - - private LocaleHolder() { - throw new IllegalStateException("Static variable holder class"); - } - - public static Locale getLocale() { - return locale; - } - - public static void setLocale(Locale locale) { - LocaleHolder.locale = locale; - } - } } diff --git a/Plan/src/main/java/com/djrapitops/plan/settings/locale/Message.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/locale/Message.java similarity index 95% rename from Plan/src/main/java/com/djrapitops/plan/settings/locale/Message.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/locale/Message.java index 4d60107f3..563ebfe6e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/settings/locale/Message.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/locale/Message.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.settings.locale; +package com.djrapitops.plan.system.settings.locale; import com.djrapitops.plugin.utilities.Verify; import org.apache.commons.lang3.text.StrSubstitutor; diff --git a/Plan/src/main/java/com/djrapitops/plan/settings/locale/Msg.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/locale/Msg.java similarity index 99% rename from Plan/src/main/java/com/djrapitops/plan/settings/locale/Msg.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/locale/Msg.java index 41d04c437..cf6c6c19a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/settings/locale/Msg.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/locale/Msg.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.settings.locale; +package com.djrapitops.plan.system.settings.locale; import java.util.Arrays; import java.util.Map; diff --git a/Plan/src/main/java/com/djrapitops/plan/system/settings/network/NetworkSettings.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/network/NetworkSettings.java new file mode 100644 index 000000000..e4ee48510 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/network/NetworkSettings.java @@ -0,0 +1,186 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.settings.network; + +import com.djrapitops.plan.api.exceptions.connection.UnsupportedTransferDatabaseException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.settings.ServerSpecificSettings; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.utilities.Base64Util; +import com.djrapitops.plugin.api.Check; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +/** + * Class for managing Config setting transfer from Bungee to Bukkit servers. + * + * @author Rsl1122 + */ +public class NetworkSettings { + + private static final String SPLIT = ";;SETTING;;"; + private static final String VAL_SPLIT = ";;VALUE;;"; + + public static void loadSettingsFromDB() { + if (Check.isBungeeAvailable()) { + return; + } + + if (Settings.BUNGEE_OVERRIDE_STANDALONE_MODE.isTrue() || Settings.BUNGEE_COPY_CONFIG.isFalse()) { + return; + } + + Processor.queue(() -> { + try { + new NetworkSettings().loadFromDatabase(); + } catch (DBException | UnsupportedTransferDatabaseException e) { + Log.toLog(NetworkSettings.class, e); + } + }); + } + + public static void placeSettingsToDB() { + if (!Check.isBungeeAvailable()) { + return; + } + + Processor.queue(() -> { + try { + new NetworkSettings().placeToDatabase(); + } catch (DBException | UnsupportedTransferDatabaseException e) { + Log.toLog(NetworkSettings.class, e); + } + }); + } + + public void loadFromDatabase() throws DBException, UnsupportedTransferDatabaseException { + Log.debug("NetworkSettings: Fetch Config settings from database.."); + Optional encodedConfigSettings = Database.getActive().transfer().getEncodedConfigSettings(); + + if (!encodedConfigSettings.isPresent()) { + Log.debug("NetworkSettings: No Config settings in database."); + return; + } + + String configSettings = Base64Util.decode(encodedConfigSettings.get()); + Map pathValueMap = getPathsAndValues(configSettings); + + Log.debug("NetworkSettings: Updating Settings"); + ServerSpecificSettings.updateSettings(pathValueMap); + } + + private Map getPathsAndValues(String configSettings) { + Map pathValueMap = new HashMap<>(); + + Log.debug("NetworkSettings: Reading Config String.."); + String[] settings = configSettings.split(SPLIT); + UUID thisServerUUID = ServerInfo.getServerUUID(); + for (String settingAndVal : settings) { + String[] split = settingAndVal.split(VAL_SPLIT); + String setting = split[0]; + String[] pathSplit = setting.split(":"); + String path; + if (pathSplit.length == 2) { + UUID serverUUID = UUID.fromString(pathSplit[0]); + if (!thisServerUUID.equals(serverUUID)) { + continue; + } + path = pathSplit[1]; + } else { + path = setting; + } + + String value = split[1]; + pathValueMap.put(path, value); + } + return pathValueMap; + } + + public void placeToDatabase() throws DBException, UnsupportedTransferDatabaseException { + Map configValues = getConfigValues(); + + Log.debug("NetworkSettings: Building Base64 String.."); + StringBuilder transferBuilder = new StringBuilder(); + int size = configValues.size(); + int i = 0; + for (Map.Entry entry : configValues.entrySet()) { + String path = entry.getKey(); + String value = entry.getValue().toString(); + + transferBuilder.append(path).append(VAL_SPLIT).append(value); + + if (i < size - 1) { + transferBuilder.append(SPLIT); + } + i++; + } + + String base64 = Base64Util.encode(transferBuilder.toString()); + + Log.debug("NetworkSettings: Saving Config settings to database.."); + Database.getActive().transfer().storeConfigSettings(base64); + } + + private Map getConfigValues() throws DBException { + Log.debug("NetworkSettings: Loading Config Values.."); + Map configValues = new HashMap<>(); + addConfigValue(configValues, Settings.DB_TYPE, "mysql"); + Settings[] sameStrings = new Settings[]{ + Settings.DB_HOST, Settings.DB_USER, Settings.DB_PASS, + Settings.DB_DATABASE, Settings.FORMAT_DECIMALS, Settings.FORMAT_SECONDS, + Settings.FORMAT_DAY, Settings.FORMAT_DAYS, Settings.FORMAT_HOURS, + Settings.FORMAT_MINUTES, Settings.FORMAT_MONTHS, Settings.FORMAT_MONTH, + Settings.FORMAT_YEAR, Settings.FORMAT_YEARS, Settings.FORMAT_ZERO_SECONDS + }; + Log.debug("NetworkSettings: Adding Config Values.."); + for (Settings setting : sameStrings) { + addConfigValue(configValues, setting, setting.toString()); + } + addConfigValue(configValues, Settings.DB_PORT, Settings.DB_PORT.getNumber()); + addServerSpecificValues(configValues); + return configValues; + } + + private void addConfigValue(Map configValues, Settings setting, Object value) { + if (value != null) { + configValues.put(setting.getPath(), value); + } + } + + private void addConfigValue(Map configValues, UUID serverUUID, Settings setting, Object value) { + if (value != null) { + configValues.put(serverUUID + ":" + setting.getPath(), value); + } + } + + private void addServerSpecificValues(Map configValues) throws DBException { + Log.debug("NetworkSettings: Adding Server-specific Config Values.."); + ServerSpecificSettings settings = Settings.serverSpecific(); + + for (UUID serverUUID : Database.getActive().fetch().getServerUUIDs()) { + String theme = settings.getString(serverUUID, Settings.THEME_BASE); + Integer port = settings.getInt(serverUUID, Settings.WEBSERVER_PORT); + String name = settings.getString(serverUUID, Settings.SERVER_NAME); + + if (!Verify.isEmpty(theme)) { + addConfigValue(configValues, serverUUID, Settings.THEME_BASE, theme); + } + if (port != null && port != 0) { + addConfigValue(configValues, serverUUID, Settings.WEBSERVER_PORT, port); + } + if (!Verify.isEmpty(name)) { + addConfigValue(configValues, serverUUID, Settings.SERVER_NAME, name); + } + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/settings/theme/PlanColorScheme.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/theme/PlanColorScheme.java similarity index 91% rename from Plan/src/main/java/com/djrapitops/plan/settings/theme/PlanColorScheme.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/theme/PlanColorScheme.java index 9dfcee5c1..f28f6a8dd 100644 --- a/Plan/src/main/java/com/djrapitops/plan/settings/theme/PlanColorScheme.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/theme/PlanColorScheme.java @@ -2,9 +2,9 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.settings.theme; +package com.djrapitops.plan.system.settings.theme; -import com.djrapitops.plan.settings.Settings; +import com.djrapitops.plan.system.settings.Settings; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.settings.ColorScheme; diff --git a/Plan/src/main/java/com/djrapitops/plan/settings/theme/Theme.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/theme/Theme.java similarity index 74% rename from Plan/src/main/java/com/djrapitops/plan/settings/theme/Theme.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/theme/Theme.java index 32f0c0af7..e396a02be 100644 --- a/Plan/src/main/java/com/djrapitops/plan/settings/theme/Theme.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/theme/Theme.java @@ -2,12 +2,13 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.settings.theme; +package com.djrapitops.plan.system.settings.theme; -import com.djrapitops.plan.api.exceptions.PlanEnableException; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.SubSystem; -import com.djrapitops.plan.systems.Systems; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.config.ConfigSystem; import com.djrapitops.plugin.api.utility.EnumUtility; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.utilities.Verify; @@ -27,21 +28,35 @@ public class Theme implements SubSystem { private ThemeConfig config; public static Theme getInstance() { - return Systems.getInstance().getThemeSystem(); + Theme themeSystem = ConfigSystem.getInstance().getThemeSystem(); + Verify.nullCheck(themeSystem, () -> new IllegalStateException("Theme System has not been initialized.")); + return themeSystem; + } + + public static String getValue(ThemeVal variable) { + try { + return getInstance().getThemeValue(variable); + } catch (NullPointerException | IllegalStateException e) { + return variable.getDefaultValue(); + } + } + + public static String replaceColors(String resourceString) { + return getInstance().replaceThemeColors(resourceString); } @Override - public void init() throws PlanEnableException { + public void enable() throws EnableException { String themeName = Settings.THEME_BASE.toString(); try { config = new ThemeConfig(themeName); } catch (IOException e) { - throw new PlanEnableException("Default theme could not be loaded.", e); + throw new EnableException("Default theme could not be loaded.", e); } } @Override - public void close() { + public void disable() { } @@ -55,6 +70,10 @@ public class Theme implements SubSystem { } else { return value; } + } catch (IllegalStateException e) { + if (!PlanPlugin.getInstance().isReloading()) { + Log.error("Something went wrong with getting variable " + variable.name() + " for: " + path); + } } catch (Exception | NoSuchFieldError e) { Log.error("Something went wrong with getting variable " + variable.name() + " for: " + path); } @@ -92,12 +111,4 @@ public class Theme implements SubSystem { public String getThemeValue(ThemeVal color) { return config.getString(color.getThemePath()); } - - public static String getValue(ThemeVal variable) { - return getInstance().getThemeValue(variable); - } - - public static String replaceColors(String resourceString) { - return getInstance().replaceThemeColors(resourceString); - } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/settings/theme/ThemeConfig.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/theme/ThemeConfig.java similarity index 85% rename from Plan/src/main/java/com/djrapitops/plan/settings/theme/ThemeConfig.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/theme/ThemeConfig.java index aeff185d0..397b75862 100644 --- a/Plan/src/main/java/com/djrapitops/plan/settings/theme/ThemeConfig.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/theme/ThemeConfig.java @@ -2,15 +2,15 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.settings.theme; +package com.djrapitops.plan.system.settings.theme; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.utilities.file.FileUtil; import com.djrapitops.plugin.api.config.Config; import com.djrapitops.plugin.api.utility.log.Log; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.List; @@ -33,7 +33,7 @@ public class ThemeConfig extends Config { private static List getDefaults(String fileName) throws IOException { String fileLocation = getFileLocation(fileName); - IPlan plugin = MiscUtils.getIPlan(); + PlanPlugin plugin = PlanPlugin.getInstance(); try { return FileUtil.lines(plugin, fileLocation); } catch (IOException e) { @@ -69,15 +69,14 @@ public class ThemeConfig extends Config { } } - private static File getConfigFile() throws IOException { - File folder = MiscUtils.getIPlan().getDataFolder(); + File folder = PlanPlugin.getInstance().getDataFolder(); if (!folder.exists()) { folder.mkdirs(); } File themeFile = new File(folder, "theme.yml"); - if (!themeFile.exists()) { - themeFile.createNewFile(); + if (!themeFile.exists() && !themeFile.createNewFile()) { + throw new FileNotFoundException("Failed to create theme.yml"); } return themeFile; } diff --git a/Plan/src/main/java/com/djrapitops/plan/settings/theme/ThemeVal.java b/Plan/src/main/java/com/djrapitops/plan/system/settings/theme/ThemeVal.java similarity index 98% rename from Plan/src/main/java/com/djrapitops/plan/settings/theme/ThemeVal.java rename to Plan/src/main/java/com/djrapitops/plan/system/settings/theme/ThemeVal.java index 42f475838..907e3cc8e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/settings/theme/ThemeVal.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/settings/theme/ThemeVal.java @@ -2,7 +2,7 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.settings.theme; +package com.djrapitops.plan.system.settings.theme; /** * Enum class used for getting the Html colors that match the config settings. diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/BukkitTaskSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/BukkitTaskSystem.java new file mode 100644 index 000000000..087ad6744 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/BukkitTaskSystem.java @@ -0,0 +1,84 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.tasks; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plan.system.tasks.bukkit.*; +import com.djrapitops.plan.utilities.file.export.HtmlExport; +import com.djrapitops.plugin.api.Benchmark; +import com.djrapitops.plugin.api.Check; +import com.djrapitops.plugin.api.TimeAmount; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.task.ITask; +import com.djrapitops.plugin.task.RunnableFactory; +import org.bukkit.Bukkit; + +/** + * TaskSystem responsible for registering tasks for Bukkit. + * + * @author Rsl1122 + */ +public class BukkitTaskSystem extends TaskSystem { + + private ITask bootAnalysisTask; + + private final Plan plugin; + + public BukkitTaskSystem(Plan plugin) { + tpsCountTimer = Check.isPaperAvailable() + ? new PaperTPSCountTimer(plugin) + : new BukkitTPSCountTimer(plugin); + + this.plugin = plugin; + } + + @Override + public void enable() { + registerTasks(); + } + + @Override + public void disable() { + super.disable(); + Bukkit.getScheduler().cancelTasks(plugin); + } + + private void registerTasks() { + Benchmark.start("Task Registration"); + + // Analysis refresh settings + int analysisRefreshMinutes = Settings.ANALYSIS_AUTO_REFRESH.getNumber(); + boolean analysisRefreshTaskIsEnabled = analysisRefreshMinutes > 0; + long analysisPeriod = analysisRefreshMinutes * TimeAmount.MINUTE.ticks(); + + Log.info(Locale.get(Msg.ENABLE_BOOT_ANALYSIS_INFO).toString()); + + registerTask(tpsCountTimer).runTaskTimer(1000, TimeAmount.SECOND.ticks()); + registerTask(new NetworkPageRefreshTask()).runTaskTimerAsynchronously(20L, 5L * TimeAmount.MINUTE.ticks()); + bootAnalysisTask = registerTask(new BootAnalysisTask()).runTaskLaterAsynchronously(30L * TimeAmount.SECOND.ticks()); + + if (analysisRefreshTaskIsEnabled) { + registerTask(new PeriodicAnalysisTask()).runTaskTimerAsynchronously(analysisPeriod, analysisPeriod); + } + if (Settings.ANALYSIS_EXPORT.isTrue()) { + RunnableFactory.createNew(new HtmlExport(plugin)).runTaskAsynchronously(); + } + Benchmark.stop("Enable", "Task Registration"); + } + + public void cancelBootAnalysis() { + try { + if (bootAnalysisTask != null) { + bootAnalysisTask.cancel(); + bootAnalysisTask = null; + } + } catch (Exception ignored) { + /* Ignored */ + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/BungeeTaskSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/BungeeTaskSystem.java new file mode 100644 index 000000000..bd71063fd --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/BungeeTaskSystem.java @@ -0,0 +1,42 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.tasks; + +import com.djrapitops.plan.PlanBungee; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.tasks.bukkit.NetworkPageRefreshTask; +import com.djrapitops.plan.system.tasks.bungee.BungeeTPSCountTimer; +import com.djrapitops.plan.system.tasks.bungee.EnableConnectionTask; +import com.djrapitops.plan.utilities.file.export.HtmlExport; +import com.djrapitops.plugin.api.TimeAmount; + +/** + * TaskSystem responsible for registering tasks for Bungee. + * + * @author Rsl1122 + */ +public class BungeeTaskSystem extends TaskSystem { + + private final PlanBungee plugin; + + public BungeeTaskSystem(PlanBungee plugin) { + tpsCountTimer = new BungeeTPSCountTimer(plugin); + this.plugin = plugin; + } + + @Override + public void enable() { + registerTasks(); + } + + private void registerTasks() { + registerTask(new EnableConnectionTask()).runTaskAsynchronously(); + registerTask(tpsCountTimer).runTaskTimerAsynchronously(1000, TimeAmount.SECOND.ticks()); + registerTask(new NetworkPageRefreshTask()).runTaskTimerAsynchronously(1500, TimeAmount.MINUTE.ticks()); + if (Settings.ANALYSIS_EXPORT.isTrue()) { + registerTask(new HtmlExport(plugin)).runTaskAsynchronously(); + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/TPSCountTimer.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/TPSCountTimer.java new file mode 100644 index 000000000..4a3d02928 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/TPSCountTimer.java @@ -0,0 +1,50 @@ +package com.djrapitops.plan.system.tasks; + +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.data.container.TPS; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.processing.processors.TPSInsertProcessor; +import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plugin.task.AbsRunnable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class responsible for calculating TPS every second. + * + * @author Rsl1122 + */ +public abstract class TPSCountTimer extends AbsRunnable { + + protected final T plugin; + protected final List history; + + + protected int latestPlayersOnline = 0; + + public TPSCountTimer(T plugin) { + super("TPSCountTimer"); + this.plugin = plugin; + history = new ArrayList<>(); + } + + @Override + public void run() { + long nanoTime = System.nanoTime(); + long now = MiscUtils.getTime(); + + addNewTPSEntry(nanoTime, now); + + if (history.size() >= 60) { + Processor.queue(new TPSInsertProcessor(new ArrayList<>(history))); + history.clear(); + } + } + + public abstract void addNewTPSEntry(long nanoTime, long now); + + public int getLatestPlayersOnline() { + return latestPlayersOnline; + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/tasks/TaskSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/TaskSystem.java similarity index 68% rename from Plan/src/main/java/com/djrapitops/plan/systems/tasks/TaskSystem.java rename to Plan/src/main/java/com/djrapitops/plan/system/tasks/TaskSystem.java index 487c20709..6e237124b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/tasks/TaskSystem.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/TaskSystem.java @@ -2,18 +2,20 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.tasks; +package com.djrapitops.plan.system.tasks; -import com.djrapitops.plan.systems.SubSystem; -import com.djrapitops.plan.systems.Systems; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; import com.djrapitops.plugin.api.systems.TaskCenter; import com.djrapitops.plugin.task.AbsRunnable; import com.djrapitops.plugin.task.IRunnable; import com.djrapitops.plugin.task.RunnableFactory; /** - * //TODO Class Javadoc Comment + * TaskSystem that registers tasks that were previously registered inside Plugin classes. + * + * Subclasses register actual tasks. * * @author Rsl1122 */ @@ -22,7 +24,7 @@ public abstract class TaskSystem implements SubSystem { protected TPSCountTimer tpsCountTimer; public static TaskSystem getInstance() { - return Systems.getInstance().getTaskSystem(); + return PlanSystem.getInstance().getTaskSystem(); } protected IRunnable registerTask(AbsRunnable runnable) { @@ -35,8 +37,8 @@ public abstract class TaskSystem implements SubSystem { } @Override - public void close() { - TaskCenter.cancelAllKnownTasks(MiscUtils.getIPlan().getClass()); + public void disable() { + TaskCenter.cancelAllKnownTasks(PlanPlugin.getInstance().getClass()); } public TPSCountTimer getTpsCountTimer() { diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/BootAnalysisTask.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/BootAnalysisTask.java new file mode 100644 index 000000000..90cd49488 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/BootAnalysisTask.java @@ -0,0 +1,38 @@ +package com.djrapitops.plan.system.tasks.bukkit; + +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.info.connection.WebExceptionLogger; +import com.djrapitops.plan.system.info.request.GenerateAnalysisPageRequest; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plan.utilities.analysis.Analysis; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.task.AbsRunnable; + +public class BootAnalysisTask extends AbsRunnable { + + public BootAnalysisTask() { + super(BootAnalysisTask.class.getSimpleName()); + } + + @Override + public void run() { + try { + String bootAnalysisRunMsg = Locale.get(Msg.ENABLE_BOOT_ANALYSIS_RUN_INFO).toString(); + Log.info(bootAnalysisRunMsg); + if (!Analysis.isAnalysisBeingRun()) { + WebExceptionLogger.logIfOccurs(this.getClass(), () -> + InfoSystem.getInstance().sendRequest(new GenerateAnalysisPageRequest(ServerInfo.getServerUUID())) + ); + } + } catch (IllegalStateException e) { + if (!PlanPlugin.getInstance().isReloading()) { + Log.toLog(this.getClass(), e); + } + } finally { + cancel(); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/BukkitTPSCountTimer.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/BukkitTPSCountTimer.java new file mode 100644 index 000000000..68666096c --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/BukkitTPSCountTimer.java @@ -0,0 +1,113 @@ +package com.djrapitops.plan.system.tasks.bukkit; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.data.container.TPS; +import com.djrapitops.plan.system.tasks.TPSCountTimer; +import com.djrapitops.plan.utilities.analysis.MathUtils; +import com.djrapitops.plugin.api.TimeAmount; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; + +public class BukkitTPSCountTimer extends TPSCountTimer { + + private long lastCheckNano; + + public BukkitTPSCountTimer(Plan plugin) { + super(plugin); + lastCheckNano = -1; + } + + @Override + public void addNewTPSEntry(long nanoTime, long now) { + long diff = nanoTime - lastCheckNano; + + lastCheckNano = nanoTime; + + if (diff > nanoTime) { // First run's diff = nanoTime + 1, no calc possible. + Log.debug("First run of TPSCountTimer Task."); + return; + } + + history.add(calculateTPS(diff, now)); + } + + /** + * Calculates the TPS + * + * @param diff The time difference between the last run and the new run + * @param now The time right now + * @return the TPS + */ + private TPS calculateTPS(long diff, long now) { + OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); + int availableProcessors = operatingSystemMXBean.getAvailableProcessors(); + double averageCPUUsage = MathUtils.round(operatingSystemMXBean.getSystemLoadAverage() / availableProcessors * 100.0); + + if (averageCPUUsage < 0) { // If unavailable, getSystemLoadAverage() returns -1 + averageCPUUsage = -1; + } + + Runtime runtime = Runtime.getRuntime(); + + long totalMemory = runtime.totalMemory(); + long usedMemory = (totalMemory - runtime.freeMemory()) / 1000000; + + int playersOnline = plugin.getServer().getOnlinePlayers().size(); + latestPlayersOnline = playersOnline; + int loadedChunks = getLoadedChunks(); + int entityCount; + + entityCount = getEntityCount(); + + // 40ms removed because the run appears to take 40-50ms, screwing the tps. + long fortyMsAsNs = TimeAmount.MILLISECOND.ns() * 40L; + return getTPS(diff - fortyMsAsNs, now, averageCPUUsage, usedMemory, entityCount, loadedChunks, playersOnline); + } + + /** + * Gets the TPS for Spigot / Bukkit + * + * @param diff The difference between the last run and this run + * @param now The time right now + * @param cpuUsage The usage of the CPU + * @param playersOnline The amount of players that are online + * @return the TPS + */ + protected TPS getTPS(long diff, long now, double cpuUsage, long usedMemory, int entityCount, int chunksLoaded, int playersOnline) { + long difference = diff; + if (difference < TimeAmount.SECOND.ns()) { // No tick count above 20 + difference = TimeAmount.SECOND.ns(); + } + + long twentySeconds = 20L * TimeAmount.SECOND.ns(); + while (difference > twentySeconds) { + // Add 0 TPS since more than 20 ticks has passed. + history.add(new TPS(now, 0, playersOnline, cpuUsage, usedMemory, entityCount, chunksLoaded)); + difference -= twentySeconds; + } + + double tpsN = twentySeconds * 1.0 / difference; + + return new TPS(now, tpsN, playersOnline, cpuUsage, usedMemory, entityCount, chunksLoaded); + } + + /** + * Gets the amount of loaded chunks + * + * @return amount of loaded chunks + */ + private int getLoadedChunks() { + return plugin.getServer().getWorlds().stream().mapToInt(world -> world.getLoadedChunks().length).sum(); + } + + /** + * Gets the amount of entities on the server for Bukkit / Spigot + * + * @return amount of entities + */ + protected int getEntityCount() { + return plugin.getServer().getWorlds().stream().mapToInt(world -> world.getEntities().size()).sum(); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/NetworkPageRefreshTask.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/NetworkPageRefreshTask.java new file mode 100644 index 000000000..6589bf4c1 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/NetworkPageRefreshTask.java @@ -0,0 +1,17 @@ +package com.djrapitops.plan.system.tasks.bukkit; + +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.info.connection.WebExceptionLogger; +import com.djrapitops.plugin.task.AbsRunnable; + +public class NetworkPageRefreshTask extends AbsRunnable { + + public NetworkPageRefreshTask() { + super(NetworkPageRefreshTask.class.getSimpleName()); + } + + @Override + public void run() { + WebExceptionLogger.logIfOccurs(this.getClass(), () -> InfoSystem.getInstance().updateNetworkPage()); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/PaperTPSCountTimer.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/PaperTPSCountTimer.java new file mode 100644 index 000000000..695551514 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/PaperTPSCountTimer.java @@ -0,0 +1,35 @@ +package com.djrapitops.plan.system.tasks.bukkit; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.data.container.TPS; +import com.djrapitops.plan.utilities.analysis.MathUtils; +import org.bukkit.World; + +public class PaperTPSCountTimer extends BukkitTPSCountTimer { + + public PaperTPSCountTimer(Plan plugin) { + super(plugin); + } + + @Override + protected TPS getTPS(long diff, long now, double cpuUsage, long usedMemory, int entityCount, int chunksLoaded, int playersOnline) { + double tps = plugin.getServer().getTPS()[0]; + + if (tps > 20) { + tps = 20; + } + + tps = MathUtils.round(tps); + + return new TPS(now, tps, playersOnline, cpuUsage, usedMemory, entityCount, chunksLoaded); + } + + @Override + protected int getEntityCount() { + try { + return plugin.getServer().getWorlds().stream().mapToInt(World::getEntityCount).sum(); + } catch (BootstrapMethodError | NoSuchMethodError e) { + return super.getEntityCount(); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/PeriodicAnalysisTask.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/PeriodicAnalysisTask.java new file mode 100644 index 000000000..ac4c04f17 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bukkit/PeriodicAnalysisTask.java @@ -0,0 +1,34 @@ +package com.djrapitops.plan.system.tasks.bukkit; + +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.info.connection.WebExceptionLogger; +import com.djrapitops.plan.system.info.request.GenerateAnalysisPageRequest; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.utilities.analysis.Analysis; +import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.task.AbsRunnable; + +public class PeriodicAnalysisTask extends AbsRunnable { + + public PeriodicAnalysisTask() { + super(PeriodicAnalysisTask.class.getSimpleName()); + } + + @Override + public void run() { + try { + if (!Analysis.isAnalysisBeingRun()) { + WebExceptionLogger.logIfOccurs(this.getClass(), () -> + InfoSystem.getInstance().sendRequest(new GenerateAnalysisPageRequest(ServerInfo.getServerUUID())) + ); + } + } catch (IllegalStateException e) { + if (!PlanPlugin.getInstance().isReloading()) { + Log.toLog(this.getClass(), e); + } + } finally { + cancel(); + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/bungee/BungeeTPSCountTimer.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bungee/BungeeTPSCountTimer.java new file mode 100644 index 000000000..058ca284e --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bungee/BungeeTPSCountTimer.java @@ -0,0 +1,26 @@ +package com.djrapitops.plan.system.tasks.bungee; + +import com.djrapitops.plan.PlanBungee; +import com.djrapitops.plan.data.container.TPS; +import com.djrapitops.plan.data.container.builders.TPSBuilder; +import com.djrapitops.plan.system.tasks.TPSCountTimer; + +public class BungeeTPSCountTimer extends TPSCountTimer { + + public BungeeTPSCountTimer(PlanBungee plugin) { + super(plugin); + } + + @Override + public void addNewTPSEntry(long nanoTime, long now) { + int onlineCount = plugin.getProxy().getOnlineCount(); + TPS tps = TPSBuilder.get() + .date(now) + .skipTPS() + .playersOnline(onlineCount) + .toTPS(); + + history.add(tps); + latestPlayersOnline = onlineCount; + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/tasks/bungee/EnableConnectionTask.java b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bungee/EnableConnectionTask.java new file mode 100644 index 000000000..33204938b --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/tasks/bungee/EnableConnectionTask.java @@ -0,0 +1,21 @@ +package com.djrapitops.plan.system.tasks.bungee; + +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.info.connection.WebExceptionLogger; +import com.djrapitops.plan.system.info.request.GenerateNetworkPageContentRequest; +import com.djrapitops.plugin.task.AbsRunnable; + +public class EnableConnectionTask extends AbsRunnable { + + public EnableConnectionTask() { + super(EnableConnectionTask.class.getSimpleName()); + } + + @Override + public void run() { + WebExceptionLogger.logIfOccurs(this.getClass(), + () -> ConnectionSystem.getInstance().sendWideInfoRequest(new GenerateNetworkPageContentRequest()) + ); + cancel(); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/update/VersionCheckSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/update/VersionCheckSystem.java similarity index 63% rename from Plan/src/main/java/com/djrapitops/plan/systems/update/VersionCheckSystem.java rename to Plan/src/main/java/com/djrapitops/plan/system/update/VersionCheckSystem.java index cc2a38476..5051d2441 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/update/VersionCheckSystem.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/update/VersionCheckSystem.java @@ -2,19 +2,20 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.update; +package com.djrapitops.plan.system.update; -import com.djrapitops.plan.systems.SubSystem; -import com.djrapitops.plan.systems.Systems; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; import com.djrapitops.plugin.api.Priority; import com.djrapitops.plugin.api.systems.NotificationCenter; import com.djrapitops.plugin.api.utility.Version; import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; import java.io.IOException; /** - * //TODO Class Javadoc Comment + * System for checking if new Version is available when the System initializes. * * @author Rsl1122 */ @@ -28,11 +29,21 @@ public class VersionCheckSystem implements SubSystem { } public static VersionCheckSystem getInstance() { - return Systems.getInstance().getVersionCheckSystem(); + VersionCheckSystem versionCheckSystem = PlanSystem.getInstance().getVersionCheckSystem(); + Verify.nullCheck(versionCheckSystem, () -> new IllegalStateException("Version Check system has not been initialized.")); + return versionCheckSystem; + } + + public static boolean isNewVersionAvailable() { + return getInstance().newVersionAvailable; + } + + public static String getCurrentVersion() { + return getInstance().currentVersion; } @Override - public void init() { + public void enable() { checkForNewVersion(); } @@ -40,12 +51,18 @@ public class VersionCheckSystem implements SubSystem { String githubVersionUrl = "https://raw.githubusercontent.com/Rsl1122/Plan-PlayerAnalytics/master/Plan/src/main/resources/plugin.yml"; String spigotUrl = "https://www.spigotmc.org/resources/plan-player-analytics.32536/"; try { - newVersionAvailable = Version.checkVersion(currentVersion, githubVersionUrl) - || Version.checkVersion(currentVersion, spigotUrl); + newVersionAvailable = Version.checkVersion(currentVersion, githubVersionUrl); + if (!newVersionAvailable) { + try { + newVersionAvailable = Version.checkVersion(currentVersion, spigotUrl); + } catch (NoClassDefFoundError ignore) { + /* 1.7.4 Does not have google gson JSONParser */ + } + } if (newVersionAvailable) { String newVersionNotification = "New Version is available at " + spigotUrl; Log.infoColor("§a----------------------------------------"); - Log.infoColor("§a"+newVersionNotification); + Log.infoColor("§a" + newVersionNotification); Log.infoColor("§a----------------------------------------"); NotificationCenter.addNotification(Priority.HIGH, newVersionNotification); } else { @@ -57,11 +74,7 @@ public class VersionCheckSystem implements SubSystem { } @Override - public void close() { + public void disable() { /* Does not need to be closed */ } - - public static boolean isNewVersionAvailable() { - return getInstance().newVersionAvailable; - } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/Request.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/Request.java similarity index 57% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/Request.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/Request.java index 4057f70c2..d5f9aacb4 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/Request.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/Request.java @@ -1,15 +1,14 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.webserver; +package com.djrapitops.plan.system.webserver; -import com.djrapitops.plugin.utilities.Verify; -import com.sun.net.httpserver.Headers; +import com.djrapitops.plan.system.webserver.auth.Authentication; import com.sun.net.httpserver.HttpExchange; import java.io.InputStream; -import java.util.List; +import java.util.Optional; /** * Represents a HttpExchange Request. @@ -19,38 +18,27 @@ import java.util.List; * @author Rsl1122 */ public class Request { - private String auth; private final String requestMethod; private final String target; - private final HttpExchange exchange; + private final String remoteAddress; + private Authentication auth; public Request(HttpExchange exchange) { this.requestMethod = exchange.getRequestMethod(); this.target = exchange.getRequestURI().toString(); + remoteAddress = exchange.getRemoteAddress().getAddress().getHostAddress(); + this.exchange = exchange; - setAuth(exchange.getRequestHeaders()); } - public String getAuth() { - return auth; + public Optional getAuth() { + return Optional.ofNullable(auth); } - public void setAuth(Headers requestHeaders) { - List authorization = requestHeaders.get("Authorization"); - if (Verify.isEmpty(authorization)) { - return; - } - - String authLine = authorization.get(0); - if (authLine.contains("Basic ")) { - auth = authLine.split(" ")[1]; - } - } - - public boolean hasAuth() { - return auth != null; + public void setAuth(Authentication authentication) { + auth = authentication; } public String getRequestMethod() { @@ -61,10 +49,6 @@ public class Request { return target; } - public boolean isAPIRequest() { - return "POST".equals(requestMethod); - } - public InputStream getRequestBody() { return exchange.getRequestBody(); } @@ -73,4 +57,8 @@ public class Request { public String toString() { return "Request:" + requestMethod + " " + target; } + + public String getRemoteAddress() { + return remoteAddress; + } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/RequestHandler.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/RequestHandler.java similarity index 52% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/RequestHandler.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/RequestHandler.java index 8959da89d..f699040b7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/RequestHandler.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/RequestHandler.java @@ -1,20 +1,22 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.webserver; +package com.djrapitops.plan.system.webserver; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.webserver.response.PromptAuthorizationResponse; -import com.djrapitops.plan.systems.webserver.response.Response; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.webserver.auth.Authentication; +import com.djrapitops.plan.system.webserver.auth.BasicAuthentication; +import com.djrapitops.plan.system.webserver.response.PromptAuthorizationResponse; +import com.djrapitops.plan.system.webserver.response.Response; import com.djrapitops.plugin.api.Benchmark; import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; -import java.io.IOException; +import java.util.List; /** * HttpHandler for WebServer request management. @@ -25,14 +27,17 @@ public class RequestHandler implements HttpHandler { private final ResponseHandler responseHandler; - RequestHandler(IPlan plugin, WebServer webServer) { - responseHandler = new ResponseHandler(plugin, webServer); + RequestHandler(WebServer webServer) { + responseHandler = new ResponseHandler(webServer); } @Override public void handle(HttpExchange exchange) { + Headers requestHeaders = exchange.getRequestHeaders(); Headers responseHeaders = exchange.getResponseHeaders(); Request request = new Request(exchange); + request.setAuth(getAuthorization(requestHeaders)); + String requestString = request.toString(); Benchmark.start("", requestString); int responseCode = -1; @@ -42,19 +47,36 @@ public class RequestHandler implements HttpHandler { if (response instanceof PromptAuthorizationResponse) { responseHeaders.set("WWW-Authenticate", "Basic realm=\"/\";"); } + response.setResponseHeaders(responseHeaders); response.send(exchange); - } catch (IOException e) { + } catch (Exception e) { if (Settings.DEV_MODE.isTrue()) { - e.printStackTrace(); + Log.warn("THIS ERROR IS ONLY LOGGED IN DEV MODE:"); + Log.toLog(this.getClass(), e); } } finally { exchange.close(); if (Settings.DEV_MODE.isTrue()) { - Log.debug(requestString + " Response code: " + responseCode+" took "+Benchmark.stop("", requestString)+" ms"); + Log.debug(requestString + " Response code: " + responseCode + " took " + Benchmark.stop("", requestString) + " ms"); } } } + private Authentication getAuthorization(Headers requestHeaders) { + List authorization = requestHeaders.get("Authorization"); + if (Verify.isEmpty(authorization)) { + return null; + } + String authLine = authorization.get(0); + if (authLine.contains("Basic ")) { + return new BasicAuthentication(authLine.split(" ")[1]); + } + return null; + } + + public ResponseHandler getResponseHandler() { + return responseHandler; + } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java new file mode 100644 index 000000000..e945c3931 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java @@ -0,0 +1,126 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver; + +import com.djrapitops.plan.api.exceptions.WebUserAuthException; +import com.djrapitops.plan.api.exceptions.connection.*; +import com.djrapitops.plan.system.info.connection.InfoRequestPageHandler; +import com.djrapitops.plan.system.webserver.auth.Authentication; +import com.djrapitops.plan.system.webserver.pages.*; +import com.djrapitops.plan.system.webserver.response.*; +import com.djrapitops.plan.system.webserver.response.api.BadRequestResponse; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.errors.ForbiddenResponse; +import com.djrapitops.plan.system.webserver.response.errors.InternalErrorResponse; +import com.djrapitops.plan.system.webserver.response.errors.NotFoundResponse; +import com.djrapitops.plan.system.webserver.response.errors.UnauthorizedServerResponse; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +/** + * Handles choosing of the correct response to a request. + * + * @author Rsl1122 + */ +public class ResponseHandler extends TreePageHandler { + + private final WebServer webServer; + + public ResponseHandler(WebServer webServer) { + this.webServer = webServer; + } + + public void registerDefaultPages() { + registerPage("favicon.ico", new RedirectResponse("https://puu.sh/tK0KL/6aa2ba141b.ico"), 5); + registerPage("debug", new DebugPageHandler()); + registerPage("players", new PlayersPageHandler()); + registerPage("player", new PlayerPageHandler()); + + ServerPageHandler serverPageHandler = new ServerPageHandler(); + registerPage("network", serverPageHandler); + registerPage("server", serverPageHandler); + if (webServer.isAuthRequired()) { + registerPage("", new RootPageHandler(this)); + } + } + + public void registerWebAPIPages() { + registerPage("info", new InfoRequestPageHandler()); + } + + public Response getResponse(Request request) { + String targetString = request.getTarget(); + List target = new ArrayList<>(Arrays.asList(targetString.split("/"))); + if (!target.isEmpty()) { + target.remove(0); + } + try { + return getResponse(request, targetString, target); + } catch (NoServersException | NotFoundException e) { + return new NotFoundResponse(e.getMessage()); + } catch (WebUserAuthException e) { + return PromptAuthorizationResponse.getBasicAuthResponse(e); + } catch (ForbiddenException e) { + return new ForbiddenResponse(e.getMessage()); + } catch (BadRequestException e) { + return new BadRequestResponse(e.getMessage()); + } catch (UnauthorizedServerException e) { + return new UnauthorizedServerResponse(e.getMessage()); + } catch (InternalErrorException e) { + if (e.getCause() != null) { + return new InternalErrorResponse(request.getTarget(), e.getCause()); + } else { + return new InternalErrorResponse(request.getTarget(), e); + } + } catch (Exception e) { + Log.toLog(this.getClass(), e); + return new InternalErrorResponse(request.getTarget(), e); + } + } + + private Response getResponse(Request request, String targetString, List target) throws WebException { + Optional authentication = Optional.empty(); + + if (targetString.endsWith(".css")) { + return ResponseCache.loadResponse(PageId.CSS.of(targetString), () -> new CSSResponse(targetString)); + } + if (targetString.endsWith(".js")) { + return ResponseCache.loadResponse(PageId.JS.of(targetString), () -> new JavaScriptResponse(targetString)); + } + boolean isNotInfoRequest = target.isEmpty() || !target.get(0).equals("info"); + boolean isAuthRequired = webServer.isAuthRequired() && isNotInfoRequest; + if (isAuthRequired) { + authentication = request.getAuth(); + if (!authentication.isPresent()) { + if (webServer.isUsingHTTPS()) { + return DefaultResponses.BASIC_AUTH.get(); + } else { + return forbiddenResponse(); + } + } + } + PageHandler pageHandler = getPageHandler(target); + if (pageHandler == null) { + return DefaultResponses.NOT_FOUND.get(); + } else { + boolean isAuthorized = authentication.isPresent() && pageHandler.isAuthorized(authentication.get(), target); + if (!isAuthRequired || isAuthorized) { + return pageHandler.getResponse(request, target); + } + return forbiddenResponse(); + } + } + + public Response forbiddenResponse() { + return ResponseCache.loadResponse(PageId.FORBIDDEN.id(), () -> + new ForbiddenResponse("Your user is not authorized to view this page.
" + + "If you believe this is an error contact staff to change your access level.")); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/WebServer.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/WebServer.java similarity index 71% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/WebServer.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/WebServer.java index 22d1cb7ca..237ac722f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/WebServer.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/WebServer.java @@ -1,17 +1,17 @@ -package com.djrapitops.plan.systems.webserver; +package com.djrapitops.plan.system.webserver; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.webserver.webapi.WebAPIManager; -import com.djrapitops.plan.systems.webserver.webapi.bukkit.*; -import com.djrapitops.plan.systems.webserver.webapi.bungee.*; -import com.djrapitops.plan.systems.webserver.webapi.universal.PingWebAPI; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plan.system.file.FileSystem; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.html.HtmlUtils; import com.djrapitops.plugin.StaticHolder; import com.djrapitops.plugin.api.Check; import com.djrapitops.plugin.api.utility.log.Log; +import com.djrapitops.plugin.utilities.Verify; import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.HttpsConfigurator; import com.sun.net.httpserver.HttpsParameters; @@ -34,55 +34,57 @@ import java.util.concurrent.TimeUnit; /** * @author Rsl1122 */ -public class WebServer { +public class WebServer implements SubSystem { - private final IPlan plugin; - private final WebAPIManager webAPI; - - private final int port; + private int port; private boolean enabled = false; private HttpServer server; private boolean usingHttps = false; - public WebServer(IPlan plugin) { - this.plugin = plugin; - this.port = Settings.WEBSERVER_PORT.getNumber(); - webAPI = new WebAPIManager(); - registerWebAPIs(); + private RequestHandler requestHandler; + private ResponseHandler responseHandler; - StaticHolder.saveInstance(APIRequestHandler.class, plugin.getClass()); - StaticHolder.saveInstance(RequestHandler.class, plugin.getClass()); - StaticHolder.saveInstance(ResponseHandler.class, plugin.getClass()); - StaticHolder.saveInstance(APIResponseHandler.class, plugin.getClass()); + public static WebServer getInstance() { + WebServer webServer = WebServerSystem.getInstance().getWebServer(); + Verify.nullCheck(webServer, () -> new IllegalStateException("WebServer was not initialized.")); + return webServer; } - private void registerWebAPIs() { - webAPI.registerNewAPI( - new AnalysisReadyWebAPI(), - new AnalyzeWebAPI(), - new ConfigurationWebAPI(), - new InspectWebAPI(), - new IsOnlineWebAPI(), - new RequestInspectPluginsTabBukkitWebAPI(), - new PingWebAPI() - ); + @Override + public void enable() throws EnableException { + this.port = Settings.WEBSERVER_PORT.getNumber(); - webAPI.registerNewAPI( - new IsCachedWebAPI(), - new PostHtmlWebAPI(), - new PostInspectPluginsTabWebAPI(), - new PostNetworkPageContentWebAPI(), - new PostOriginalBukkitSettingsWebAPI(), - new RequestPluginsTabWebAPI(), - new RequestSetupWebAPI() - ); + requestHandler = new RequestHandler(this); + responseHandler = requestHandler.getResponseHandler(); + + PlanPlugin plugin = PlanPlugin.getInstance(); + StaticHolder.saveInstance(RequestHandler.class, plugin.getClass()); + StaticHolder.saveInstance(ResponseHandler.class, plugin.getClass()); + + initServer(); + + if (!isEnabled()) { + if (Check.isBungeeAvailable()) { + throw new EnableException("WebServer did not initialize!"); + } + if (Settings.WEBSERVER_DISABLED.isTrue()) { + Log.warn("WebServer was not initialized. (WebServer.DisableWebServer: true)"); + } else { + Log.error("WebServer was not initialized successfully. Is the port (" + Settings.WEBSERVER_PORT.getNumber() + ") in use?"); + } + } + } + + @Override + public void disable() { + stop(); } /** * Starts up the WebServer in a new Thread Pool. */ - public void initServer() { + private void initServer() { // Check if Bukkit WebServer has been disabled. if (!Check.isBungeeAvailable() && Settings.WEBSERVER_DISABLED.isTrue()) { return; @@ -103,12 +105,7 @@ public class WebServer { Log.infoColor("§eUser Authorization Disabled! (Not possible over http)"); server = HttpServer.create(new InetSocketAddress(Settings.WEBSERVER_IP.toString(), port), 10); } - if (plugin.getInfoManager().isUsingAnotherWebServer()) { - server.createContext("/", new APIRequestHandler(getWebAPI())); - Log.infoColor("§aWebServer Running in WebAPI-only Mode"); - } else { - server.createContext("/", new RequestHandler(plugin, this)); - } + server.createContext("/", requestHandler); server.setExecutor(new ThreadPoolExecutor(4, 8, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100))); server.start(); @@ -117,7 +114,7 @@ public class WebServer { Log.info(Locale.get(Msg.ENABLE_WEBSERVER_INFO).parse(server.getAddress().getPort()) + " (" + getAccessAddress() + ")"); } catch (IllegalArgumentException | IllegalStateException | IOException e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); enabled = false; } } @@ -125,7 +122,7 @@ public class WebServer { private boolean startHttpsServer() { String keyStorePath = Settings.WEBSERVER_CERTIFICATE_PATH.toString(); if (!Paths.get(keyStorePath).isAbsolute()) { - keyStorePath = plugin.getDataFolder() + File.separator + keyStorePath; + keyStorePath = FileSystem.getDataFolder() + File.separator + keyStorePath; } char[] storepass = Settings.WEBSERVER_CERTIFICATE_STOREPASS.toString().toCharArray(); @@ -167,16 +164,16 @@ public class WebServer { startSuccessful = true; } catch (KeyManagementException | NoSuchAlgorithmException e) { Log.error("WebServer: SSL Context Initialization Failed."); - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } catch (FileNotFoundException e) { Log.infoColor("§eWebServer: SSL Certificate KeyStore File not Found: " + keyStorePath); Log.info("No Certificate -> Using Http server for Visualization."); } catch (IOException e) { Log.error("WebServer: " + e); - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } catch (KeyStoreException | CertificateException | UnrecoverableKeyException e) { Log.error("WebServer: SSL Certificate loading Failed."); - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } return startSuccessful; } @@ -192,8 +189,8 @@ public class WebServer { * Shuts down the server - Async thread is closed with shutdown boolean. */ public void stop() { - Log.info(Locale.get(Msg.DISABLE_WEBSERVER).toString()); if (server != null) { + Log.info(Locale.get(Msg.DISABLE_WEBSERVER).toString()); server.stop(0); } enabled = false; @@ -215,7 +212,11 @@ public class WebServer { return isEnabled() ? getProtocol() + "://" + HtmlUtils.getIP() : Settings.EXTERNAL_WEBSERVER_LINK.toString(); } - public WebAPIManager getWebAPI() { - return webAPI; + public RequestHandler getRequestHandler() { + return requestHandler; + } + + public ResponseHandler getResponseHandler() { + return responseHandler; } } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/WebServerSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/WebServerSystem.java new file mode 100644 index 000000000..b1f5c4ee0 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/WebServerSystem.java @@ -0,0 +1,54 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver; + +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.SubSystem; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plugin.api.Benchmark; + +/** + * WebServer subsystem for managing WebServer initialization. + * + * @author Rsl1122 + */ +public class WebServerSystem implements SubSystem { + + private WebServer webServer; + + public WebServerSystem() { + webServer = new WebServer(); + } + + public static WebServerSystem getInstance() { + return PlanSystem.getInstance().getWebServerSystem(); + } + + public static boolean isWebServerEnabled() { + WebServer webServer = getInstance().webServer; + return webServer != null && webServer.isEnabled(); + } + + @Override + public void enable() throws EnableException { + Benchmark.start("WebServer Initialization"); + webServer.enable(); + Benchmark.stop("Enable", "WebServer Initialization"); + ResponseHandler responseHandler = webServer.getResponseHandler(); + responseHandler.registerWebAPIPages(); + responseHandler.registerDefaultPages(); + } + + @Override + public void disable() { + ResponseCache.clearCache(); + webServer.stop(); + } + + public WebServer getWebServer() { + return webServer; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/auth/Authentication.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/auth/Authentication.java new file mode 100644 index 000000000..e07a6ca63 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/auth/Authentication.java @@ -0,0 +1,19 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.auth; + +import com.djrapitops.plan.api.exceptions.WebUserAuthException; +import com.djrapitops.plan.data.WebUser; + +/** + * Interface for different WebUser authentication methods used by Requests. + * + * @author Rsl1122 + */ +public interface Authentication { + + WebUser getWebUser() throws WebUserAuthException; + +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/auth/BasicAuthentication.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/auth/BasicAuthentication.java new file mode 100644 index 000000000..5e3471a91 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/auth/BasicAuthentication.java @@ -0,0 +1,61 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.auth; + +import com.djrapitops.plan.api.exceptions.PassEncryptException; +import com.djrapitops.plan.api.exceptions.WebUserAuthException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.WebUser; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.utilities.Base64Util; +import com.djrapitops.plan.utilities.PassEncryptUtil; + +/** + * Authentication handling for Basic Auth. + *

+ * Basic access authentication (Wikipedia): + * https://en.wikipedia.org/wiki/Basic_access_authentication + * + * @author Rsl1122 + */ +public class BasicAuthentication implements Authentication { + + private String authenticationString; + + public BasicAuthentication(String authenticationString) { + this.authenticationString = authenticationString; + } + + @Override + public WebUser getWebUser() throws WebUserAuthException { + String decoded = Base64Util.decode(authenticationString); + + String[] userInfo = decoded.split(":"); + if (userInfo.length != 2) { + throw new WebUserAuthException(FailReason.USER_AND_PASS_NOT_SPECIFIED); + } + + String user = userInfo[0]; + String passwordRaw = userInfo[1]; + + try { + + Database database = Database.getActive(); + if (!database.check().doesWebUserExists(user)) { + throw new WebUserAuthException(FailReason.USER_DOES_NOT_EXIST, user); + } + + WebUser webUser = database.fetch().getWebUser(user); + + boolean correctPass = PassEncryptUtil.verifyPassword(passwordRaw, webUser.getSaltedPassHash()); + if (!correctPass) { + throw new WebUserAuthException(FailReason.USER_PASS_MISMATCH, user); + } + return webUser; + } catch (DBException | PassEncryptException e) { + throw new WebUserAuthException(e); + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/auth/FailReason.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/auth/FailReason.java new file mode 100644 index 000000000..44f522db8 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/auth/FailReason.java @@ -0,0 +1,28 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.auth; + +/** + * Reason for WebUserAuthException. + * + * @author Rsl1122 + * @see com.djrapitops.plan.api.exceptions.WebUserAuthException + */ +public enum FailReason { + USER_AND_PASS_NOT_SPECIFIED("User and Password not specified"), + USER_DOES_NOT_EXIST("User does not exist"), + USER_PASS_MISMATCH("User and Password did not match"), + ERROR("Authentication failed due to error"); + + private final String reason; + + FailReason(String reason) { + this.reason = reason; + } + + public String getReason() { + return reason; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/DebugPageHandler.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/DebugPageHandler.java new file mode 100644 index 000000000..8f0abe9eb --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/DebugPageHandler.java @@ -0,0 +1,33 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.pages; + +import com.djrapitops.plan.api.exceptions.WebUserAuthException; +import com.djrapitops.plan.data.WebUser; +import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.auth.Authentication; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.pages.DebugPageResponse; + +import java.util.List; + +/** + * PageHandler for /debug page. + * + * @author Rsl1122 + */ +public class DebugPageHandler extends PageHandler { + + @Override + public Response getResponse(Request request, List target) { + return new DebugPageResponse(); + } + + @Override + public boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + WebUser webUser = auth.getWebUser(); + return webUser.getPermLevel() <= 0; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/PageHandler.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/PageHandler.java new file mode 100644 index 000000000..0bcdea3f4 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/PageHandler.java @@ -0,0 +1,35 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.pages; + +import com.djrapitops.plan.api.exceptions.WebUserAuthException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.auth.Authentication; +import com.djrapitops.plan.system.webserver.response.Response; + +import java.util.List; + +/** + * PageHandlers are used for easier Response management and authorization checking. + * + * @author Rsl1122 + */ +public abstract class PageHandler { + + /** + * Get the Response of a PageHandler. + * + * @param request Request in case it is useful for choosing page. + * @param target Rest of the target coordinates after this page has been solved. + * @return Response appropriate to the PageHandler. + */ + public abstract Response getResponse(Request request, List target) throws WebException; + + public boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + return true; + } + +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayerPageHandler.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayerPageHandler.java new file mode 100644 index 000000000..493cdc233 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayerPageHandler.java @@ -0,0 +1,78 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.pages; + +import com.djrapitops.plan.api.exceptions.WebUserAuthException; +import com.djrapitops.plan.api.exceptions.connection.InternalErrorException; +import com.djrapitops.plan.api.exceptions.connection.NoServersException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.data.WebUser; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.auth.Authentication; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.errors.NotFoundResponse; +import com.djrapitops.plan.system.webserver.response.pages.InspectPageResponse; +import com.djrapitops.plan.utilities.uuid.UUIDUtility; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.util.List; +import java.util.UUID; + +/** + * PageHandler for /player/PlayerName pages. + * + * @author Rsl1122 + */ +public class PlayerPageHandler extends PageHandler { + + @Override + public Response getResponse(Request request, List target) throws WebException { + if (target.isEmpty()) { + return DefaultResponses.NOT_FOUND.get(); + } + + String playerName = target.get(0); + UUID uuid = UUIDUtility.getUUIDOf(playerName); + + if (uuid == null) { + return notFound("Player UUID was not found in the database."); + } + + try { + if (Database.getActive().check().isPlayerRegistered(uuid)) { + Response response = ResponseCache.loadResponse(PageId.PLAYER.of(uuid)); + if (response == null || !(response instanceof InspectPageResponse)) { + InfoSystem.getInstance().generateAndCachePlayerPage(uuid); + response = ResponseCache.loadResponse(PageId.PLAYER.of(uuid)); + } + return response; + } else { + return notFound("Player has not played on this server."); + } + } catch (DBException e) { + Log.toLog(this.getClass(), e); + throw new InternalErrorException("Analysis", e); + } catch (NoServersException e) { + ResponseCache.loadResponse(PageId.PLAYER.of(uuid), () -> new NotFoundResponse(e.getMessage())); + } + return InspectPageResponse.getRefreshing(); + } + + private Response notFound(String error) { + return ResponseCache.loadResponse(PageId.NOT_FOUND.of(error), () -> new NotFoundResponse(error)); + } + + @Override + public boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + WebUser webUser = auth.getWebUser(); + return webUser.getPermLevel() <= 1 || webUser.getName().equalsIgnoreCase(target.get(target.size() - 1)); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayersPageHandler.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayersPageHandler.java new file mode 100644 index 000000000..a36a19027 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayersPageHandler.java @@ -0,0 +1,33 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.pages; + +import com.djrapitops.plan.api.exceptions.WebUserAuthException; +import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.auth.Authentication; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.pages.PlayersPageResponse; + +import java.util.List; + +/** + * PageHandler for /players page. + * + * @author Rsl1122 + */ +public class PlayersPageHandler extends PageHandler { + + @Override + public Response getResponse(Request request, List target) { + return ResponseCache.loadResponse(PageId.PLAYERS.id(), PlayersPageResponse::new); + } + + @Override + public boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + return auth.getWebUser().getPermLevel() <= 1; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/RootPageHandler.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/RootPageHandler.java new file mode 100644 index 000000000..83904f8fc --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/RootPageHandler.java @@ -0,0 +1,60 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.pages; + +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.data.WebUser; +import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.ResponseHandler; +import com.djrapitops.plan.system.webserver.auth.Authentication; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +/** + * PageHandler for / page (Address root). + *

+ * Not Available if Authentication is not enabled. + * + * @author Rsl1122 + */ +public class RootPageHandler extends PageHandler { + + private final ResponseHandler responseHandler; + + public RootPageHandler(ResponseHandler responseHandler) { + this.responseHandler = responseHandler; + } + + @Override + public Response getResponse(Request request, List target) throws WebException { + Optional auth = request.getAuth(); + if (!auth.isPresent()) { + return DefaultResponses.BASIC_AUTH.get(); + } + + WebUser webUser = auth.get().getWebUser(); + + int permLevel = webUser.getPermLevel(); + switch (permLevel) { + case 0: + return responseHandler.getPageHandler("server").getResponse(request, Collections.emptyList()); + case 1: + return responseHandler.getPageHandler("players").getResponse(request, Collections.emptyList()); + case 2: + return responseHandler.getPageHandler("player").getResponse(request, Collections.singletonList(webUser.getName())); + default: + return responseHandler.forbiddenResponse(); + } + } + + @Override + public boolean isAuthorized(Authentication auth, List target) { + return true; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/ServerPageHandler.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/ServerPageHandler.java new file mode 100644 index 000000000..67230dd0e --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/ServerPageHandler.java @@ -0,0 +1,63 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.pages; + +import com.djrapitops.plan.api.exceptions.WebUserAuthException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.auth.Authentication; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.pages.AnalysisPageResponse; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +/** + * PageHandler for /server and /network pages. + * + * @author Rsl1122 + */ +public class ServerPageHandler extends PageHandler { + + @Override + public Response getResponse(Request request, List target) { + UUID serverUUID = getServerUUID(target); + Response response = ResponseCache.loadResponse(PageId.SERVER.of(serverUUID)); + if (response != null) { + return response; + } else { + return AnalysisPageResponse.refreshNow(serverUUID); + } + } + + private UUID getServerUUID(List target) { + UUID serverUUID = ServerInfo.getServerUUID(); + if (!target.isEmpty()) { + try { + String serverName = target.get(0).replace("%20", " "); + Optional serverUUIDOptional = Database.getActive().fetch().getServerUUID(serverName); + if (serverUUIDOptional.isPresent()) { + serverUUID = serverUUIDOptional.get(); + } + } catch (IllegalArgumentException ignore) { + /*ignored*/ + } catch (DBException e) { + Log.toLog(this.getClass(), e); + } + } + return serverUUID; + } + + @Override + public boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + return auth.getWebUser().getPermLevel() <= 0; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/TreePageHandler.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/TreePageHandler.java new file mode 100644 index 000000000..89b034ea8 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/TreePageHandler.java @@ -0,0 +1,69 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.pages; + +import com.djrapitops.plan.api.exceptions.WebUserAuthException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.auth.Authentication; +import com.djrapitops.plan.system.webserver.response.DefaultResponses; +import com.djrapitops.plan.system.webserver.response.Response; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Abstract PageHandler that allows Tree-like target deduction. + * + * @author Rsl1122 + */ +public abstract class TreePageHandler extends PageHandler { + + private Map pages; + + public TreePageHandler() { + pages = new HashMap<>(); + } + + public void registerPage(String targetPage, PageHandler handler) { + pages.put(targetPage, handler); + } + + public void registerPage(String targetPage, Response response, int requiredPerm) { + pages.put(targetPage, new PageHandler() { + @Override + public Response getResponse(Request request, List target) { + return response; + } + + @Override + public boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + return auth.getWebUser().getPermLevel() <= requiredPerm; + } + }); + } + + @Override + public Response getResponse(Request request, List target) throws WebException { + PageHandler pageHandler = getPageHandler(target); + return pageHandler != null + ? pageHandler.getResponse(request, target) + : DefaultResponses.NOT_FOUND.get(); + } + + public PageHandler getPageHandler(List target) { + if (target.isEmpty()) { + return pages.get(""); + } + String targetPage = target.get(0); + target.remove(0); + return pages.get(targetPage); + } + + public PageHandler getPageHandler(String targetPage) { + return pages.get(targetPage); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/AnalysisPageParser.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/AnalysisPage.java similarity index 50% rename from Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/AnalysisPageParser.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/AnalysisPage.java index 0dc2b98d4..74058108d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/AnalysisPageParser.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/AnalysisPage.java @@ -1,17 +1,14 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.info.parsing; +package com.djrapitops.plan.system.webserver.pages.parsing; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.api.IPlan; import com.djrapitops.plan.api.exceptions.ParseException; -import com.djrapitops.plan.data.AnalysisData; +import com.djrapitops.plan.data.calculation.AnalysisData; +import com.djrapitops.plan.system.webserver.response.errors.ErrorResponse; import com.djrapitops.plan.utilities.file.FileUtil; import com.djrapitops.plan.utilities.html.HtmlUtils; -import com.djrapitops.plugin.api.Check; import java.io.IOException; @@ -20,18 +17,24 @@ import java.io.IOException; * * @author Rsl1122 */ -public class AnalysisPageParser extends PageParser { +public class AnalysisPage extends Page { private final AnalysisData data; - private final IPlan plugin; - public AnalysisPageParser(AnalysisData analysisData, IPlan plugin) { + public AnalysisPage(AnalysisData analysisData) { this.data = analysisData; - this.plugin = plugin; + } + + public static String getRefreshingHtml() { + ErrorResponse refreshPage = new ErrorResponse(); + refreshPage.setTitle("Analysis is being refreshed.."); + refreshPage.setParagraph(" Analysis is being run, refresh the page after a few seconds.. (F5)"); + refreshPage.replacePlaceholders(); + return refreshPage.getContent(); } @Override - public String parse() throws ParseException { + public String toHtml() throws ParseException { addValues(data.getReplaceMap()); try { @@ -40,11 +43,4 @@ public class AnalysisPageParser extends PageParser { throw new ParseException(e); } } - - private int getPlayersOnline() { - if (Check.isBukkitAvailable()) { - return ((Plan) plugin).getServer().getOnlinePlayers().size(); - } - return ((PlanBungee) plugin).getProxy().getOnlineCount(); - } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/InspectPageParser.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/InspectPage.java similarity index 78% rename from Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/InspectPageParser.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/InspectPage.java index 81d167ad7..c593540bd 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/InspectPageParser.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/InspectPage.java @@ -2,21 +2,23 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.info.parsing; +package com.djrapitops.plan.system.webserver.pages.parsing; -import com.djrapitops.plan.api.IPlan; import com.djrapitops.plan.api.exceptions.ParseException; import com.djrapitops.plan.data.PlayerProfile; +import com.djrapitops.plan.data.calculation.ActivityIndex; import com.djrapitops.plan.data.container.Action; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.settings.theme.ThemeVal; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.ThemeVal; import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plan.utilities.analysis.AnalysisUtils; import com.djrapitops.plan.utilities.analysis.MathUtils; import com.djrapitops.plan.utilities.comparators.SessionLengthComparator; import com.djrapitops.plan.utilities.comparators.SessionStartComparator; @@ -24,15 +26,14 @@ import com.djrapitops.plan.utilities.file.FileUtil; import com.djrapitops.plan.utilities.html.HtmlStructure; import com.djrapitops.plan.utilities.html.HtmlUtils; import com.djrapitops.plan.utilities.html.graphs.PunchCardGraph; -import com.djrapitops.plan.utilities.html.graphs.line.ServerPreferencePie; +import com.djrapitops.plan.utilities.html.graphs.pie.ServerPreferencePie; import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie; import com.djrapitops.plan.utilities.html.structure.ServerAccordionCreator; -import com.djrapitops.plan.utilities.html.tables.ActionsTableCreator; -import com.djrapitops.plan.utilities.html.tables.IpTableCreator; -import com.djrapitops.plan.utilities.html.tables.NicknameTableCreator; +import com.djrapitops.plan.utilities.html.tables.ActionsTable; +import com.djrapitops.plan.utilities.html.tables.GeoInfoTable; +import com.djrapitops.plan.utilities.html.tables.NicknameTable; import com.djrapitops.plugin.api.Benchmark; import com.djrapitops.plugin.api.TimeAmount; -import com.djrapitops.plugin.api.utility.log.Log; import java.io.IOException; import java.util.*; @@ -43,30 +44,28 @@ import java.util.stream.Collectors; * * @author Rsl1122 */ -public class InspectPageParser extends PageParser { +public class InspectPage extends Page { private final UUID uuid; - private final IPlan plugin; - public InspectPageParser(UUID uuid, IPlan plugin) { + public InspectPage(UUID uuid) { this.uuid = uuid; - this.plugin = plugin; } - public String parse() throws ParseException { + @Override + public String toHtml() throws ParseException { try { if (uuid == null) { throw new IllegalStateException("UUID was null!"); } - Log.logDebug("Database", "Inspect Parse Fetch"); Benchmark.start("Inspect Parse, Fetch"); - Database db = plugin.getDB(); - PlayerProfile profile = db.getPlayerProfile(uuid); + Database db = Database.getActive(); + PlayerProfile profile = db.fetch().getPlayerProfile(uuid); if (profile == null) { throw new IllegalStateException("Player profile was null!"); } - UUID serverUUID = MiscUtils.getIPlan().getServerUuid(); - Map serverNames = db.getServerTable().getServerNames(); + UUID serverUUID = ServerInfo.getServerUUID(); + Map serverNames = db.fetch().getServerNames(); Benchmark.stop("Inspect Parse, Fetch"); @@ -79,12 +78,12 @@ public class InspectPageParser extends PageParser { public String parse(PlayerProfile profile, UUID serverUUID, Map serverNames) throws IOException { long now = MiscUtils.getTime(); - addValue("refresh", FormatUtils.formatTimeStamp(now)); + addValue("refresh", FormatUtils.formatTimeStampClock(now)); addValue("version", MiscUtils.getPlanVersion()); addValue("timeZone", MiscUtils.getTimeZoneOffsetHours()); String online = "Offline"; - Optional activeSession = plugin.getInfoManager().getDataCache().getCachedSession(uuid); + Optional activeSession = SessionCache.getCachedSession(uuid); if (activeSession.isPresent()) { Session session = activeSession.get(); session.setSessionID(Integer.MAX_VALUE); @@ -100,14 +99,11 @@ public class InspectPageParser extends PageParser { addValue("registered", FormatUtils.formatTimeStampYear(registered)); addValue("playerName", playerName); addValue("kickCount", timesKicked); - if (lastSeen != 0) { - addValue("lastSeen", FormatUtils.formatTimeStampYear(lastSeen)); - } else { - addValue("lastSeen", "-"); - } + + addValue("lastSeen", lastSeen != 0 ? FormatUtils.formatTimeStampYear(lastSeen) : "-"); Map worldTimesPerServer = profile.getWorldTimesPerServer(); - addValue("serverPieSeries", ServerPreferencePie.createSeries(serverNames, worldTimesPerServer)); + addValue("serverPieSeries", new ServerPreferencePie(serverNames, worldTimesPerServer).toHighChartsSeries()); addValue("worldPieColors", Theme.getValue(ThemeVal.GRAPH_WORLD_PIE)); addValue("gmPieColors", Theme.getValue(ThemeVal.GRAPH_GM_PIE)); addValue("serverPieColors", Theme.getValue(ThemeVal.GRAPH_SERVER_PREF_PIE)); @@ -115,8 +111,8 @@ public class InspectPageParser extends PageParser { String favoriteServer = serverNames.get(profile.getFavoriteServer()); addValue("favoriteServer", favoriteServer != null ? favoriteServer : "Unknown"); - addValue("tableBodyNicknames", NicknameTableCreator.createTable(profile.getNicknames(), serverNames)); - addValue("tableBodyIPs", IpTableCreator.createTable(profile.getGeoInformation())); + addValue("tableBodyNicknames", new NicknameTable(profile.getNicknames(), serverNames).parseBody()); + addValue("tableBodyIPs", new GeoInfoTable(profile.getGeoInformation()).parseBody()); Map> sessions = profile.getSessions(); Map> sessionsByServerName = sessions.entrySet().stream() @@ -185,23 +181,21 @@ public class InspectPageParser extends PageParser { addValue("sessionAverageWeek", sessionAverageWeek > 0L ? FormatUtils.formatTimeAmount(sessionAverageWeek) : "-"); addValue("sessionAverageMonth", sessionAverageMonth > 0L ? FormatUtils.formatTimeAmount(sessionAverageMonth) : "-"); - addValue("sessionCount", sessionCount); addValue("sessionCountDay", sessionCountDay); addValue("sessionCountWeek", sessionCountWeek); addValue("sessionCountMonth", sessionCountMonth); List actions = profile.getAllActions(); - addValue("tableBodyActions", ActionsTableCreator.createTable(actions)); + addValue("tableBodyActions", new ActionsTable(actions).parseBody()); - String punchCardData = PunchCardGraph.createSeries(allSessions); + String punchCardData = new PunchCardGraph(allSessions).toHighChartsSeries(); WorldTimes worldTimes = profile.getWorldTimes(); - AnalysisUtils.addMissingWorlds(worldTimes); - String[] worldPieData = WorldPie.createSeries(worldTimes); + WorldPie worldPie = new WorldPie(worldTimes); - addValue("worldPieSeries", worldPieData[0]); - addValue("gmSeries", worldPieData[1]); + addValue("worldPieSeries", worldPie.toHighChartsSeries()); + addValue("gmSeries", worldPie.toHighChartsDrilldown()); addValue("punchCardSeries", punchCardData); @@ -225,16 +219,15 @@ public class InspectPageParser extends PageParser { addValue("mobKillCount", mobKillCount); addValue("deathCount", deathCount); - double activityIndex = profile.getActivityIndex(now); - String[] activityIndexFormat = FormatUtils.readableActivityIndex(activityIndex); + ActivityIndex activityIndex = profile.getActivityIndex(now); - addValue("activityIndexNumber", FormatUtils.cutDecimals(activityIndex)); - addValue("activityIndexColor", activityIndexFormat[0]); - addValue("activityIndex", activityIndexFormat[1]); + addValue("activityIndexNumber", activityIndex.getFormattedValue()); + addValue("activityIndexColor", activityIndex.getColor()); + addValue("activityIndex", activityIndex.getGroup()); addValue("playerStatus", HtmlStructure.playerStatus(online, profile.getBannedOnServers(), profile.isOp())); - if (!plugin.getInfoManager().isUsingAnotherWebServer()) { + if (!InfoSystem.getInstance().getConnectionSystem().isServerAvailable()) { addValue("networkName", Settings.SERVER_NAME.toString().replaceAll("[^a-zA-Z0-9_\\s]", "_")); } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/NetworkPageParser.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/NetworkPage.java similarity index 52% rename from Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/NetworkPageParser.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/NetworkPage.java index 55aabe8d8..6e1704ddd 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/NetworkPageParser.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/NetworkPage.java @@ -1,28 +1,30 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.info.parsing; +package com.djrapitops.plan.system.webserver.pages.parsing; -import com.djrapitops.plan.PlanBungee; import com.djrapitops.plan.api.exceptions.ParseException; +import com.djrapitops.plan.api.exceptions.database.DBException; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.container.TPS; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.settings.theme.ThemeVal; -import com.djrapitops.plan.systems.info.BungeeInformationManager; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.ThemeVal; +import com.djrapitops.plan.system.update.VersionCheckSystem; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.pages.parts.NetworkPageContent; import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plan.utilities.analysis.AnalysisUtils; import com.djrapitops.plan.utilities.file.FileUtil; -import com.djrapitops.plan.utilities.html.HtmlStructure; import com.djrapitops.plan.utilities.html.HtmlUtils; -import com.djrapitops.plan.utilities.html.graphs.line.PlayerActivityGraph; +import com.djrapitops.plan.utilities.html.graphs.line.OnlineActivityGraph; import com.djrapitops.plugin.api.TimeAmount; -import java.sql.SQLException; import java.util.List; import java.util.Map; import java.util.Optional; @@ -33,42 +35,37 @@ import java.util.UUID; * * @author Rsl1122 */ -public class NetworkPageParser extends PageParser { - - private final PlanBungee plugin; - - public NetworkPageParser(PlanBungee plugin) { - this.plugin = plugin; - } +public class NetworkPage extends Page { @Override - public String parse() throws ParseException { + public String toHtml() throws ParseException { try { - UUID serverUUID = plugin.getServerUuid(); + UUID serverUUID = ServerInfo.getServerUUID(); long now = MiscUtils.getTime(); - Database db = plugin.getDB(); - List networkOnlineData = db.getTpsTable().getNetworkOnlineData(); + Database database = Database.getActive(); + List networkOnlineData = database.fetch().getNetworkOnlineData(); - peakTimes(serverUUID, now, db); + peakTimes(serverUUID, now, database); - uniquePlayers(now, db); + uniquePlayers(now, database); addValue("timeZone", MiscUtils.getTimeZoneOffsetHours()); addValue("networkName", Settings.BUNGEE_NETWORK_NAME.toString()); - addValue("version", plugin.getVersion()); - addValue("playersOnlineSeries", PlayerActivityGraph.createSeries(networkOnlineData)); + addValue("version", VersionCheckSystem.getCurrentVersion()); + addValue("playersOnlineSeries", new OnlineActivityGraph(networkOnlineData).toHighChartsSeries()); addValue("playersGraphColor", Theme.getValue(ThemeVal.GRAPH_PLAYERS_ONLINE)); - addValue("playersOnline", plugin.getProxy().getOnlineCount()); + addValue("playersOnline", ServerInfo.getServerProperties().getOnlinePlayers()); - addValue("playersTotal", db.getUsersTable().getPlayerCount()); + addValue("playersTotal", database.count().getNetworkPlayerCount()); - List registerDates = db.getUsersTable().getRegisterDates(); + List registerDates = database.fetch().getRegisterDates(); addValue("playersNewDay", AnalysisUtils.getNewPlayers(registerDates, TimeAmount.DAY.ms(), now)); addValue("playersNewWeek", AnalysisUtils.getNewPlayers(registerDates, TimeAmount.WEEK.ms(), now)); addValue("playersNewMonth", AnalysisUtils.getNewPlayers(registerDates, TimeAmount.MONTH.ms(), now)); - Map networkPageContents = ((BungeeInformationManager) plugin.getInfoManager()).getNetworkPageContent(); - addValue("tabContentServers", HtmlStructure.createNetworkPageContent(networkPageContents)); + NetworkPageContent networkPageContent = (NetworkPageContent) + ResponseCache.loadResponse(PageId.NETWORK_CONTENT.id(), NetworkPageContent::new); + addValue("tabContentServers", networkPageContent.getContents()); return HtmlUtils.replacePlaceholders(FileUtil.getStringFromResource("web/network.html"), placeHolders); } catch (Exception e) { @@ -76,22 +73,22 @@ public class NetworkPageParser extends PageParser { } } - private void uniquePlayers(long now, Database db) throws SQLException { - Map>> allSessions = db.getSessionsTable().getAllSessions(false); + private void uniquePlayers(long now, Database db) throws DBException { + Map>> allSessions = db.fetch().getSessionsInLastMonth(); Map> userSessions = AnalysisUtils.sortSessionsByUser(allSessions); long dayAgo = now - TimeAmount.DAY.ms(); long weekAgo = now - TimeAmount.WEEK.ms(); long monthAgo = now - TimeAmount.MONTH.ms(); - addValue("playersUniqueDay", AnalysisUtils.getUniqueJoinsPerDay(userSessions, dayAgo)); - addValue("playersUniqueWeek", AnalysisUtils.getUniqueJoinsPerDay(userSessions, weekAgo)); - addValue("playersUniqueMonth", AnalysisUtils.getUniqueJoinsPerDay(userSessions, monthAgo)); + addValue("playersUniqueDay", AnalysisUtils.getUniquePlayers(userSessions, dayAgo)); + addValue("playersUniqueWeek", AnalysisUtils.getUniquePlayers(userSessions, weekAgo)); + addValue("playersUniqueMonth", AnalysisUtils.getUniquePlayers(userSessions, monthAgo)); } - private void peakTimes(UUID serverUUID, long now, Database db) throws SQLException { - Optional allTimePeak = db.getTpsTable().getAllTimePeak(serverUUID); - Optional lastPeak = db.getTpsTable().getPeakPlayerCount(serverUUID, now - TimeAmount.DAY.ms() * 2L); + private void peakTimes(UUID serverUUID, long now, Database db) throws DBException { + Optional allTimePeak = db.fetch().getAllTimePeak(serverUUID); + Optional lastPeak = db.fetch().getPeakPlayerCount(serverUUID, now - TimeAmount.DAY.ms() * 2L); if (allTimePeak.isPresent()) { TPS tps = allTimePeak.get(); diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/PageParser.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/Page.java similarity index 81% rename from Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/PageParser.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/Page.java index b4eb1be73..427b64775 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/PageParser.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/pages/parsing/Page.java @@ -1,8 +1,8 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.info.parsing; +package com.djrapitops.plan.system.webserver.pages.parsing; import com.djrapitops.plan.api.exceptions.ParseException; @@ -15,11 +15,11 @@ import java.util.Map; * * @author Rsl1122 */ -public abstract class PageParser { +public abstract class Page { protected final Map placeHolders; - public PageParser() { + public Page() { this.placeHolders = new HashMap<>(); } @@ -31,5 +31,5 @@ public abstract class PageParser { placeHolders.putAll(values); } - public abstract String parse() throws ParseException; + public abstract String toHtml() throws ParseException; } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/CSSResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/CSSResponse.java similarity index 71% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/CSSResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/CSSResponse.java index 247ff3ef4..f381dff85 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/CSSResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/CSSResponse.java @@ -1,6 +1,6 @@ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response; -import com.djrapitops.plan.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.Theme; /** * @author Rsl1122 diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/DefaultResponses.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/DefaultResponses.java new file mode 100644 index 000000000..214c32f58 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/DefaultResponses.java @@ -0,0 +1,35 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.response; + +import com.djrapitops.plan.system.webserver.response.PromptAuthorizationResponse; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.api.SuccessResponse; +import com.djrapitops.plan.system.webserver.response.errors.NotFoundResponse; + +/** + * Enum containing default responses that don't need to be cached because they're always the same. + * + * @author Rsl1122 + */ +public enum DefaultResponses { + NOT_FOUND( + new NotFoundResponse("Make sure you're accessing a link given by a command, Examples:

" + + "

/player/PlayerName
" + + "/server/ServerName

") + ), + BASIC_AUTH(PromptAuthorizationResponse.getBasicAuthResponse()), + SUCCESS(new SuccessResponse()); + + private final Response response; + + DefaultResponses(Response response) { + this.response = response; + } + + public Response get() { + return response; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/FileResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/FileResponse.java similarity index 90% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/FileResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/FileResponse.java index 6d6dd0414..4397758b7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/FileResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/FileResponse.java @@ -1,9 +1,10 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response; +import com.djrapitops.plan.system.webserver.response.errors.NotFoundResponse; import com.djrapitops.plan.utilities.file.FileUtil; import com.djrapitops.plugin.utilities.Verify; diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/JavaScriptResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/JavaScriptResponse.java similarity index 76% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/JavaScriptResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/JavaScriptResponse.java index 04cfef747..884df375a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/JavaScriptResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/JavaScriptResponse.java @@ -1,7 +1,7 @@ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.settings.theme.ThemeVal; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.ThemeVal; import org.apache.commons.lang3.text.StrSubstitutor; import java.util.HashMap; diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/PromptAuthorizationResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/PromptAuthorizationResponse.java new file mode 100644 index 000000000..a5cc4f0c6 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/PromptAuthorizationResponse.java @@ -0,0 +1,56 @@ +package com.djrapitops.plan.system.webserver.response; + +import com.djrapitops.plan.api.exceptions.WebUserAuthException; +import com.djrapitops.plan.system.webserver.auth.FailReason; +import com.djrapitops.plan.system.webserver.response.errors.ErrorResponse; +import com.djrapitops.plan.utilities.FormatUtils; +import com.djrapitops.plan.utilities.html.Html; + +/** + * @author Rsl1122 + * @since 3.5.2 + */ +public class PromptAuthorizationResponse extends ErrorResponse { + + private static final String TIPS = "
- Ensure you have registered a user with /plan register
" + + "- Check that the username and password are correct
" + + "- Username and password are case-sensitive
" + + "
If you have forgotten your password, ask a staff member to delete your old user and re-register."; + + private PromptAuthorizationResponse() { + super.setTitle(Html.FONT_AWESOME_ICON.parse("lock") + " 401 Unauthorized"); + } + + public static PromptAuthorizationResponse getBasicAuthResponse() { + PromptAuthorizationResponse response = new PromptAuthorizationResponse(); + response.setHeader("HTTP/1.1 401 Access Denied\r\n" + + "WWW-Authenticate: Basic realm=\"/\";"); + + response.setParagraph("Authentication Failed." + TIPS); + response.replacePlaceholders(); + return response; + } + + public static PromptAuthorizationResponse getBasicAuthResponse(WebUserAuthException e) { + PromptAuthorizationResponse response = new PromptAuthorizationResponse(); + response.setHeader("HTTP/1.1 401 Access Denied\r\n" + + "WWW-Authenticate: Basic realm=\"/\";"); + + FailReason failReason = e.getFailReason(); + String reason = failReason.getReason(); + + if (failReason == FailReason.ERROR) { + StringBuilder errorBuilder = new StringBuilder("

");
+            for (String line : FormatUtils.getStackTrace(e.getCause())) {
+                errorBuilder.append(line);
+            }
+            errorBuilder.append("
"); + + reason += errorBuilder.toString(); + } + + response.setParagraph("Authentication Failed.

Reason: " + reason + "

" + TIPS); + response.replacePlaceholders(); + return response; + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/RedirectResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/RedirectResponse.java similarity index 81% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/RedirectResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/RedirectResponse.java index 1b72a2621..e29e566a0 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/RedirectResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/RedirectResponse.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response; /** * @author Rsl1122 diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/Response.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/Response.java similarity index 92% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/Response.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/Response.java index b5e07411b..728642226 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/Response.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/Response.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; @@ -20,21 +20,25 @@ public abstract class Response { private Headers responseHeaders; - /** - * Class Constructor. - */ public Response(ResponseType type) { this.type = type.get(); } + /** + * Default Response constructor that defaults ResponseType to HTML. + */ public Response() { - this.type = ResponseType.HTML.get(); + this(ResponseType.HTML); } protected String getHeader() { return header; } + public void setHeader(String header) { + this.header = header; + } + public String getResponse() { return header + "\r\n" + "Content-Type: " + type + ";\r\n" @@ -51,10 +55,6 @@ public abstract class Response { this.content = content; } - public void setHeader(String header) { - this.header = header; - } - public int getCode() { return header == null ? 500 : Integer.parseInt(header.split(" ")[1]); } @@ -87,7 +87,7 @@ public abstract class Response { exchange.sendResponseHeaders(getCode(), 0); try (GZIPOutputStream out = new GZIPOutputStream(exchange.getResponseBody()); - ByteArrayInputStream bis = new ByteArrayInputStream(content.getBytes())) { + ByteArrayInputStream bis = new ByteArrayInputStream(getContent().getBytes())) { byte[] buffer = new byte[2048]; int count; while ((count = bis.read(buffer)) != -1) { diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/ResponseType.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ResponseType.java similarity index 81% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/ResponseType.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ResponseType.java index 78bc83585..c12f2b615 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/ResponseType.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ResponseType.java @@ -1,11 +1,11 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response; /** - * //TODO Class Javadoc Comment + * Enum for HTTP content-type response header Strings. * * @author Rsl1122 */ diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/api/BadRequestResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/api/BadRequestResponse.java similarity index 55% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/api/BadRequestResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/api/BadRequestResponse.java index 18c96c563..ca557b400 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/api/BadRequestResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/api/BadRequestResponse.java @@ -1,10 +1,10 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.webserver.response.api; +package com.djrapitops.plan.system.webserver.response.api; -import com.djrapitops.plan.systems.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.Response; /** * @author Fuzzlemann @@ -12,7 +12,7 @@ import com.djrapitops.plan.systems.webserver.response.Response; public class BadRequestResponse extends Response { public BadRequestResponse(String error) { - super.setHeader("HTTP/1.1 400 Bad Request"); - super.setContent(error); + super.setHeader("HTTP/1.1 400 Bad Request " + error); + super.setContent("400 Bad Request: " + error); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/api/JsonResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/api/JsonResponse.java similarity index 70% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/api/JsonResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/api/JsonResponse.java index fd4694a1c..bb17adb87 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/api/JsonResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/api/JsonResponse.java @@ -1,11 +1,11 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.webserver.response.api; +package com.djrapitops.plan.system.webserver.response.api; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.response.ResponseType; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.ResponseType; import com.google.gson.Gson; /** diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/api/SuccessResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/api/SuccessResponse.java similarity index 73% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/api/SuccessResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/api/SuccessResponse.java index c69435c30..bf34c7940 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/api/SuccessResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/api/SuccessResponse.java @@ -1,10 +1,10 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.webserver.response.api; +package com.djrapitops.plan.system.webserver.response.api; -import com.djrapitops.plan.systems.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.Response; /** * @author Fuzzlemann diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/pagecache/PageId.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/cache/PageId.java similarity index 77% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/pagecache/PageId.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/cache/PageId.java index 51d12471c..0b43938b5 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/pagecache/PageId.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/cache/PageId.java @@ -2,12 +2,12 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.webserver.pagecache; +package com.djrapitops.plan.system.webserver.response.cache; import java.util.UUID; /** - * Enum class for "magic" PageCache identifier values. + * Enum class for "magic" ResponseCache identifier values. * * @author Rsl1122 */ @@ -27,8 +27,10 @@ public enum PageId { CSS("css:"), // FAVICON_REDIRECT("Redirect:Favicon"), - AUTH_PROMPT("PromptAuth") - ; + AUTH_PROMPT("PromptAuth"), + // + PLAYER_PLUGINS_TAB("playerPluginsTab:"), + NETWORK_CONTENT("networkContent"); private final String id; diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/cache/ResponseCache.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/cache/ResponseCache.java new file mode 100644 index 000000000..2613fd395 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/cache/ResponseCache.java @@ -0,0 +1,106 @@ +package com.djrapitops.plan.system.webserver.response.cache; + +import com.djrapitops.plan.system.webserver.response.Response; + +import java.util.HashMap; +import java.util.Map; + +/** + * This class contains the page cache. + *

+ * It caches all Responses with their matching identifiers. + * This reduces CPU cycles and the time to wait for loading the pages. + * This is especially useful in situations where multiple clients are accessing the server. + * + * @author Fuzzlemann + * @since 3.6.0 + */ +public class ResponseCache { + + private static final Map cache = new HashMap<>(); + + /** + * Constructor used to hide the public constructor + */ + private ResponseCache() { + throw new IllegalStateException("Utility class"); + } + + /** + * Loads the response from the response cache. + *

+ * If the {@link Response} isn't cached, {@link ResponseLoader#createResponse()} in the {@code loader} + * is called to create the Response. + *

+ * If the Response is created, it's automatically cached. + * + * @param identifier The identifier of the page + * @param loader The {@link ResponseLoader} (How should it load the page if it's not cached) + * @return The Response that was cached or created by the {@link ResponseLoader loader} + */ + public static Response loadResponse(String identifier, ResponseLoader loader) { + Response response = loadResponse(identifier); + + if (response != null) { + return response; + } + + response = loader.createResponse(); + + cache.put(identifier, response); + + return response; + } + + /** + * Loads the page from the page cache. + * + * @param identifier The identifier of the page + * @return The Response that was cached or {@code null} if it wasn't + */ + public static Response loadResponse(String identifier) { + return cache.get(identifier); + } + + /** + * Puts the page into the page cache. + *

+ * If the cache already inherits that {@code identifier}, it's renewed. + * + * @param identifier The identifier of the page + * @param loader The {@link ResponseLoader} (How it should load the page) + */ + public static void cacheResponse(String identifier, ResponseLoader loader) { + Response response = loader.createResponse(); + cache.put(identifier, response); + } + + /** + * Checks if the page is cached. + * + * @param identifier The identifier of the page + * @return true if the page is cached + */ + public static boolean isCached(String identifier) { + return cache.containsKey(identifier); + } + + /** + * Clears the cache from all its contents. + */ + public static void clearCache() { + cache.clear(); + } + + /** + * This interface is used for providing the method to load the page. + * + * @author Fuzzlemann + * @since 4.2.0 + */ + public interface ResponseLoader { + + Response createResponse(); + + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/ErrorResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/ErrorResponse.java similarity index 86% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/ErrorResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/ErrorResponse.java index a3ec460f0..26a50d66f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/ErrorResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/ErrorResponse.java @@ -1,10 +1,11 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response.errors; -import com.djrapitops.plan.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.webserver.response.Response; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plan.utilities.file.FileUtil; import com.djrapitops.plugin.api.utility.log.Log; @@ -28,7 +29,7 @@ public class ErrorResponse extends Response { try { setContent(Theme.replaceColors(FileUtil.getStringFromResource("web/error.html"))); } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/ForbiddenResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/ForbiddenResponse.java similarity index 69% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/ForbiddenResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/ForbiddenResponse.java index ebf1a42dd..7bd81d274 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/ForbiddenResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/ForbiddenResponse.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response.errors; import com.djrapitops.plan.utilities.html.Html; @@ -9,12 +9,12 @@ import com.djrapitops.plan.utilities.html.Html; public class ForbiddenResponse extends ErrorResponse { public ForbiddenResponse() { super.setHeader("HTTP/1.1 403 Forbidden"); - super.setTitle(Html.FONT_AWESOME_ICON.parse("hand-stop-o")+" 403 Forbidden - Access Denied"); + super.setTitle(Html.FONT_AWESOME_ICON.parse("hand-stop-o") + " 403 Forbidden - Access Denied"); } public ForbiddenResponse(String msg) { super.setHeader("HTTP/1.1 403 Forbidden"); - super.setTitle("403 Forbidden - Access Denied"); + super.setTitle(Html.FONT_AWESOME_ICON.parse("hand-stop-o") + " 403 Forbidden - Access Denied"); super.setParagraph(msg); super.replacePlaceholders(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/InternalErrorResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/InternalErrorResponse.java similarity index 92% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/InternalErrorResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/InternalErrorResponse.java index 2531158ce..19c2e99b0 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/InternalErrorResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/InternalErrorResponse.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response.errors; import com.djrapitops.plan.utilities.html.Html; @@ -8,7 +8,7 @@ import com.djrapitops.plan.utilities.html.Html; */ public class InternalErrorResponse extends ErrorResponse { - public InternalErrorResponse(Throwable e, String cause) { + public InternalErrorResponse(String cause, Throwable e) { super.setHeader("HTTP/1.1 500 Internal Error"); super.setTitle(Html.FONT_AWESOME_ICON.parse("bug") + " 500 Internal Error occurred"); diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/NotFoundResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/NotFoundResponse.java similarity index 76% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/NotFoundResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/NotFoundResponse.java index e32dd3d6a..46273df1b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/NotFoundResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/NotFoundResponse.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response.errors; import com.djrapitops.plan.utilities.html.Html; @@ -10,14 +10,14 @@ public class NotFoundResponse extends ErrorResponse { public NotFoundResponse() { super.setHeader("HTTP/1.1 404 Not Found"); - super.setTitle(Html.FONT_AWESOME_ICON.parse("map-signs")+" 404 Not Found"); + super.setTitle(Html.FONT_AWESOME_ICON.parse("map-signs") + " 404 Not Found"); super.setParagraph("Page does not exist."); super.replacePlaceholders(); } public NotFoundResponse(String msg) { super.setHeader("HTTP/1.1 404 Not Found"); - super.setTitle("404 Not Found"); + super.setTitle(Html.FONT_AWESOME_ICON.parse("map-signs") + " 404 Not Found"); super.setParagraph(msg); super.replacePlaceholders(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/UnauthorizedServerResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/UnauthorizedServerResponse.java new file mode 100644 index 000000000..cda90bd7b --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/errors/UnauthorizedServerResponse.java @@ -0,0 +1,20 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.response.errors; + +/** + * Response when Server is not found in database when attempting to InfoRequest. + * + * @author Rsl1122 + */ +public class UnauthorizedServerResponse extends ErrorResponse { + + public UnauthorizedServerResponse(String message) { + super.setHeader("HTTP/1.1 412 Unauthorized"); + super.setTitle("Unauthorized Server"); + super.setParagraph(message); + super.replacePlaceholders(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/AnalysisPageResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/AnalysisPageResponse.java new file mode 100644 index 000000000..4f121cc0c --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/AnalysisPageResponse.java @@ -0,0 +1,41 @@ +package com.djrapitops.plan.system.webserver.response.pages; + +import com.djrapitops.plan.api.exceptions.connection.ConnectionFailException; +import com.djrapitops.plan.api.exceptions.connection.NoServersException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.info.InfoSystem; +import com.djrapitops.plan.system.processing.Processor; +import com.djrapitops.plan.system.webserver.pages.parsing.AnalysisPage; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.errors.NotFoundResponse; +import com.djrapitops.plugin.api.utility.log.Log; + +import java.util.UUID; + +/** + * @author Rsl1122 + * @since 3.5.2 + */ +public class AnalysisPageResponse extends Response { + + public static AnalysisPageResponse refreshNow(UUID serverUUID) { + Processor.queue(() -> { + try { + InfoSystem.getInstance().generateAnalysisPage(serverUUID); + } catch (NoServersException | ConnectionFailException e) { + ResponseCache.cacheResponse(PageId.SERVER.of(serverUUID), () -> new NotFoundResponse(e.getMessage())); + } catch (WebException e) { + // TODO Exception handling + Log.toLog(AnalysisPageResponse.class.getName(), e); + } + }); + return new AnalysisPageResponse(AnalysisPage.getRefreshingHtml()); + } + + public AnalysisPageResponse(String html) { + super.setHeader("HTTP/1.1 200 OK"); + super.setContent(html); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/DebugPageResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/DebugPageResponse.java similarity index 64% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/DebugPageResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/DebugPageResponse.java index 153cc0aff..23e7a81a1 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/DebugPageResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/DebugPageResponse.java @@ -2,18 +2,22 @@ * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response.pages; -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.ServerVariableHolder; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.systems.info.server.BungeeServerInfoManager; -import com.djrapitops.plan.systems.info.server.ServerInfo; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.info.connection.ConnectionLog; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.info.server.ServerProperties; +import com.djrapitops.plan.system.webserver.response.errors.ErrorResponse; +import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.file.FileUtil; import com.djrapitops.plan.utilities.html.Html; import com.djrapitops.plugin.api.Benchmark; -import com.djrapitops.plugin.api.Check; +import com.djrapitops.plugin.api.utility.log.ErrorLogger; import com.djrapitops.plugin.api.utility.log.Log; import java.io.File; @@ -50,21 +54,57 @@ public class DebugPageResponse extends ErrorResponse { appendServerInformation(content); - if (Check.isBungeeAvailable()) { - appendBungeeConfiguration(content); - } - + appendConnectionLog(content); appendLoggedErrors(content); - appendDebugLog(content); appendBenchmarks(content); + appendDebugLog(content); appendConfig(content); return content.toString(); } + private void appendConnectionLog(StringBuilder content) { + try { + Map> logEntries = ConnectionLog.getLogEntries(); + + content.append("

**Connection Log:**
"); + content.append("Server Address | Request Type | Response | Sent
") + .append("-- | -- | -- | --
"); + for (Map.Entry> entry : logEntries.entrySet()) { + String address = entry.getKey(); + Map requests = entry.getValue(); + for (Map.Entry requestEntry : requests.entrySet()) { + String infoRequest = requestEntry.getKey(); + ConnectionLog.Entry logEntry = requestEntry.getValue(); + + content.append(address).append(" | ") + .append(infoRequest).append(" | ") + .append(logEntry.getResponseCode()).append(" | ") + .append(FormatUtils.formatTimeStampSecond(logEntry.getTimeSent())).append("
"); + } + + } + content.append("
"); + + content.append("
**Servers:**
"); + List servers = ConnectionSystem.getInstance().getBukkitServers(); + content.append("Server Name | Address | UUID
") + .append("-- | -- | --
"); + for (Server server : servers) { + content.append(server.getName()).append(" | ") + .append(server.getWebAddress()).append(" | ") + .append(server.getUuid()).append("
"); + } + content.append("
"); + + } catch (Exception e) { + Log.toLog(this.getClass(), e); + } + } + private void appendServerInformation(StringBuilder content) { - IPlan plugin = MiscUtils.getIPlan(); - ServerVariableHolder variable = plugin.getVariable(); + PlanPlugin plugin = PlanPlugin.getInstance(); + ServerProperties variable = ServerInfo.getServerProperties(); content.append("
### Server Information
") .append("**Plan Version:** ").append(plugin.getVersion()).append("
"); @@ -75,12 +115,17 @@ public class DebugPageResponse extends ErrorResponse { .append(" ").append(variable.getVersion()); content.append("
"); - content.append("**Database:** ").append(plugin.getDB().getName()); - try { - content.append(" schema v").append(plugin.getDB().getVersion()); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); + Database database = Database.getActive(); + content.append("**Database:** ").append(database.getName()); + + if (database instanceof SQLDB) { + try { + content.append(" schema v").append(((SQLDB) database).getVersion()); + } catch (SQLException e) { + Log.toLog(this.getClass(), e); + } } + content.append("

"); RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); @@ -111,48 +156,19 @@ public class DebugPageResponse extends ErrorResponse { private void appendConfig(StringBuilder content) { try { - File configFile = new File(MiscUtils.getIPlan().getDataFolder(), "config.yml"); + File configFile = new File(PlanPlugin.getInstance().getDataFolder(), "config.yml"); if (configFile.exists()) { content.append("
### config.yml
```
"); FileUtil.lines(configFile, Charset.forName("UTF-8")) - .stream().filter(line -> !line.toLowerCase().contains("pass")) + .stream().filter(line -> !line.toLowerCase().contains("pass") && !line.toLowerCase().contains("secret")) .forEach(line -> content.append(line).append("
")); content.append("```
"); } } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } } - private void appendBungeeConfiguration(StringBuilder content) { - - PlanBungee plugin = PlanBungee.getInstance(); - BungeeServerInfoManager serverInfoManager = plugin.getServerInfoManager(); - Collection online = serverInfoManager.getOnlineBukkitServers(); - Collection bukkitServers = serverInfoManager.getBukkitServers(); - - if (!bukkitServers.isEmpty()) { - content.append("

If your issue is about Bungee-Bukkit connection relations, please include the following debug information of available servers as well:

"); - for (ServerInfo info : bukkitServers) { - String link = Html.LINK.parse(info.getWebAddress() + "/debug", info.getWebAddress() + "/debug"); - content.append("

").append(link).append("

"); - } - } - - content.append("
### Bungee Configuration
"); - - content.append("Server name | Online | Address | UUID
") - .append("-- | -- | -- | --
"); - for (ServerInfo info : bukkitServers) { - content.append(info.getName()).append(" | ") - .append(online.contains(info) ? "Online" : "Offline").append(" | ") - .append(info.getWebAddress()).append(" | ") - .append(info.getUuid()).append("
"); - } - - content.append("
"); - } - private void appendBenchmarks(StringBuilder content) { content.append("
### Benchmarks
```
"); try { @@ -169,7 +185,7 @@ public class DebugPageResponse extends ErrorResponse { try { content.append("
### Logged Errors
"); - TreeMap> errors = MiscUtils.getIPlan().getInfoManager().getErrors(); + TreeMap> errors = ErrorLogger.getLoggedErrors(PlanPlugin.getInstance()); if (!errors.isEmpty()) { List errorLines = new ArrayList<>(); @@ -194,7 +210,7 @@ public class DebugPageResponse extends ErrorResponse { } content.append("
"); } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/InspectPageResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/InspectPageResponse.java new file mode 100644 index 000000000..1ce21334e --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/InspectPageResponse.java @@ -0,0 +1,52 @@ +package com.djrapitops.plan.system.webserver.response.pages; + +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import com.djrapitops.plan.system.webserver.response.errors.ErrorResponse; +import com.djrapitops.plan.system.webserver.response.pages.parts.InspectPagePluginsContent; +import org.apache.commons.lang3.text.StrSubstitutor; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author Rsl1122 + * @since 3.5.2 + */ +public class InspectPageResponse extends Response { + + private final UUID uuid; + + public InspectPageResponse(UUID uuid, String html) { + super.setHeader("HTTP/1.1 200 OK"); + super.setContent(Theme.replaceColors(html)); + this.uuid = uuid; + } + + @Override + public String getContent() { + Map replaceMap = new HashMap<>(); + InspectPagePluginsContent pluginsTab = (InspectPagePluginsContent) + ResponseCache.loadResponse(PageId.PLAYER_PLUGINS_TAB.of(uuid)); + String[] inspectPagePluginsTab = pluginsTab != null ? pluginsTab.getContents() : getCalculating(); + replaceMap.put("navPluginsTabs", inspectPagePluginsTab[0]); + replaceMap.put("pluginsTabs", inspectPagePluginsTab[1]); + + return StrSubstitutor.replace(super.getContent(), replaceMap); + } + + private String[] getCalculating() { + return new String[]{"
  • Calculating...
  • ", ""}; + } + + public static InspectPageResponse getRefreshing() { + ErrorResponse refreshPage = new ErrorResponse(); + refreshPage.setTitle("Player page request is being processed.."); + refreshPage.setParagraph(" Page will refresh automatically.."); + refreshPage.replacePlaceholders(); + return new InspectPageResponse(null, refreshPage.getContent()); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/PlayersPageResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/PlayersPageResponse.java similarity index 75% rename from Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/PlayersPageResponse.java rename to Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/PlayersPageResponse.java index 941cfc8f0..ace6d0bfc 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/PlayersPageResponse.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/PlayersPageResponse.java @@ -1,15 +1,18 @@ -package com.djrapitops.plan.systems.webserver.response; +package com.djrapitops.plan.system.webserver.response.pages; -import com.djrapitops.plan.api.IPlan; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.api.exceptions.database.DBException; import com.djrapitops.plan.data.container.GeoInfo; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.container.UserInfo; import com.djrapitops.plan.data.element.TableContainer; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.theme.Theme; +import com.djrapitops.plan.system.PlanSystem; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.errors.InternalErrorResponse; import com.djrapitops.plan.utilities.FormatUtils; -import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plan.utilities.analysis.AnalysisUtils; import com.djrapitops.plan.utilities.comparators.GeoInfoComparator; import com.djrapitops.plan.utilities.comparators.UserInfoLastPlayedComparator; @@ -20,7 +23,6 @@ import com.djrapitops.plugin.api.utility.log.Log; import org.apache.commons.lang3.text.StrSubstitutor; import java.io.IOException; -import java.sql.SQLException; import java.util.*; /** @@ -32,8 +34,10 @@ public class PlayersPageResponse extends Response { public PlayersPageResponse() { super.setHeader("HTTP/1.1 200 OK"); try { - IPlan plugin = MiscUtils.getIPlan(); - List names = new ArrayList<>(plugin.getDB().getUsersTable().getPlayerNames().values()); + PlanSystem system = PlanSystem.getInstance(); + PlanPlugin plugin = PlanPlugin.getInstance(); + Database db = system.getDatabaseSystem().getActiveDatabase(); + List names = new ArrayList<>(db.fetch().getPlayerNames().values()); Collections.sort(names); Map replace = new HashMap<>(); if (Check.isBukkitAvailable()) { @@ -41,22 +45,22 @@ public class PlayersPageResponse extends Response { } else { replace.put("networkName", Settings.BUNGEE_NETWORK_NAME.toString()); } - replace.put("playersTable", buildPlayersTable(plugin.getDB())); + replace.put("playersTable", buildPlayersTable(db)); replace.put("version", plugin.getVersion()); super.setContent(Theme.replaceColors(StrSubstitutor.replace(FileUtil.getStringFromResource("web/players.html"), replace))); - } catch (SQLException | IOException e) { - Log.toLog(this.getClass().getName(), e); - setContent(new InternalErrorResponse(e, "/players").getContent()); + } catch (DBException | IOException e) { + Log.toLog(this.getClass(), e); + setContent(new InternalErrorResponse("/players", e).getContent()); } } - public static String buildPlayersTable(Database db) { + private String buildPlayersTable(Database db) { try { - List users = new ArrayList<>(db.getUsersTable().getUsers().values()); + List users = new ArrayList<>(db.fetch().getUsers().values()); users.sort(new UserInfoLastPlayedComparator()); - Map lastSeenForAllPlayers = db.getSessionsTable().getLastSeenForAllPlayers(); - Map> sessionsByUser = AnalysisUtils.sortSessionsByUser(db.getSessionsTable().getAllSessions(false)); - Map> geoInfos = db.getIpsTable().getAllGeoInfo(); + Map lastSeenForAllPlayers = db.fetch().getLastSeenForAllPlayers(); + Map> sessionsByUser = AnalysisUtils.sortSessionsByUser(db.fetch().getSessionsWithNoExtras()); + Map> geoInfos = db.fetch().getAllGeoInfo(); String userS = Html.FONT_AWESOME_ICON.parse("user") + " Player"; String playtimeS = Html.FONT_AWESOME_ICON.parse("clock-o") + " Playtime"; @@ -96,8 +100,8 @@ public class PlayersPageResponse extends Response { List sessions = sessionsByUser.getOrDefault(uuid, new ArrayList<>()); int sessionCount = sessions.size(); - long playtime = sessionCount != 0 ? sessions.stream().map(Session::getLength) - .mapToLong(p -> p) + long playtime = sessionCount != 0 ? sessions.stream() + .mapToLong(Session::getLength) .sum() : 0L; long registered = userInfo.getRegistered(); long lastSeen = lastSeenForAllPlayers.getOrDefault(uuid, 0L); @@ -119,9 +123,9 @@ public class PlayersPageResponse extends Response { } catch (IllegalArgumentException ignored) { } return html.append("").toString(); - } catch (SQLException e) { + } catch (DBException e) { Log.toLog(PlayersPageResponse.class.getClass().getName(), e); - return new InternalErrorResponse(e, "/players").getContent(); + return new InternalErrorResponse("/players", e).getContent(); } } } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/parts/InspectPagePluginsContent.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/parts/InspectPagePluginsContent.java new file mode 100644 index 000000000..2fad77811 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/parts/InspectPagePluginsContent.java @@ -0,0 +1,92 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.response.pages.parts; + +import com.djrapitops.plan.data.element.InspectContainer; +import com.djrapitops.plan.data.plugin.HookHandler; +import com.djrapitops.plan.data.plugin.PluginData; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.utilities.comparators.PluginDataNameComparator; +import com.djrapitops.plan.utilities.html.Html; +import com.djrapitops.plan.utilities.html.HtmlStructure; +import com.djrapitops.plan.utilities.html.structure.AnalysisPluginsTabContentCreator; + +import java.util.*; + +/** + * Represents Plugins tabs on Inspect page. + *

    + * Extends Response so that it can be stored in ResponseCache. + * + * @author Rsl1122 + */ +public class InspectPagePluginsContent extends Response { + + // ServerUUID, {nav, html} + private final Map pluginsTab; + + public InspectPagePluginsContent() { + pluginsTab = new HashMap<>(); + } + + public InspectPagePluginsContent(UUID serverUUID, String nav, String html) { + pluginsTab = new HashMap<>(); + addTab(serverUUID, nav, html); + } + + public static InspectPagePluginsContent generateForThisServer(UUID playerUUID) { + HookHandler hookHandler = HookHandler.getInstance(); + Map containers = hookHandler.getInspectContainersFor(playerUUID); + String serverName = ServerInfo.getServerName(); + String actualServerName = serverName.equals("Plan") ? "Server " + ServerInfo.getServerID() : serverName; + if (containers.isEmpty()) { + return new InspectPagePluginsContent(playerUUID, "

  • " + actualServerName + " (No Data)
  • ", Html.CARD.parse("

    No Data (" + actualServerName + ")

    ")); + } + + String nav = "
  • " + actualServerName + "
  • "; + + StringBuilder tab = new StringBuilder(); + tab.append("
    "); + + List order = new ArrayList<>(containers.keySet()); + order.sort(new PluginDataNameComparator()); + + for (PluginData pluginData : order) { + InspectContainer container = containers.get(pluginData); + AnalysisPluginsTabContentCreator.appendThird(pluginData, container, tab); + } + + tab.append("
    "); + + return new InspectPagePluginsContent(ServerInfo.getServerUUID(), nav, tab.toString()); + } + + public void addTab(UUID serverUUID, String nav, String html) { + pluginsTab.put(serverUUID, new String[]{nav, html}); + } + + public void addTab(InspectPagePluginsContent content) { + pluginsTab.putAll(content.pluginsTab); + } + + public String[] getContents() { + if (pluginsTab.isEmpty()) { + return HtmlStructure.createInspectPageTabContentCalculating(); + } + + List order = new ArrayList<>(pluginsTab.values()); + // Sort serverNames alphabetically + order.sort(Comparator.comparing(name -> name[0])); + + StringBuilder nav = new StringBuilder(); + StringBuilder tabs = new StringBuilder(); + for (String[] tab : order) { + nav.append(tab[0]); + tabs.append(tab[1]); + } + return new String[]{nav.toString(), tabs.toString()}; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/parts/NetworkPageContent.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/parts/NetworkPageContent.java new file mode 100644 index 000000000..bd303067a --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/pages/parts/NetworkPageContent.java @@ -0,0 +1,50 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.webserver.response.pages.parts; + +import com.djrapitops.plan.system.webserver.response.Response; + +import java.util.*; + +/** + * Represents Servers tab content of Network page. + *

    + * Extends Response so that it can be stored in ResponseCache. + * + * @author Rsl1122 + */ +public class NetworkPageContent extends Response { + + private final Map content; + + public NetworkPageContent() { + content = new HashMap<>(); + } + + public NetworkPageContent(String serverName, String html) { + this(); + content.put(serverName, html); + } + + public void addElement(String serverName, String html) { + content.put(serverName, html); + } + + public String getContents() { + if (content.isEmpty()) { + return ""; // TODO "No Servers" + } + + List serverNames = new ArrayList<>(content.keySet()); + Collections.sort(serverNames); + + StringBuilder b = new StringBuilder(); + for (String serverName : serverNames) { + b.append(content.get(serverName)); + } + + return b.toString(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/SubSystem.java b/Plan/src/main/java/com/djrapitops/plan/systems/SubSystem.java deleted file mode 100644 index b85958045..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/SubSystem.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems; - -import com.djrapitops.plan.api.exceptions.PlanEnableException; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public interface SubSystem { - - void init() throws PlanEnableException; - - void close(); - -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/Systems.java b/Plan/src/main/java/com/djrapitops/plan/systems/Systems.java deleted file mode 100644 index 2abdfcf12..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/Systems.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.systems.file.FileSystem; -import com.djrapitops.plan.systems.file.config.ConfigSystem; -import com.djrapitops.plan.systems.file.config.PlanBungeeConfigSystem; -import com.djrapitops.plan.systems.file.config.PlanConfigSystem; -import com.djrapitops.plan.systems.file.database.DBSystem; -import com.djrapitops.plan.systems.file.database.PlanBungeeDBSystem; -import com.djrapitops.plan.systems.file.database.PlanDBSystem; -import com.djrapitops.plan.systems.tasks.PlanBungeeTaskSystem; -import com.djrapitops.plan.systems.tasks.PlanTaskSystem; -import com.djrapitops.plan.systems.tasks.TaskSystem; -import com.djrapitops.plan.systems.update.VersionCheckSystem; -import com.djrapitops.plan.systems.webserver.WebServerSystem; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plugin.api.utility.log.Log; -import org.apache.commons.lang3.ArrayUtils; - -/** - * Layer for reducing - * - * @author Rsl1122 - */ -public class Systems { - - private FileSystem fileSystem; - private ConfigSystem configSystem; - private DBSystem databaseSystem; - private Theme themeSystem; - - private WebServerSystem webServerSystem; - - private TaskSystem taskSystem; - - private VersionCheckSystem versionCheckSystem; - - /** - * Constructor for Bukkit version. - * - * @param plugin Plan instance - */ - public Systems(Plan plugin) { - fileSystem = new FileSystem(plugin); - configSystem = new PlanConfigSystem(); - databaseSystem = new PlanDBSystem(); - versionCheckSystem = new VersionCheckSystem(plugin.getVersion()); - - taskSystem = new PlanTaskSystem(); - - webServerSystem = new WebServerSystem(); - themeSystem = new Theme(); - } - - /** - * Constructor for Bungee version. - * - * @param plugin PlanBungee instance - */ - public Systems(PlanBungee plugin) { - fileSystem = new FileSystem(plugin); - configSystem = new PlanBungeeConfigSystem(); - databaseSystem = new PlanBungeeDBSystem(); - versionCheckSystem = new VersionCheckSystem(plugin.getVersion()); - - taskSystem = new PlanBungeeTaskSystem(); - - webServerSystem = new WebServerSystem(); - themeSystem = new Theme(); - } - - private SubSystem[] getSubSystems() { - return new SubSystem[]{ - fileSystem, - configSystem, - versionCheckSystem, - databaseSystem, - taskSystem, - webServerSystem, - themeSystem - }; - } - - public void close() { - SubSystem[] subSystems = getSubSystems(); - ArrayUtils.reverse(subSystems); - for (SubSystem subSystem : subSystems) { - try { - subSystem.close(); - } catch (Exception e) { - Log.toLog(Systems.class, e); - } - } - } - - public static Systems getInstance() { - return MiscUtils.getIPlan().getSystems(); - } - - public FileSystem getFileSystem() { - return fileSystem; - } - - public DBSystem getDatabaseSystem() { - return databaseSystem; - } - - public ConfigSystem getConfigSystem() { - return configSystem; - } - - public WebServerSystem getWebServerSystem() { - return webServerSystem; - } - - public VersionCheckSystem getVersionCheckSystem() { - return versionCheckSystem; - } - - public Theme getThemeSystem() { - return themeSystem; - } - - public TaskSystem getTaskSystem() { - return taskSystem; - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/cache/SessionCache.java b/Plan/src/main/java/com/djrapitops/plan/systems/cache/SessionCache.java deleted file mode 100644 index 95740524d..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/cache/SessionCache.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.djrapitops.plan.systems.cache; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.systems.processing.Processor; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; - -/** - * This class is used to store active sessions of players in memory. - * - * @author Rsl1122 - * @since 3.0.0 - */ -public class SessionCache { - - private static final Map activeSessions = new HashMap<>(); - protected final Plan plugin; - - /** - * Class Constructor. - */ - public SessionCache(Plan plugin) { - this.plugin = plugin; - } - - public void cacheSession(UUID uuid, Session session) { - activeSessions.put(uuid, session); - plugin.addToProcessQueue(new Processor(plugin) { - @Override - public void process() { - plugin.getInfoManager().cachePlayer(uuid); - } - }); - } - - public void endSession(UUID uuid, long time) { - try { - Session session = activeSessions.get(uuid); - if (session == null) { - return; - } - session.endSession(time); - plugin.getDB().getSessionsTable().saveSession(uuid, session); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } finally { - activeSessions.remove(uuid); - plugin.getInfoManager().cachePlayer(uuid); - } - } - - public void refreshActiveSessionsState() { - for (Session session : activeSessions.values()) { - session.getWorldTimes().updateState(MiscUtils.getTime()); - } - } - - /** - * Used to get the Session of the player in the sessionCache. - * - * @param uuid UUID of the player. - * @return Session or null if not cached. - */ - public Optional getCachedSession(UUID uuid) { - Session session = activeSessions.get(uuid); - if (session != null) { - return Optional.of(session); - } - return Optional.empty(); - } - - /** - * Used to get the Map of active sessions. - *

    - * Used for testing. - * - * @return key:value UUID:Session - */ - public static Map getActiveSessions() { - return activeSessions; - } - - public static void clear() { - activeSessions.clear(); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/file/config/ConfigSystem.java b/Plan/src/main/java/com/djrapitops/plan/systems/file/config/ConfigSystem.java deleted file mode 100644 index 6bb45d30d..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/file/config/ConfigSystem.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.file.config; - -import com.djrapitops.plan.api.exceptions.PlanEnableException; -import com.djrapitops.plan.systems.SubSystem; -import com.djrapitops.plan.systems.Systems; -import com.djrapitops.plan.systems.file.FileSystem; -import com.djrapitops.plugin.api.config.Config; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.io.IOException; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public abstract class ConfigSystem implements SubSystem { - - protected Config config; - - public static ConfigSystem getInstance() { - return Systems.getInstance().getConfigSystem(); - } - - public Config getConfig() { - return config; - } - - @Override - public void init() throws PlanEnableException { - try { - config = new Config(FileSystem.getConfigFile()); - copyDefaults(); - config.save(); - } catch (IOException e) { - throw new PlanEnableException("Config Subsystem failed to initialize", e); - } - } - - protected abstract void copyDefaults() throws IOException; - - @Override - public void close() { - - } - - public static void reload() { - try { - getInstance().config.read(); - } catch (IOException e) { - Log.toLog(ConfigSystem.class, e); - } - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/file/database/DBSystem.java b/Plan/src/main/java/com/djrapitops/plan/systems/file/database/DBSystem.java deleted file mode 100644 index 148db067e..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/file/database/DBSystem.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.file.database; - -import com.djrapitops.plan.api.exceptions.DatabaseInitException; -import com.djrapitops.plan.api.exceptions.PlanEnableException; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.SubSystem; -import com.djrapitops.plan.systems.Systems; -import com.djrapitops.plugin.api.Benchmark; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.utilities.Verify; - -import java.sql.SQLException; -import java.util.HashSet; -import java.util.Set; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public abstract class DBSystem implements SubSystem { - - protected SQLDB db; - protected Set databases; - - public DBSystem() { - databases = new HashSet<>(); - } - - public static DBSystem getInstance() { - return Systems.getInstance().getDatabaseSystem(); - } - - @Override - public void init() throws PlanEnableException { - try { - Benchmark.start("Init Database"); - Log.info(Locale.get(Msg.ENABLE_DB_INIT).toString()); - initDatabase(); - db.scheduleClean(10L); - Log.info(Locale.get(Msg.ENABLE_DB_INFO).parse(db.getConfigName())); - Benchmark.stop("Systems", "Init Database"); - } catch (DatabaseInitException e) { - throw new PlanEnableException(db.getName() + "-Database failed to initialize", e); - } - } - - protected abstract void initDatabase() throws DatabaseInitException; - - public Set getDatabases() { - return databases; - } - - public void setDatabases(Set databases) { - this.databases = databases; - } - - @Override - public void close() { - try { - if (db != null) { - db.close(); - } - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - } - - public Database getActiveDatabase() { - return db; - } - - public static SQLDB getActiveDatabase(String dbName) throws DatabaseInitException { - for (SQLDB database : DBSystem.getInstance().getDatabases()) { - String dbConfigName = database.getConfigName(); - if (Verify.equalsIgnoreCase(dbName, dbConfigName)) { - database.init(); - return database; - } - } - throw new DatabaseInitException(Locale.get(Msg.ENABLE_FAIL_WRONG_DB) + " " + dbName); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/file/database/PlanBungeeDBSystem.java b/Plan/src/main/java/com/djrapitops/plan/systems/file/database/PlanBungeeDBSystem.java deleted file mode 100644 index 25e2eb9ec..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/file/database/PlanBungeeDBSystem.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.file.database; - -import com.djrapitops.plan.api.exceptions.DatabaseInitException; -import com.djrapitops.plan.database.databases.MySQLDB; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public class PlanBungeeDBSystem extends DBSystem { - - - @Override - protected void initDatabase() throws DatabaseInitException { - db = new MySQLDB(); - databases.add(db); - db.init(); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/file/database/PlanDBSystem.java b/Plan/src/main/java/com/djrapitops/plan/systems/file/database/PlanDBSystem.java deleted file mode 100644 index d367247b1..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/file/database/PlanDBSystem.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.file.database; - -import com.djrapitops.plan.api.exceptions.DatabaseInitException; -import com.djrapitops.plan.database.databases.MySQLDB; -import com.djrapitops.plan.database.databases.SQLiteDB; -import com.djrapitops.plan.settings.Settings; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public class PlanDBSystem extends DBSystem { - - @Override - protected void initDatabase() throws DatabaseInitException { - databases.add(new MySQLDB()); - databases.add(new SQLiteDB()); - - String dbType = Settings.DB_TYPE.toString().toLowerCase().trim(); - db = getActiveDatabase(dbType); - db.init(); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/BukkitInformationManager.java b/Plan/src/main/java/com/djrapitops/plan/systems/info/BukkitInformationManager.java deleted file mode 100644 index 0702d0078..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/BukkitInformationManager.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.info; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.*; -import com.djrapitops.plan.command.commands.AnalyzeCommand; -import com.djrapitops.plan.data.AnalysisData; -import com.djrapitops.plan.data.element.InspectContainer; -import com.djrapitops.plan.data.plugin.HookHandler; -import com.djrapitops.plan.data.plugin.PluginData; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.info.parsing.AnalysisPageParser; -import com.djrapitops.plan.systems.info.parsing.InspectPageParser; -import com.djrapitops.plan.systems.processing.Processor; -import com.djrapitops.plan.systems.webserver.WebServer; -import com.djrapitops.plan.systems.webserver.WebServerSystem; -import com.djrapitops.plan.systems.webserver.pagecache.PageCache; -import com.djrapitops.plan.systems.webserver.pagecache.PageId; -import com.djrapitops.plan.systems.webserver.response.*; -import com.djrapitops.plan.systems.webserver.webapi.WebAPIManager; -import com.djrapitops.plan.systems.webserver.webapi.bukkit.AnalysisReadyWebAPI; -import com.djrapitops.plan.systems.webserver.webapi.bukkit.AnalyzeWebAPI; -import com.djrapitops.plan.systems.webserver.webapi.bukkit.RequestInspectPluginsTabBukkitWebAPI; -import com.djrapitops.plan.systems.webserver.webapi.bungee.*; -import com.djrapitops.plan.systems.webserver.webapi.universal.PingWebAPI; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plan.utilities.analysis.Analysis; -import com.djrapitops.plan.utilities.file.export.HtmlExport; -import com.djrapitops.plan.utilities.html.HtmlStructure; -import com.djrapitops.plan.utilities.html.structure.InspectPluginsTabContentCreator; -import com.djrapitops.plugin.api.utility.log.ErrorLogger; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.io.IOException; -import java.sql.SQLException; -import java.util.*; - -/** - * Manages the Information going to the PageCache. - *

    - * This means Inspect and Analysis pages as well as managing what is sent to Bungee WebServer when one is in use. - * - * @author Rsl1122 - */ -public class BukkitInformationManager extends InformationManager { - - private final Plan plugin; - private final DataCache dataCache; - private final Analysis analysis; - - private AnalysisData analysisData; - private String analysisPluginsTab; - private Long refreshDate; - - private final Map pluginsTabContents; - - public BukkitInformationManager(Plan plugin) { - this.plugin = plugin; - dataCache = new DataCache(plugin); - analysis = new Analysis(plugin); - pluginsTabContents = new HashMap<>(); - usingAnotherWebServer = false; - } - - public void updateConnection() { - Optional bungeeConnectionAddress = plugin.getServerInfoManager().getBungeeConnectionAddress(); - if (bungeeConnectionAddress.isPresent() && Settings.BUNGEE_OVERRIDE_STANDALONE_MODE.isFalse()) { - webServerAddress = bungeeConnectionAddress.get(); - attemptConnection(); - } else { - usingAnotherWebServer = false; - } - } - - @Override - public void refreshAnalysis(UUID serverUUID) { - if (Plan.getServerUUID().equals(serverUUID)) { - plugin.getDataCache().cacheSavedNames(); - analysis.runAnalysis(this); - } else if (usingAnotherWebServer) { - try { - getWebAPI().getAPI(AnalyzeWebAPI.class).sendRequest(webServerAddress, serverUUID); - } catch (WebAPIFailException e) { - Log.error("Failed to request Analysis refresh from Bungee."); - } catch (WebAPIException e) { - attemptConnection(); - refreshAnalysis(serverUUID); - } - } - - } - - @Override - public void cachePlayer(UUID uuid) { - if (uuid == null) { - Log.debug("BukkitInformationManager.cachePlayer: UUID was null"); - return; - } - if (usingAnotherWebServer) { - try { - getWebAPI().getAPI(PostHtmlWebAPI.class).sendInspectHtml(webServerAddress, uuid, getPlayerHtml(uuid)); - } catch (WebAPIFailException e) { - Log.error("Failed to request Inspect from Bungee."); - } catch (WebAPIException e) { - attemptConnection(); - cachePlayer(uuid); - } catch (ParseException e) { - if (!(e.getCause() instanceof IllegalStateException)) { - Log.toLog(this.getClass().getName(), e); - } - } - } else { - PageCache.cachePage(PageId.PLAYER.of(uuid), () -> { - try { - return new InspectPageResponse(this, uuid); - } catch (ParseException e) { - if (e.getCause() instanceof IllegalStateException) { - return new NotFoundResponse( - "Player just registered, so the data was not yet in the database. " + - "Please wait until they log off or use /plan inspect " - ); - } - return new InternalErrorResponse(e, this.getClass().getName()); - } - }); - if (Settings.ANALYSIS_EXPORT.isTrue()) { - HtmlExport.exportPlayer(plugin, uuid); - } - } - plugin.addToProcessQueue(new Processor(uuid) { - @Override - public void process() { - cacheInspectPluginsTab(object); - } - }); - } - - public void cacheInspectPluginsTab(UUID uuid) { - cacheInspectPluginsTab(uuid, this.getClass()); - } - - public void cacheInspectPluginsTab(UUID uuid, Class origin) { - if (usingAnotherWebServer && !origin.equals(RequestInspectPluginsTabBukkitWebAPI.class)) { - try { - getWebAPI().getAPI(RequestPluginsTabWebAPI.class).sendRequest(webServerAddress, uuid); - } catch (WebAPIFailException e) { - Log.error("Failed send Player Plugins tab contents to BungeeCord."); - } catch (WebAPIException e) { - attemptConnection(); - cacheInspectPluginsTab(uuid, origin); - } - } else { - HookHandler hookHandler = plugin.getHookHandler(); - List plugins = hookHandler.getAdditionalDataSources(); - Map containers = new HashMap<>(); - for (PluginData pluginData : plugins) { - InspectContainer inspectContainer = new InspectContainer(); - try { - InspectContainer container = pluginData.getPlayerData(uuid, inspectContainer); - if (container != null && !container.isEmpty()) { - containers.put(pluginData, container); - } - } catch (Exception e) { - String sourcePlugin = pluginData.getSourcePlugin(); - Log.error("PluginData caused exception: " + sourcePlugin); - Log.toLog(this.getClass().getName() + " " + sourcePlugin, e); - } - } - - cacheInspectPluginsTab(uuid, InspectPluginsTabContentCreator.createContent(containers)); - } - } - - public void cacheInspectPluginsTab(UUID uuid, String[] contents) { - if (usingAnotherWebServer) { - try { - getWebAPI().getAPI(PostInspectPluginsTabWebAPI.class).sendPluginsTab(webServerAddress, uuid, contents); - } catch (WebAPIFailException e) { - Log.error("Failed send Player HTML to BungeeCord."); - } catch (WebAPIException e) { - attemptConnection(); - cacheInspectPluginsTab(uuid, contents); - } - } else { - pluginsTabContents.put(uuid, contents); - Response inspectResponse = PageCache.loadPage(PageId.PLAYER.of(uuid)); - if (inspectResponse != null && inspectResponse instanceof InspectPageResponse) { - ((InspectPageResponse) inspectResponse).setInspectPagePluginsTab(contents); - } - } - } - - @Override - public String[] getPluginsTabContent(UUID uuid) { - String[] calculating = HtmlStructure.createInspectPageTabContentCalculating(); - return pluginsTabContents.getOrDefault(uuid, calculating); - } - - @Override - public boolean isCached(UUID uuid) { - if (usingAnotherWebServer) { - try { - return getWebAPI().getAPI(IsCachedWebAPI.class).isInspectCached(webServerAddress, uuid); - } catch (WebAPIFailException e) { - Log.error("Failed check Bungee Player Cache status."); - } catch (WebAPIException e) { - attemptConnection(); - return isCached(uuid); - } - } - return super.isCached(uuid); - } - - @Override - public boolean isAnalysisCached(UUID serverUUID) { - if (Plan.getServerUUID().equals(serverUUID)) { - return analysisData != null; - } - if (usingAnotherWebServer) { - try { - return getWebAPI().getAPI(IsCachedWebAPI.class).isAnalysisCached(webServerAddress, serverUUID); - } catch (WebAPIFailException e) { - Log.error("Failed check Bungee Analysis Cache status."); - } catch (WebAPIException e) { - attemptConnection(); - return isAnalysisCached(serverUUID); - } - } - return PageCache.isCached(PageId.SERVER.of(serverUUID)); - } - - private WebAPIManager getWebAPI() { - return plugin.getWebServer().getWebAPI(); - } - - /** - * Get the HTML for analysis page of this server. - * - * @return Html for Analysis page - * @throws NullPointerException if AnalysisData has not been cached. - */ - @Override - public String getAnalysisHtml() { - if (analysisData == null) { - analysis.runAnalysis(this); - ErrorResponse analysisRefreshPage = new ErrorResponse(); - analysisRefreshPage.setTitle("Analysis is being refreshed.."); - analysisRefreshPage.setParagraph(" Analysis is being run, refresh the page after a few seconds.. (F5)"); - analysisRefreshPage.replacePlaceholders(); - return analysisRefreshPage.getContent(); - } - try { - return Theme.replaceColors(new AnalysisPageParser(analysisData, plugin).parse()); - } catch (ParseException e) { - return new InternalErrorResponse(e, this.getClass().getSimpleName()).getContent(); - } - } - - @Override - public String getPlayerHtml(UUID uuid) throws ParseException { - return Theme.replaceColors(new InspectPageParser(uuid, plugin).parse()); - } - - @Override - public DataCache getDataCache() { - return dataCache; - } - - public void cacheAnalysisData(AnalysisData analysisData) { - this.analysisData = analysisData; - refreshDate = MiscUtils.getTime(); - cacheAnalysisHtml(); - UUID serverUUID = Plan.getServerUUID(); - if (usingAnotherWebServer) { - try { - getWebAPI().getAPI(AnalysisReadyWebAPI.class).sendRequest(webServerAddress, serverUUID); - updateNetworkPageContent(); - return; - } catch (WebAPIFailException ignored) { - Log.error("Failed to notify Bungee of Analysis Completion."); - } catch (WebAPIException e) { - attemptConnection(); - } - } - analysisReady(serverUUID); - } - - private void cacheAnalysisHtml() { - cacheAnalysisHtml(getAnalysisHtml()); - } - - public void cacheAnalysisHtml(String html) { - if (usingAnotherWebServer) { - try { - getWebAPI().getAPI(PostHtmlWebAPI.class).sendAnalysisHtml(webServerAddress, html); - } catch (WebAPIFailException e) { - Log.error("Failed to send Analysis HTML to Bungee Server."); - } catch (WebAPIException e) { - attemptConnection(); - cacheAnalysisHtml(html); - } - } else { - UUID serverUUID = Plan.getServerUUID(); - PageCache.cachePage(PageId.SERVER.of(serverUUID), () -> new AnalysisPageResponse(html)); - if (Settings.ANALYSIS_EXPORT.isTrue()) { - HtmlExport.exportServer(plugin, serverUUID); - } - } - } - - public AnalysisData getAnalysisData() { - return analysisData; - } - - public Optional getAnalysisRefreshDate() { - return refreshDate != null ? Optional.of(refreshDate) : Optional.empty(); - } - - @Override - public boolean attemptConnection() { - boolean webServerIsEnabled = WebServerSystem.isWebServerEnabled(); - boolean previousState = usingAnotherWebServer; - - try { - Log.info("Attempting Bungee Connection.. (" + webServerAddress + ")"); - PingWebAPI api = getWebAPI().getAPI(PingWebAPI.class); - try { - api.sendRequest(webServerAddress); - getWebAPI().getAPI(PostOriginalBukkitSettingsWebAPI.class).sendRequest(webServerAddress); - Log.info("Bungee Connection OK"); - plugin.getServerInfoManager().resetConnectionFails(); - usingAnotherWebServer = true; - return true; - } catch (WebAPIConnectionFailException e) { - plugin.getServerInfoManager().markConnectionFail(); - } catch (WebAPINotFoundException e) { - Log.info("Bungee reported that UUID of this server is not in the MySQL-database. Try using '/plan m setup " + webServerAddress + "' again"); - } catch (WebAPIException e) { - Log.toLog(this.getClass().getName(), e); - } - Log.info("Bungee Connection Failed."); - usingAnotherWebServer = false; - return false; - } finally { - boolean changedState = previousState != usingAnotherWebServer; - if (webServerIsEnabled && changedState) { - WebServer webServer = WebServerSystem.getInstance().getWebServer(); - webServer.stop(); - webServer.initServer(); - } - } - } - - @Override - public String getWebServerAddress() { - return webServerAddress != null ? webServerAddress : plugin.getWebServer().getAccessAddress(); - } - - @Override - public void analysisReady(UUID serverUUID) { - try { - AnalyzeCommand.sendAnalysisMessage(analysisNotification.get(serverUUID), serverUUID); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - analysisNotification.getOrDefault(serverUUID, new HashSet<>()).clear(); - } - - @Override - public void updateNetworkPageContent() { - if (usingAnotherWebServer) { - try { - getWebAPI().getAPI(PostNetworkPageContentWebAPI.class).sendNetworkContent(webServerAddress, HtmlStructure.createServerContainer(plugin)); - } catch (WebAPIFailException ignored) { - /* Do nothing */ - } catch (WebAPIException ignored) { - attemptConnection(); - updateNetworkPageContent(); - } - } - } - - @Override - public TreeMap> getErrors() throws IOException { - return ErrorLogger.getLoggedErrors(plugin); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/BungeeInformationManager.java b/Plan/src/main/java/com/djrapitops/plan/systems/info/BungeeInformationManager.java deleted file mode 100644 index 9fba8fa47..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/BungeeInformationManager.java +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.info; - -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.api.exceptions.ParseException; -import com.djrapitops.plan.api.exceptions.WebAPIConnectionFailException; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.api.exceptions.WebAPINotFoundException; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.info.parsing.NetworkPageParser; -import com.djrapitops.plan.systems.info.server.BungeeServerInfoManager; -import com.djrapitops.plan.systems.info.server.ServerInfo; -import com.djrapitops.plan.systems.webserver.pagecache.PageCache; -import com.djrapitops.plan.systems.webserver.pagecache.PageId; -import com.djrapitops.plan.systems.webserver.response.*; -import com.djrapitops.plan.systems.webserver.webapi.WebAPIManager; -import com.djrapitops.plan.systems.webserver.webapi.bukkit.AnalysisReadyWebAPI; -import com.djrapitops.plan.systems.webserver.webapi.bukkit.AnalyzeWebAPI; -import com.djrapitops.plan.systems.webserver.webapi.bukkit.InspectWebAPI; -import com.djrapitops.plan.systems.webserver.webapi.bukkit.IsOnlineWebAPI; -import com.djrapitops.plan.systems.webserver.webapi.bungee.RequestPluginsTabWebAPI; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plan.utilities.file.export.HtmlExport; -import com.djrapitops.plan.utilities.html.HtmlStructure; -import com.djrapitops.plugin.api.utility.log.ErrorLogger; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.io.IOException; -import java.sql.SQLException; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * Manages information going to the PageCache from Bukkit servers. - * - * @author Rsl1122 - */ -public class BungeeInformationManager extends InformationManager { - - private final PlanBungee plugin; - private Map bukkitServers; - - private final Map networkPageContent; - private final Map> pluginsTabContent; - private final BungeeServerInfoManager serverInfoManager; - - public BungeeInformationManager(PlanBungee plugin) throws SQLException { - usingAnotherWebServer = false; - pluginsTabContent = new HashMap<>(); - networkPageContent = new HashMap<>(); - this.plugin = plugin; - serverInfoManager = plugin.getServerInfoManager(); - refreshBukkitServerMap(); - } - - /** - * Refreshes the Offline Bukkit server Map (UUID - Server Address Map) from DB. - * - * @throws SQLException If DB Error occurs. - */ - private void refreshBukkitServerMap() throws SQLException { - bukkitServers = plugin.getDB().getServerTable().getBukkitServers().stream().collect(Collectors.toMap(ServerInfo::getUuid, Function.identity())); - } - - /** - * Sends a "Refresh Analysis" WebAPI call to the appropriate Bukkit server. - *

    - * if server is not online, api request will not be made. - * - * @param serverUUID Server UUID of the server in question. - */ - @Override - public void refreshAnalysis(UUID serverUUID) { - if (PlanBungee.getServerUUID().equals(serverUUID)) { - return; - } - ServerInfo serverInfo = getOnlineServerInfo(serverUUID); - if (serverInfo == null) { - return; - } - - AnalyzeWebAPI api = plugin.getWebServer().getWebAPI().getAPI(AnalyzeWebAPI.class); - try { - api.sendRequest(serverInfo.getWebAddress(), serverUUID); - } catch (WebAPIConnectionFailException e) { - attemptConnection(); - } catch (WebAPIException e) { - Log.toLog(this.getClass().getName(), e); - } - } - - /** - * Attempts to get info of a server that is online. - *

    - * Returns null if server doesn't exist. - * - * @param serverUUID UUID of server - * @return Online ServerInfo or null - */ - private ServerInfo getOnlineServerInfo(UUID serverUUID) { - ServerInfo serverInfo = bukkitServers.get(serverUUID); - if (serverInfo == null) { - try { - refreshBukkitServerMap(); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - serverInfo = bukkitServers.get(serverUUID); - } - if (serverInfo == null) { - return null; - } - - if (serverInfoManager.getOnlineBukkitServers().contains(serverInfo) || serverInfoManager.attemptConnection(serverInfo)) { - return serverInfo; - } - return null; - } - - /** - * Caches the inspect page for a matching player. - *

    - * Attempt is made to use the server where the player is online. - *

    - * If there is no Bukkit server to handle the request it is not fulfilled. - * - * @param uuid UUID of a player. - */ - @Override - public void cachePlayer(UUID uuid) { - ServerInfo inspectServer = null; - try { - inspectServer = getInspectRequestProcessorServer(uuid); - - WebAPIManager apiManager = getWebAPI(); - - apiManager.getAPI(InspectWebAPI.class).sendRequest(inspectServer.getWebAddress(), uuid); - apiManager.getAPI(RequestPluginsTabWebAPI.class).sendRequestsToBukkitServers(plugin, uuid); - } catch (IllegalStateException ignored) { - /* Ignored */ - } catch (WebAPIException e) { - plugin.getServerInfoManager().attemptConnection(inspectServer); - } - } - - /** - * Get ServerInfo of an online server that should process an inspect request. - *

    - * If the player is online, an attempt to use the server where the player resides is made. - *

    - * If the player is offline or in the lobby, any server can be used. - * - * @param uuid UUID of the player - * @return ServerInfo of the server that should handle the request. - * @throws IllegalStateException If no Bukkit servers are online. - */ - private ServerInfo getInspectRequestProcessorServer(UUID uuid) { - if (bukkitServers.isEmpty()) { - try { - refreshBukkitServerMap(); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - if (bukkitServers.isEmpty()) { - throw new IllegalStateException("No Bukkit Servers."); - } - } - - Collection onlineServers = serverInfoManager.getOnlineBukkitServers(); - if (plugin.getProxy().getPlayer(uuid) != null) { - for (ServerInfo server : onlineServers) { - try { - getWebAPI().getAPI(IsOnlineWebAPI.class).sendRequest(server.getWebAddress(), uuid); - return server; - } catch (WebAPIConnectionFailException e) { - serverInfoManager.serverHasGoneOffline(server.getUuid()); - } catch (WebAPINotFoundException ignored) { - /*continue*/ - } catch (WebAPIException e) { - Log.toLog(this.getClass().getName(), e); - } - } - } - - Optional bukkitServer = serverInfoManager.getOnlineBukkitServers().stream().findAny(); - if (bukkitServer.isPresent()) { - return bukkitServer.get(); - } - throw new IllegalStateException("No Bukkit servers online"); - } - - /** - * PlanBungee has no DataCache so this method should not be used. - *

    - * DataCache is meant for storing player data. - * - * @return null - */ - @Override - public DataCache getDataCache() { - return null; - } - - /** - * Attempts a connection to every Bukkit server in the database. - * - * @return true (always) - */ - @Override - public boolean attemptConnection() { - try { - List bukkitServers = plugin.getDB().getServerTable().getBukkitServers(); - for (ServerInfo server : bukkitServers) { - serverInfoManager.attemptConnection(server); - } - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - return true; - } - - /** - * Condition if analysis page for an UUID is cached. - *

    - * If serverUUID is that of Bungee, network page state is returned. - * - * @param serverUUID UUID of the server - * @return true/false - */ - @Override - public boolean isAnalysisCached(UUID serverUUID) { - return PageCache.isCached(PageId.SERVER.of(serverUUID)); - } - - /** - * Returns the Html players inspect page. - *

    - * If no Bukkit servers are online a 404 is returned instead. - * - * @param uuid UUID of the player - * @return Html string (Full page) - */ - @Override - public String getPlayerHtml(UUID uuid) { - Response response = PageCache.copyPage(PageId.PLAYER.of(uuid), - () -> new NotFoundResponse("No Bukkit Servers were online to process this request")); - if (response instanceof InspectPageResponse) { - ((InspectPageResponse) response).setInspectPagePluginsTab(getPluginsTabContent(uuid)); - } - return response.getContent(); - } - - /** - * Get the Network page html. - * - * @return Html string (Full page) - */ - @Override - public String getAnalysisHtml() { - try { - return new NetworkPageParser(plugin).parse(); - } catch (ParseException e) { - return new InternalErrorResponse(e, this.getClass().getSimpleName()).getContent(); - } - } - - /** - * Used to parse the Plugins tab html String out of all sent to Bungee. - * - * @param uuid UUID of the player - * @return Html string. - */ - @Override - public String[] getPluginsTabContent(UUID uuid) { - Map pluginsTab = pluginsTabContent.get(uuid); - if (pluginsTab == null) { - return HtmlStructure.createInspectPageTabContentCalculating(); - } - - List order = new ArrayList<>(pluginsTab.values()); - // Sort serverNames alphabetically - order.sort(new Comparator() { - @Override - public int compare(String[] o1, String[] o2) { - return o1[0].compareTo(o2[1]); - } - }); - - StringBuilder nav = new StringBuilder(); - StringBuilder tabs = new StringBuilder(); - for (String[] tab : order) { - nav.append(tab[0]); - tabs.append(tab[1]); - } - return new String[]{nav.toString(), tabs.toString()}; - } - - /** - * Places plugins tab content for a single player to the pluginsTabContent map. - * - * @param serverUUID UUID of the server - * @param uuid UUID of the player - * @param html Plugins tab html for the player on the server - */ - public void cachePluginsTabContent(UUID serverUUID, UUID uuid, String[] html) { - Map perServerPluginsTab = pluginsTabContent.getOrDefault(uuid, new HashMap<>()); - perServerPluginsTab.put(serverUUID, html); - pluginsTabContent.put(uuid, perServerPluginsTab); - Response inspectResponse = PageCache.loadPage(PageId.PLAYER.of(uuid)); - if (inspectResponse != null && inspectResponse instanceof InspectPageResponse) { - ((InspectPageResponse) inspectResponse).setInspectPagePluginsTab(getPluginsTabContent(uuid)); - } - } - - /** - * Shortcut for getting WebAPIManager - * - * @return WebAPIManager - */ - private WebAPIManager getWebAPI() { - return plugin.getWebServer().getWebAPI(); - } - - /** - * Get address of Bungee WebServer. - * - * @return URL String - */ - @Override - public String getWebServerAddress() { - return plugin.getWebServer().getAccessAddress(); - } - - public void cacheNetworkPageContent(UUID serverUUID, String html) { - networkPageContent.put(serverUUID, html); - updateNetworkPageContent(); - } - - public void removeNetworkPageContent(UUID serverUUID) { - networkPageContent.put(serverUUID, HtmlStructure.parseOfflineServerContainer(networkPageContent.get(serverUUID))); - } - - public Map getNetworkPageContent() { - return networkPageContent; - } - - /** - * Send notification of analysis being ready to all online bukkit servers via WebAPI. - * - * @param serverUUID UUID of a server which analysis is ready. - */ - @Override - public void analysisReady(UUID serverUUID) { - AnalysisReadyWebAPI api = getWebAPI().getAPI(AnalysisReadyWebAPI.class); - for (ServerInfo serverInfo : serverInfoManager.getOnlineBukkitServers()) { - try { - api.sendRequest(serverInfo.getWebAddress(), serverUUID); - } catch (WebAPIException ignored) { - /*Ignored*/ - } - } - } - - @Override - public void updateNetworkPageContent() { - UUID serverUUID = MiscUtils.getIPlan().getServerUuid(); - PageCache.cachePage(PageId.SERVER.of(serverUUID), () -> new AnalysisPageResponse(this)); - if (Settings.ANALYSIS_EXPORT.isTrue()) { - HtmlExport.exportServer(plugin, serverUUID); - } - } - - public void sendConfigSettings() { - Collection online = serverInfoManager.getOnlineBukkitServers(); - online.stream().map(ServerInfo::getUuid) - .forEach(serverInfoManager::sendConfigSettings); - } - - @Override - public TreeMap> getErrors() throws IOException { - // TODO Request Bukkit servers for errors - return ErrorLogger.getLoggedErrors(plugin); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/InformationManager.java b/Plan/src/main/java/com/djrapitops/plan/systems/info/InformationManager.java deleted file mode 100644 index bfd2d64f1..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/InformationManager.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.info; - -import com.djrapitops.plan.api.exceptions.ParseException; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.cache.SessionCache; -import com.djrapitops.plan.systems.webserver.pagecache.PageCache; -import com.djrapitops.plan.systems.webserver.pagecache.PageId; -import com.djrapitops.plugin.command.ISender; - -import java.io.IOException; -import java.util.*; - -/** - * Abstract layer for Bukkit and Bungee Information managers. - *

    - * Manages analysis notification sending. - * - * @author Rsl1122 - */ -public abstract class InformationManager { - boolean usingAnotherWebServer; - String webServerAddress; - Map> analysisNotification; - - public InformationManager() { - analysisNotification = new HashMap<>(); - } - - public abstract boolean attemptConnection(); - - public abstract void cachePlayer(UUID uuid); - - public String getLinkTo(String target) { - return getWebServerAddress() + target; - } - - public abstract void refreshAnalysis(UUID serverUUID); - - public abstract DataCache getDataCache(); - - public SessionCache getSessionCache() { - return getDataCache(); - } - - public boolean isCached(UUID uuid) { - return PageCache.isCached(PageId.PLAYER.of(uuid)); - } - - public abstract String getPlayerHtml(UUID uuid) throws ParseException; - - /** - * Used for /server on Bukkit and /network on Bungee - * - * @return Is page cached. - */ - public abstract boolean isAnalysisCached(UUID serverUUID); - - /** - * Used for /server on Bukkit and /network on Bungee - * - * @return Html of a page. - */ - public abstract String getAnalysisHtml(); - - public void addAnalysisNotification(ISender sender, UUID serverUUID) { - Set notify = analysisNotification.getOrDefault(serverUUID, new HashSet<>()); - notify.add(sender); - analysisNotification.put(serverUUID, notify); - } - - public abstract String[] getPluginsTabContent(UUID uuid); - - public boolean isUsingAnotherWebServer() { - return usingAnotherWebServer; - } - - public abstract String getWebServerAddress(); - - public boolean isAuthRequired() { - return getWebServerAddress().startsWith("https"); - } - - public abstract void analysisReady(UUID serverUUID); - - public abstract void updateNetworkPageContent(); - - public abstract TreeMap> getErrors() throws IOException; -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/UrlParser.java b/Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/UrlParser.java deleted file mode 100644 index 8373f7116..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/parsing/UrlParser.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.info.parsing; - -/** - * Used for parsing URL strings. - * - * @author Rsl1122 - */ -public class UrlParser { - - private final String webServerAddress; - private StringBuilder url; - - public UrlParser(String address) { - webServerAddress = address; - url = new StringBuilder(); - } - - public UrlParser relativeProtocol() { - url.append("//"); - return this; - } - - public UrlParser httpProtocol() { - if (url.length() == 0) { - url.append("http://"); - } else { - String current = url.toString(); - url = new StringBuilder("./"); - url.append(current.substring(current.indexOf("/"))); - } - return this; - } - - public UrlParser httpsProtocol() { - if (url.length() == 0) { - url.append("https://"); - } else { - String current = url.toString(); - url = new StringBuilder("./"); - url.append(current.substring(current.indexOf("/"))); - } - return this; - } - - public UrlParser relative() { - if (url.length() == 0) { - url.append("./"); - } else { - String current = url.toString(); - url = new StringBuilder("./"); - url.append(current.substring(current.indexOf("/"))); - } - return this; - } - - public UrlParser webAddress() { - url.append(webServerAddress); - return this; - } - - public UrlParser target(String target) { - if (!target.startsWith("/") && url.charAt(url.length() - 1) != '/') { - url.append("/"); - } - url.append(target); - return this; - } - - @Override - public String toString() { - return url.toString(); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/server/BukkitServerInfoManager.java b/Plan/src/main/java/com/djrapitops/plan/systems/info/server/BukkitServerInfoManager.java deleted file mode 100644 index 247cf590c..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/server/BukkitServerInfoManager.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.info.server; - - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.ServerVariableHolder; -import com.djrapitops.plan.api.exceptions.PlanEnableException; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.database.tables.ServerTable; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.io.IOException; -import java.sql.SQLException; -import java.util.Optional; -import java.util.UUID; - -/** - * Manages the Server information required for Bungee-Bukkit WebAPI connection. - *

    - * Also manages Server ID required for MySQL database independence. - * - * @author Rsl1122 - */ -public class BukkitServerInfoManager { - - private final Plan plugin; - private ServerInfo serverInfo; - private ServerInfoFile serverInfoFile; - private final ServerTable serverTable; - - public BukkitServerInfoManager(Plan plugin) throws PlanEnableException { - this.plugin = plugin; - Database db = plugin.getDB(); - serverTable = db.getServerTable(); - - try { - serverInfoFile = new ServerInfoFile(plugin); - } catch (IOException e) { - throw new PlanEnableException("Failed to read ServerInfoFile.yml", e); - } - } - - public void updateServerInfo() throws SQLException, IOException { - Optional serverUUID = serverInfoFile.getUUID(); - if (serverUUID.isPresent()) { - updateDbInfo(serverUUID.get()); - } else { - registerServer(); - } - } - - private void updateDbInfo(UUID serverUUID) throws SQLException, IOException { - Optional serverID = serverTable.getServerID(serverUUID); - if (!serverID.isPresent()) { - registerServer(serverUUID); - return; - } - String name = Settings.SERVER_NAME.toString().replaceAll("[^a-zA-Z0-9_\\s]", "_"); - String webAddress = plugin.getWebServer().getAccessAddress(); - if ("plan".equalsIgnoreCase(name)) { - name = "Server " + serverID.get(); - } - int maxPlayers = plugin.getVariable().getMaxPlayers(); - - serverInfo = new ServerInfo(serverID.get(), serverUUID, name, webAddress, maxPlayers); - serverTable.saveCurrentServerInfo(serverInfo); - } - - private void registerServer() throws SQLException, IOException { - registerServer(generateNewUUID(plugin.getVariable())); - } - - private void registerServer(UUID serverUUID) throws SQLException, IOException { - String webAddress = plugin.getWebServer().getAccessAddress(); - String name = Settings.SERVER_NAME.toString().replaceAll("[^a-zA-Z0-9_\\s]", "_"); - int maxPlayers = plugin.getVariable().getMaxPlayers(); - serverInfo = new ServerInfo(-1, serverUUID, name, webAddress, maxPlayers); - serverTable.saveCurrentServerInfo(serverInfo); - Optional serverID = serverTable.getServerID(serverUUID); - if (!serverID.isPresent()) { - throw new IllegalStateException("Failed to Register Server (ID not found)"); - } - - int id = serverID.get(); - serverInfo.setId(id); - - serverInfoFile.saveInfo(serverInfo, new ServerInfo(-1, null, name, "", 0)); - } - - private UUID generateNewUUID(ServerVariableHolder variableHolder) { - String seed = plugin.getServer().getServerId() + variableHolder.getName() + variableHolder.getIp() + variableHolder.getPort() + variableHolder.getVersion() + variableHolder.getImplVersion(); - return UUID.nameUUIDFromBytes(seed.getBytes()); - } - - public Optional getBungeeConnectionAddress() { - try { - String bungeeWebAddress = serverInfoFile.getBungeeWebAddress(); - if (!bungeeWebAddress.isEmpty()) { - return Optional.of(bungeeWebAddress); - } - } catch (Exception ignored) { - /* Ignored */ - } - try { - Optional bungeeInfo = plugin.getDB().getServerTable().getBungeeInfo(); - if (bungeeInfo.isPresent()) { - return Optional.of(bungeeInfo.get().getWebAddress()); - } - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - return Optional.empty(); - } - - /** - * Saves Bungee connection information to local file on Bukkit servers. - * - * @param address Address to save - * @throws IOException If ServerInfo file can not be written to. - */ - public void saveBungeeConnectionAddress(String address) throws IOException { - serverInfoFile.saveInfo(serverInfo, new ServerInfo(-1, null, "Bungee", address, -1)); - } - - public void markConnectionFail() { - serverInfoFile.markConnectionFail(); - } - - public void resetConnectionFails() { - serverInfoFile.resetConnectionFails(); - } - - public int getServerID() { - return serverInfo.getId(); - } - - public UUID getServerUUID() { - return serverInfo.getUuid(); - } - - public String getServerName() { - return serverInfo.getName(); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/server/BungeeServerInfoManager.java b/Plan/src/main/java/com/djrapitops/plan/systems/info/server/BungeeServerInfoManager.java deleted file mode 100644 index 179ccf8d0..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/server/BungeeServerInfoManager.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.info.server; - -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.ServerVariableHolder; -import com.djrapitops.plan.api.exceptions.PlanEnableException; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.database.tables.ServerTable; -import com.djrapitops.plan.systems.webserver.webapi.bukkit.ConfigurationWebAPI; -import com.djrapitops.plan.systems.webserver.webapi.universal.PingWebAPI; -import com.djrapitops.plugin.api.TimeAmount; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.task.AbsRunnable; -import com.djrapitops.plugin.task.RunnableFactory; - -import java.sql.SQLException; -import java.util.*; -import java.util.stream.Collectors; - -/** - * Manages Server information on the Bungee instance. - * - * @author Rsl1122 - */ -public class BungeeServerInfoManager { - - private final PlanBungee plugin; - private ServerInfo serverInfo; - private final Database db; - - private final Map bukkitServers; - private final Set onlineServers; - private ServerTable serverTable; - - public BungeeServerInfoManager(PlanBungee plugin) { - this.plugin = plugin; - this.db = plugin.getDB(); - serverTable = db.getServerTable(); - - bukkitServers = new HashMap<>(); - onlineServers = new HashSet<>(); - } - - public void loadServerInfo() throws PlanEnableException { - try { - Optional bungeeInfo = db.getServerTable().getBungeeInfo(); - if (bungeeInfo.isPresent()) { - serverInfo = bungeeInfo.get(); - String accessAddress = plugin.getWebServer().getAccessAddress(); - if (!accessAddress.equals(serverInfo.getWebAddress())) { - serverInfo.setWebAddress(accessAddress); - serverTable.saveCurrentServerInfo(serverInfo); - } - } else { - serverInfo = registerBungeeInfo(); - } - } catch (SQLException e) { - throw new PlanEnableException("Failed to read Database for ServerInfo"); - } - } - - private ServerInfo registerBungeeInfo() throws SQLException, PlanEnableException { - ServerVariableHolder variable = plugin.getVariable(); - UUID serverUUID = generateNewUUID(variable); - String accessAddress = plugin.getWebServer().getAccessAddress(); - - serverTable.saveCurrentServerInfo( - new ServerInfo(-1, serverUUID, "BungeeCord", accessAddress, variable.getMaxPlayers()) - ); - - Optional bungeeInfo = db.getServerTable().getBungeeInfo(); - if (bungeeInfo.isPresent()) { - return bungeeInfo.get(); - } - throw new PlanEnableException("BungeeCord registration failed (DB)"); - } - - private UUID generateNewUUID(ServerVariableHolder variableHolder) { - String seed = variableHolder.getName() + variableHolder.getIp() + variableHolder.getPort() + variableHolder.getVersion() + variableHolder.getImplVersion(); - return UUID.nameUUIDFromBytes(seed.getBytes()); - } - - public UUID getServerUUID() { - return serverInfo.getUuid(); - } - - public boolean attemptConnection(ServerInfo server, String accessCode) { - if (server == null) { - Log.debug("Attempted a connection to a null ServerInfo"); - return false; - } - try { - String webAddress = server.getWebAddress(); - Log.debug("Attempting to connect to Bukkit server.. (" + webAddress + ")"); - PingWebAPI pingApi = plugin.getWebServer().getWebAPI().getAPI(PingWebAPI.class); - if (accessCode != null) { - pingApi.sendRequest(webAddress, accessCode); - plugin.getWebServer().getWebAPI().getAPI(ConfigurationWebAPI.class).sendRequest(webAddress, server.getUuid(), accessCode); - } else { - pingApi.sendRequest(webAddress); - } - connectedToServer(server); - return true; - } catch (WebAPIException e) { - Log.debug(e.toString()); - serverHasGoneOffline(server.getUuid()); - return false; - } - } - - public boolean attemptConnection(ServerInfo server) { - return attemptConnection(server, null); - } - - public void sendConfigSettings(UUID serverUUID) { - String webAddress = null; - try { - ServerInfo server = bukkitServers.get(serverUUID); - if (server == null) { - return; - } - webAddress = server.getWebAddress(); - Log.debug("Sending config settings to " + webAddress + ""); - plugin.getWebServer().getWebAPI().getAPI(ConfigurationWebAPI.class).sendRequest(webAddress, serverUUID); - } catch (WebAPIException e) { - Log.info("Connection to Bukkit (" + webAddress + ") did not succeed."); - serverHasGoneOffline(serverUUID); - } - } - - public void connectedToServer(ServerInfo server) { - Log.info("Connection to Bukkit (" + server.getWebAddress() + ") OK"); - bukkitServers.put(server.getUuid(), server); - onlineServers.add(server.getUuid()); - } - - public boolean serverConnected(UUID serverUUID) { - if (plugin.getServerUuid().equals(serverUUID)) { - return false; - } - Log.info("Received a connection from a Bukkit server.."); - if (onlineServers.contains(serverUUID)) { - RunnableFactory.createNew("BukkitRebootedConnectionTask: " + serverUUID, new AbsRunnable() { - @Override - public void run() { - sendConfigSettings(serverUUID); - connectedToServer(bukkitServers.get(serverUUID)); - this.cancel(); - } - }).runTaskLaterAsynchronously(TimeAmount.SECOND.ticks() * 3L); - return true; - } - try { - Optional serverInfo = db.getServerTable().getServerInfo(serverUUID); - if (serverInfo.isPresent()) { - ServerInfo server = serverInfo.get(); - Log.info("Server Info found from DB: " + server.getName()); - RunnableFactory.createNew("BukkitConnectionTask: " + server.getName(), new AbsRunnable() { - @Override - public void run() { - attemptConnection(server); - sendConfigSettings(serverUUID); - this.cancel(); - } - }).runTaskLaterAsynchronously(TimeAmount.SECOND.ticks() * 3L); - return true; - } - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - return false; - } - - public Collection getOnlineBukkitServers() { - return bukkitServers.entrySet().stream() - .filter(entry -> onlineServers.contains(entry.getKey())) - .map(Map.Entry::getValue) - .collect(Collectors.toSet()); - } - - public Collection getBukkitServers() { - return bukkitServers.values(); - } - - public void serverHasGoneOffline(UUID serverUUID) { - onlineServers.remove(serverUUID); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/info/server/ServerInfoFile.java b/Plan/src/main/java/com/djrapitops/plan/systems/info/server/ServerInfoFile.java deleted file mode 100644 index dd3bbda54..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/info/server/ServerInfoFile.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.info.server; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.utilities.file.FileUtil; -import com.djrapitops.plugin.api.config.Config; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.utilities.Verify; - -import java.io.File; -import java.io.IOException; -import java.util.Optional; -import java.util.UUID; - -/** - * Manages local server info file. - *

    - * ServerInfo.yml contains current server's ID, UUID and Bungee WebServer connection information. - * It - * - * @author Rsl1122 - */ -public class ServerInfoFile extends Config { - public ServerInfoFile(Plan plugin) throws IOException { - super(new File(plugin.getDataFolder(), "ServerInfoFile.yml")); - copyDefaults(FileUtil.lines(plugin, "DefaultServerInfoFile.yml")); - save(); - } - - public void saveInfo(ServerInfo thisServer, ServerInfo bungee) throws IOException { - set("Server.UUID", thisServer.getUuid().toString()); - - String oldAddress = getString("Bungee.WebAddress"); - String newAddress = bungee.getWebAddress(); - - if (!newAddress.equals(oldAddress)) { - set("Bungee.Fail", 0); - set("Bungee.WebAddress", newAddress); - } - save(); - } - - public Optional getUUID() { - String uuidString = getString("Server.UUID"); - if (Verify.isEmpty(uuidString)) { - return Optional.empty(); - } - return Optional.of(UUID.fromString(uuidString)); - } - - public String getBungeeWebAddress() { - return getString("Bungee.WebAddress"); - } - - public int markConnectionFail() { - try { - int fails = getInt("Bungee.Fail"); - set("Bungee.Fail", fails + 1); - save(); - return fails; - } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); - } - return -1; - } - - public void resetConnectionFails() { - try { - set("Bungee.Fail", 0); - save(); - } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); - } - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/NewNickActionProcessor.java b/Plan/src/main/java/com/djrapitops/plan/systems/processing/NewNickActionProcessor.java deleted file mode 100644 index 124f1e7cd..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/NewNickActionProcessor.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.processing; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.data.container.Action; -import com.djrapitops.plan.database.tables.Actions; -import com.djrapitops.plan.systems.processing.player.PlayerProcessor; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plan.utilities.html.HtmlUtils; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.sql.SQLException; -import java.util.UUID; - -/** - * Processor for inserting a Name Change action to the Actions table. - * - * @author Rsl1122 - * @since 4.0.0 - */ -public class NewNickActionProcessor extends PlayerProcessor { - - private final String displayName; - - public NewNickActionProcessor(UUID uuid, String displayName) { - super(uuid); - this.displayName = displayName; - } - - @Override - public void process() { - UUID uuid = getUUID(); - - String info = HtmlUtils.removeXSS(displayName); - - Action action = new Action(MiscUtils.getTime(), Actions.NEW_NICKNAME, info); - - try { - Plan.getInstance().getDB().getActionsTable().insertAction(uuid, action); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/info/BungeePluginChannelSenderProcessor.java b/Plan/src/main/java/com/djrapitops/plan/systems/processing/info/BungeePluginChannelSenderProcessor.java deleted file mode 100644 index 3b51cb1c1..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/info/BungeePluginChannelSenderProcessor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.processing.info; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.systems.processing.Processor; -import com.djrapitops.plugin.api.utility.log.Log; -import org.bukkit.entity.Player; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public class BungeePluginChannelSenderProcessor extends Processor { - - public BungeePluginChannelSenderProcessor(Player object) { - super(object); - } - - @Override - public void process() { - Log.debug("Sending a Bungee Address get Request through plugin channel"); - try (ByteArrayOutputStream b = new ByteArrayOutputStream()) { - try (DataOutputStream out = new DataOutputStream(b)) { - out.writeUTF("bungee_address_get"); - object.sendPluginMessage(Plan.getInstance(), "BungeeCord", b.toByteArray()); - } - } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); - } - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/info/NetworkPageUpdateProcessor.java b/Plan/src/main/java/com/djrapitops/plan/systems/processing/info/NetworkPageUpdateProcessor.java deleted file mode 100644 index e085b887f..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/info/NetworkPageUpdateProcessor.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.processing.info; - -import com.djrapitops.plan.systems.info.InformationManager; -import com.djrapitops.plan.systems.processing.Processor; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public class NetworkPageUpdateProcessor extends Processor { - - public NetworkPageUpdateProcessor(InformationManager object) { - super(object); - } - - @Override - public void process() { - object.updateNetworkPageContent(); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/DeathProcessor.java b/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/DeathProcessor.java deleted file mode 100644 index c519e51f9..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/DeathProcessor.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.djrapitops.plan.systems.processing.player; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.data.container.Session; - -import java.util.Optional; -import java.util.UUID; - -/** - * Updates death count of the current session. - * - * @author Rsl1122 - * @since 4.0.0 - */ -public class DeathProcessor extends PlayerProcessor { - - /** - * Constructor. - * - * @param uuid UUID of the dead player. - */ - public DeathProcessor(UUID uuid) { - super(uuid); - } - - @Override - public void process() { - UUID uuid = getUUID(); - Optional cachedSession = Plan.getInstance().getDataCache().getCachedSession(uuid); - cachedSession.ifPresent(Session::died); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/NameProcessor.java b/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/NameProcessor.java deleted file mode 100644 index 4dec0a1bb..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/NameProcessor.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.processing.player; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.database.tables.NicknamesTable; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.processing.NewNickActionProcessor; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; - -/** - * Processor for updating name in the database if the player has changed it. - * - * @author Rsl1122 - * @since 4.0.0 - */ -public class NameProcessor extends PlayerProcessor { - - private final String playerName; - private final String displayName; - - public NameProcessor(UUID uuid, String playerName, String displayName) { - super(uuid); - this.playerName = playerName; - this.displayName = displayName; - } - - @Override - public void process() { - UUID uuid = getUUID(); - Plan plugin = Plan.getInstance(); - DataCache dataCache = plugin.getDataCache(); - String cachedName = dataCache.getName(uuid); - String cachedDisplayName = dataCache.getDisplayName(uuid); - - boolean sameAsCached = displayName.equals(cachedDisplayName); - if (playerName.equals(cachedName) && sameAsCached) { - return; - } - - Database db = plugin.getDB(); - NicknamesTable nicknamesTable = db.getNicknamesTable(); - cueNameChangeActionProcessor(uuid, plugin, nicknamesTable); - - try { - db.getUsersTable().updateName(uuid, playerName); - - nicknamesTable.saveUserName(uuid, displayName); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - - dataCache.updateNames(uuid, playerName, displayName); - } - - private void cueNameChangeActionProcessor(UUID uuid, Plan plugin, NicknamesTable nicknamesTable) { - try { - List nicknames = nicknamesTable.getNicknames(uuid, Plan.getServerUUID()); - if (nicknames.contains(displayName)) { - return; - } - plugin.addToProcessQueue(new NewNickActionProcessor(uuid, displayName)); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/RegisterProcessor.java b/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/RegisterProcessor.java deleted file mode 100644 index 0d29b2110..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/processing/player/RegisterProcessor.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.processing.player; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.data.container.Action; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.database.tables.Actions; -import com.djrapitops.plan.database.tables.UserInfoTable; -import com.djrapitops.plan.database.tables.UsersTable; -import com.djrapitops.plan.systems.processing.Processor; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.sql.SQLException; -import java.util.UUID; - -/** - * Registers the user to the database and marks first session if the user has no actions. - * - * @author Rsl1122 - */ -public class RegisterProcessor extends PlayerProcessor { - - private final long registered; - private final long time; - private final int playersOnline; - private final String name; - private final Processor[] afterProcess; - - public RegisterProcessor(UUID uuid, long registered, long time, String name, int playersOnline, Processor... afterProcess) { - super(uuid); - this.registered = registered; - this.time = time; - this.playersOnline = playersOnline; - this.name = name; - this.afterProcess = afterProcess; - } - - @Override - public void process() { - UUID uuid = getUUID(); - Plan plugin = Plan.getInstance(); - Database db = plugin.getDB(); - UsersTable usersTable = db.getUsersTable(); - UserInfoTable userInfoTable = db.getUserInfoTable(); - try { - if (!usersTable.isRegistered(uuid)) { - usersTable.registerUser(uuid, registered, name); - } - if (!userInfoTable.isRegistered(uuid)) { - userInfoTable.registerUserInfo(uuid, registered); - } - if (db.getActionsTable().getActions(uuid).size() > 0) { - return; - } - plugin.getDataCache().markFirstSession(uuid); - db.getActionsTable().insertAction(uuid, new Action(time, Actions.FIRST_SESSION, "Online: " + playersOnline + " Players")); - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } finally { - plugin.addToProcessQueue(afterProcess); - } - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/tasks/PlanBungeeTaskSystem.java b/Plan/src/main/java/com/djrapitops/plan/systems/tasks/PlanBungeeTaskSystem.java deleted file mode 100644 index f77cc8e57..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/tasks/PlanBungeeTaskSystem.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.tasks; - -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.systems.info.BungeeInformationManager; -import com.djrapitops.plugin.api.TimeAmount; -import com.djrapitops.plugin.task.AbsRunnable; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public class PlanBungeeTaskSystem extends TaskSystem { - - @Override - public void init() { - registerTasks(); - } - - private void registerTasks() { - BungeeInformationManager infoManager = ((BungeeInformationManager) PlanBungee.getInstance().getInfoManager()); - - registerTask("Enable Bukkit Connection Task", new AbsRunnable() { - @Override - public void run() { - infoManager.attemptConnection(); - infoManager.sendConfigSettings(); - } - }).runTaskAsynchronously(); - registerTask("Player Count task", new TPSCountTimer(PlanBungee.getInstance())) - .runTaskTimerAsynchronously(1000, TimeAmount.SECOND.ticks()); - registerTask("NetworkPageContentUpdateTask", new AbsRunnable("NetworkPageContentUpdateTask") { - @Override - public void run() { - infoManager.updateNetworkPageContent(); - } - }).runTaskTimerAsynchronously(1500, TimeAmount.MINUTE.ticks()); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/tasks/PlanTaskSystem.java b/Plan/src/main/java/com/djrapitops/plan/systems/tasks/PlanTaskSystem.java deleted file mode 100644 index fe30f7b49..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/tasks/PlanTaskSystem.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.tasks; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.info.InformationManager; -import com.djrapitops.plugin.api.Benchmark; -import com.djrapitops.plugin.api.TimeAmount; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.task.AbsRunnable; -import com.djrapitops.plugin.task.ITask; -import com.djrapitops.plugin.task.RunnableFactory; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public class PlanTaskSystem extends TaskSystem { - - // TODO Remove Plan.getInstance requirement. - - private ITask bootAnalysisTask; - - @Override - public void init() { - registerTasks(); - } - - // TODO Clean Up - private void registerTasks() { - String bootAnalysisMsg = Locale.get(Msg.ENABLE_BOOT_ANALYSIS_INFO).toString(); - String bootAnalysisRunMsg = Locale.get(Msg.ENABLE_BOOT_ANALYSIS_RUN_INFO).toString(); - - Benchmark.start("Task Registration"); - tpsCountTimer = new TPSCountTimer(Plan.getInstance()); - registerTask(tpsCountTimer).runTaskTimer(1000, TimeAmount.SECOND.ticks()); - - // Analysis refresh settings - int analysisRefreshMinutes = Settings.ANALYSIS_AUTO_REFRESH.getNumber(); - boolean analysisRefreshTaskIsEnabled = analysisRefreshMinutes > 0; - long analysisPeriod = analysisRefreshMinutes * TimeAmount.MINUTE.ticks(); - - Log.info(bootAnalysisMsg); - - InformationManager infoManager = Plan.getInstance().getInfoManager(); - - bootAnalysisTask = RunnableFactory.createNew("BootAnalysisTask", new AbsRunnable() { - @Override - public void run() { - Log.info(bootAnalysisRunMsg); - infoManager.refreshAnalysis(Plan.getServerUUID()); - this.cancel(); - } - }).runTaskLaterAsynchronously(30 * TimeAmount.SECOND.ticks()); - - if (analysisRefreshTaskIsEnabled) { - RunnableFactory.createNew("PeriodicalAnalysisTask", new AbsRunnable() { - @Override - public void run() { - infoManager.refreshAnalysis(Plan.getServerUUID()); - } - }).runTaskTimerAsynchronously(analysisPeriod, analysisPeriod); - } - - registerTask("PeriodicNetworkBoxRefreshTask", new AbsRunnable() { - @Override - public void run() { - infoManager.updateNetworkPageContent(); - } - }).runTaskTimerAsynchronously(TimeAmount.SECOND.ticks(), TimeAmount.MINUTE.ticks() * 5L); - - Benchmark.stop("Enable", "Task Registration"); - } - - public void cancelBootAnalysis() { - try { - bootAnalysisTask.cancel(); - } catch (Exception ignored) { - /* Ignored */ - } - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/tasks/TPSCountTimer.java b/Plan/src/main/java/com/djrapitops/plan/systems/tasks/TPSCountTimer.java deleted file mode 100644 index d8979029e..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/tasks/TPSCountTimer.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.djrapitops.plan.systems.tasks; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.data.container.TPS; -import com.djrapitops.plan.systems.processing.TPSInsertProcessor; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plan.utilities.analysis.MathUtils; -import com.djrapitops.plugin.api.Check; -import com.djrapitops.plugin.api.TimeAmount; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.task.AbsRunnable; -import org.bukkit.World; - -import java.lang.management.ManagementFactory; -import java.lang.management.OperatingSystemMXBean; -import java.util.ArrayList; -import java.util.List; - -/** - * Class responsible for calculating TPS every second. - * - * @author Rsl1122 - */ -public class TPSCountTimer extends AbsRunnable { - - private final IPlan plugin; - private final List history; - private long lastCheckNano; - - private final boolean usingBungee; - - private int latestPlayersOnline = 0; - - public TPSCountTimer(IPlan plugin) { - super("TPSCountTimer"); - lastCheckNano = -1; - this.plugin = plugin; - history = new ArrayList<>(); - usingBungee = Check.isBungeeAvailable(); - } - - @Override - public void run() { - long nanoTime = System.nanoTime(); - long now = MiscUtils.getTime(); - - if (usingBungee) { - history.add(new TPS(now, -1, ((PlanBungee) plugin).getProxy().getOnlineCount(), -1, -1, -1, -1)); - } else { - long diff = nanoTime - lastCheckNano; - - lastCheckNano = nanoTime; - - if (diff > nanoTime) { // First run's diff = nanoTime + 1, no calc possible. - Log.debug("First run of TPSCountTimer Task."); - return; - } - - history.add(calculateTPS(diff, now)); - } - if (history.size() >= 60) { - plugin.addToProcessQueue(new TPSInsertProcessor(new ArrayList<>(history))); - history.clear(); - } - } - - /** - * Calculates the TPS - * - * @param diff The time difference between the last run and the new run - * @param now The time right now - * @return the TPS - */ - private TPS calculateTPS(long diff, long now) { - OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); - int availableProcessors = operatingSystemMXBean.getAvailableProcessors(); - double averageCPUUsage = MathUtils.round(operatingSystemMXBean.getSystemLoadAverage() / availableProcessors * 100.0); - - if (averageCPUUsage < 0) { // If unavailable, getSystemLoadAverage() returns -1 - averageCPUUsage = -1; - } - - Runtime runtime = Runtime.getRuntime(); - - long totalMemory = runtime.totalMemory(); - long usedMemory = (totalMemory - runtime.freeMemory()) / 1000000; - - int playersOnline = ((Plan) plugin).getServer().getOnlinePlayers().size(); - latestPlayersOnline = playersOnline; - int loadedChunks = getLoadedChunks(); - int entityCount; - - if (plugin.getVariable().isUsingPaper()) { - entityCount = getEntityCountPaper(); - - return getTPSPaper(now, averageCPUUsage, usedMemory, entityCount, loadedChunks, playersOnline); - } else { - entityCount = getEntityCount(); - - // 40ms removed because the run appears to take 40-50ms, screwing the tps. - long fortyMsAsNs = TimeAmount.MILLISECOND.ns() * 40L; - return getTPS(diff - fortyMsAsNs, now, averageCPUUsage, usedMemory, entityCount, loadedChunks, playersOnline); - } - } - - /** - * Gets the TPS for Spigot / Bukkit - * - * @param diff The difference between the last run and this run - * @param now The time right now - * @param cpuUsage The usage of the CPU - * @param playersOnline The amount of players that are online - * @return the TPS - */ - private TPS getTPS(long diff, long now, double cpuUsage, long usedMemory, int entityCount, int chunksLoaded, int playersOnline) { - long difference = diff; - if (difference < TimeAmount.SECOND.ns()) { // No tick count above 20 - difference = TimeAmount.SECOND.ns(); - } - - long twentySeconds = 20L * TimeAmount.SECOND.ns(); - while (difference > twentySeconds) { - history.add(new TPS(now, 0, playersOnline, cpuUsage, usedMemory, entityCount, chunksLoaded)); - difference -= twentySeconds; - } - - double tpsN = twentySeconds * 1.0 / difference; - - return new TPS(now, tpsN, playersOnline, cpuUsage, usedMemory, entityCount, chunksLoaded); - } - - /** - * Gets the TPS for Paper - * - * @param now The time right now - * @param cpuUsage The usage of the CPU - * @param playersOnline The amount of players that are online - * @return the TPS - */ - private TPS getTPSPaper(long now, double cpuUsage, long usedMemory, int entityCount, int chunksLoaded, int playersOnline) { - double tps = ((Plan) plugin).getServer().getTPS()[0]; - - if (tps > 20) { - tps = 20; - } - - tps = MathUtils.round(tps); - - return new TPS(now, tps, playersOnline, cpuUsage, usedMemory, entityCount, chunksLoaded); - } - - /** - * Gets the amount of loaded chunks - * - * @return amount of loaded chunks - */ - private int getLoadedChunks() { - return ((Plan) plugin).getServer().getWorlds().stream().mapToInt(world -> world.getLoadedChunks().length).sum(); - } - - /** - * Gets the amount of entities on the server for Bukkit / Spigot - * - * @return amount of entities - */ - private int getEntityCount() { - return ((Plan) plugin).getServer().getWorlds().stream().mapToInt(world -> world.getEntities().size()).sum(); - } - - /** - * Gets the amount of entities on the server for Paper - * - * @return amount of entities - */ - private int getEntityCountPaper() { - try { - return ((Plan) plugin).getServer().getWorlds().stream().mapToInt(World::getEntityCount).sum(); - } catch (BootstrapMethodError | NoSuchMethodError e) { - return getEntityCount(); - } - } - - public int getLatestPlayersOnline() { - return latestPlayersOnline; - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/APIRequestHandler.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/APIRequestHandler.java deleted file mode 100644 index c0e6c79a6..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/APIRequestHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver; - -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPIManager; -import com.djrapitops.plugin.api.Benchmark; -import com.djrapitops.plugin.api.utility.log.Log; -import com.sun.net.httpserver.Headers; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -/** - * HttpHandler for webserver request management. - * - * @author Rsl1122 - */ -public class APIRequestHandler implements HttpHandler { - - private final APIResponseHandler responseHandler; - - APIRequestHandler(WebAPIManager webAPI) { - responseHandler = new APIResponseHandler(webAPI); - } - - @Override - public void handle(HttpExchange exchange) { - Headers responseHeaders = exchange.getResponseHeaders(); - Request request = new Request(exchange); - String requestString = request.toString(); - Benchmark.start("", requestString); - int responseCode = -1; - try { - Response response = responseHandler.getAPIResponse(request); - responseCode = response.getCode(); - response.setResponseHeaders(responseHeaders); - response.send(exchange); - } catch (Exception e) { - if (Settings.DEV_MODE.isTrue()) { - Log.toLog(this.getClass().getName(), e); - } - } finally { - exchange.close(); - if (Settings.DEV_MODE.isTrue()) { - Log.debug(requestString + " Response code: " + responseCode + " took " + Benchmark.stop("", requestString) + " ms"); - } - } - } - - -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/APIResponseHandler.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/APIResponseHandler.java deleted file mode 100644 index cd31e3e45..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/APIResponseHandler.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver; - -import com.djrapitops.plan.systems.webserver.pagecache.PageCache; -import com.djrapitops.plan.systems.webserver.pagecache.PageId; -import com.djrapitops.plan.systems.webserver.response.*; -import com.djrapitops.plan.systems.webserver.response.api.BadRequestResponse; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; -import com.djrapitops.plan.systems.webserver.webapi.WebAPIManager; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plan.utilities.html.Html; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.sql.SQLException; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -/** - * Handles choosing of the correct API response to an API request. - * - * @author Rsl1122 - */ -public class APIResponseHandler { - - private final WebAPIManager webAPI; - - public APIResponseHandler(WebAPIManager webAPI) { - this.webAPI = webAPI; - } - - Response getAPIResponse(Request request) throws IOException { - String target = request.getTarget(); - String[] args = target.split("/"); - - if ("/favicon.ico".equalsIgnoreCase(target)) { - return PageCache.loadPage(PageId.FAVICON_REDIRECT.id(), () -> new RedirectResponse("https://puu.sh/tK0KL/6aa2ba141b.ico")); - } - if ("/debug".equalsIgnoreCase(target)) { - return new DebugPageResponse(); - } - if (target.endsWith(".css")) { - return PageCache.loadPage(PageId.CSS.of(target), () -> new CSSResponse(target)); - } - - if (target.endsWith(".js")) { - return PageCache.loadPage(PageId.JS.of(target), () -> new JavaScriptResponse(target)); - } - - if (args.length < 2 || !"api".equals(args[1])) { - String address = MiscUtils.getIPlan().getInfoManager().getWebServerAddress() + target; - String link = Html.LINK.parse(address, address); - return PageCache.loadPage(PageId.ERROR.of("Non-API Request"), () -> new NotFoundResponse("WebServer is in WebAPI-only mode, " + - "connect to the Bungee server instead: " + link)); - } - - if (args.length < 3) { - String error = "API Method not specified"; - return PageCache.loadPage(PageId.ERROR.of(error), () -> new BadRequestResponse(error)); - } - - String method = args[2]; - String requestBody; - try (InputStream inputStream = request.getRequestBody()) { - requestBody = readPOSTRequest(inputStream); - } - - if (requestBody == null) { - String error = "Error at reading the POST request." + - "Note that the Encoding must be ISO-8859-1."; - return PageCache.loadPage(PageId.ERROR.of(error), () -> new BadRequestResponse(error)); - } - - Map variables = WebAPI.readVariables(requestBody); - String sender = variables.get("sender"); - Log.debug("Received WebAPI Request" + target + " from " + sender); - - boolean isPing = "pingwebapi".equalsIgnoreCase(method); - boolean isSetupRequest = "requestsetupwebapi".equalsIgnoreCase(method); - boolean isPostOriginalSettings = "postoriginalbukkitsettingswebapi".equalsIgnoreCase(method); - boolean skipAuthCheck = isPing || isSetupRequest || isPostOriginalSettings; - - // TODO refactor to more methods - if (!skipAuthCheck) { - String accessKey = variables.get("accessKey"); - if (accessKey == null) { - if (!checkKey(sender)) { - String error = "Server Key not given or invalid"; - Log.debug("Request had invalid Server key: " + sender); - return PageCache.loadPage(PageId.ERROR.of(error), () -> { - ForbiddenResponse forbidden = new ForbiddenResponse(); - forbidden.setContent(error); - return forbidden; - }); - } - } else { - if (!webAPI.isAuthorized(accessKey)) { - String error = "Access Key invalid"; - Log.debug("Request had invalid Access key: " + accessKey); - return PageCache.loadPage(PageId.ERROR.of(error), () -> { - ForbiddenResponse forbidden = new ForbiddenResponse(); - forbidden.setContent(error); - return forbidden; - }); - } - } - } - - WebAPI api = webAPI.getAPI(method); - - if (api == null) { - String error = "API Method not found"; - Log.debug(error); - return PageCache.loadPage(PageId.ERROR.of(error), () -> new BadRequestResponse(error)); - } - - Response response = api.processRequest(MiscUtils.getIPlan(), variables); - - Log.debug("Response: " + response.getResponse().split("\r\n")[0]); - - return response; - } - - private String readPOSTRequest(InputStream in) throws IOException { - byte[] bytes; - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - byte[] buf = new byte[4096]; - for (int n = in.read(buf); n > 0; n = in.read(buf)) { - out.write(buf, 0, n); - } - - bytes = out.toByteArray(); - - try { - return new String(bytes, StandardCharsets.ISO_8859_1); - } catch (Exception e) { - return null; - } - } - - private boolean checkKey(String sender) { - if (sender == null) { - return false; - } - - try { - List uuids = MiscUtils.getIPlan().getDB().getServerTable().getServerUUIDs(); - UUID keyUUID = UUID.fromString(sender); - return uuids.contains(keyUUID); - } catch (SQLException | IllegalArgumentException e) { - return false; - } - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/ResponseHandler.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/ResponseHandler.java deleted file mode 100644 index 5ab8363e6..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/ResponseHandler.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver; - -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.ParseException; -import com.djrapitops.plan.api.exceptions.WebUserAuthException; -import com.djrapitops.plan.data.WebUser; -import com.djrapitops.plan.database.tables.SecurityTable; -import com.djrapitops.plan.systems.webserver.pagecache.PageCache; -import com.djrapitops.plan.systems.webserver.pagecache.PageId; -import com.djrapitops.plan.systems.webserver.response.*; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plan.utilities.PassEncryptUtil; -import com.djrapitops.plan.utilities.uuid.UUIDUtility; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.sql.SQLException; -import java.util.Base64; -import java.util.Optional; -import java.util.UUID; - -/** - * Handles choosing of the correct response to a request. - * - * @author Rsl1122 - */ -public class ResponseHandler extends APIResponseHandler { - - private final IPlan plugin; - - private final boolean usingHttps; - - public ResponseHandler(IPlan plugin, WebServer webServer) { - super(webServer.getWebAPI()); - this.plugin = plugin; - this.usingHttps = webServer.isUsingHTTPS(); - } - - public Response getResponse(Request request) { - String target = request.getTarget(); - String[] args = target.split("/"); - try { - if ("/favicon.ico".equals(target)) { - return PageCache.loadPage(PageId.FAVICON_REDIRECT.id(), () -> new RedirectResponse("https://puu.sh/tK0KL/6aa2ba141b.ico")); - } - if (request.isAPIRequest()) { - return getAPIResponse(request); - } - if (target.endsWith(".css")) { - return PageCache.loadPage(PageId.CSS.of(target), () -> new CSSResponse(target)); - } - - if (target.endsWith(".js")) { - return PageCache.loadPage(PageId.JS.of(target), () -> new JavaScriptResponse(target)); - } - - UUID serverUUID = MiscUtils.getIPlan().getServerUuid(); - - if (usingHttps) { - if (!request.hasAuth()) { - throw new WebUserAuthException("No Authorization"); - } - - WebUser user = getUser(request.getAuth()); - int required = getRequiredPermLevel(target, user.getName()); - int permLevel = user.getPermLevel(); - - if (!isAuthorized(required, permLevel)) { - return forbiddenResponse(required, permLevel); - } - if (args.length < 2) { - return rootPageResponse(user, serverUUID); - } - } else if (args.length < 2) { - return notFoundResponse(); - } - - String page = args[1]; - switch (page) { - case "debug": - return new DebugPageResponse(); - case "players": - return PageCache.loadPage(PageId.PLAYERS.id(), PlayersPageResponse::new); - case "player": - return playerResponse(args); - case "network": - case "server": - if (args.length > 2) { - try { - Optional serverUUIDOptional = plugin.getDB().getServerTable().getServerUUID(args[2].replace("%20", " ")); - if (serverUUIDOptional.isPresent()) { - serverUUID = serverUUIDOptional.get(); - } - } catch (IllegalArgumentException ignore) { - /*ignored*/ - } - } - return serverResponse(serverUUID); - default: - return notFoundResponse(); - } - - } catch (WebUserAuthException e) { - return PageCache.loadPage(PageId.AUTH_PROMPT.id(), PromptAuthorizationResponse::new); - } catch (Exception e) { - Log.toLog(this.getClass().getName(), e); - return new InternalErrorResponse(e, request.getTarget()); - } - } - - private Response forbiddenResponse(int required, int permLevel) { - return PageCache.loadPage(PageId.FORBIDDEN.id(), () -> - new ForbiddenResponse("Unauthorized User.
    " - + "Make sure your user has the correct access level.
    " - + "This page requires permission level of " + required + ",
    " - + "This user has permission level of " + permLevel)); - } - - private boolean isAuthorized(int requiredPermLevel, int permLevel) { - return permLevel <= requiredPermLevel; - } - - private WebUser getUser(String auth) throws SQLException, PassEncryptUtil.InvalidHashException, PassEncryptUtil.CannotPerformOperationException, WebUserAuthException { - Base64.Decoder decoder = Base64.getDecoder(); - byte[] decoded = decoder.decode(auth); - String[] userInfo = new String(decoded).split(":"); - if (userInfo.length != 2) { - throw new WebUserAuthException("User and Password not specified"); - } - - String user = userInfo[0]; - String passwordRaw = userInfo[1]; - - SecurityTable securityTable = plugin.getDB().getSecurityTable(); - if (!securityTable.userExists(user)) { - throw new WebUserAuthException("User Doesn't exist"); - } - - WebUser webUser = securityTable.getWebUser(user); - - boolean correctPass = PassEncryptUtil.verifyPassword(passwordRaw, webUser.getSaltedPassHash()); - if (!correctPass) { - throw new WebUserAuthException("User and Password do not match"); - } - return webUser; - } - - private int getRequiredPermLevel(String target, String user) { - String[] t = target.split("/"); - if (t.length < 2) { - return 100; - } - if (t.length > 3) { - return 0; - } - String page = t[1]; - switch (page) { - case "players": - return 1; - case "player": - // /player/ - 404 for perm lvl 1 - if (t.length < 3) { - return 1; - } - - final String wantedUser = t[2].toLowerCase().trim(); - final String theUser = user.trim().toLowerCase(); - - return wantedUser.equals(theUser) ? 2 : 1; - default: - return 0; - } - } - - private Response rootPageResponse(WebUser user, UUID serverUUID) { - if (user == null) { - return notFoundResponse(); - } - - switch (user.getPermLevel()) { - case 0: - return serverResponse(serverUUID); - case 1: - return PageCache.loadPage(PageId.PLAYERS.id(), PlayersPageResponse::new); - case 2: - return playerResponse(new String[]{"", "", user.getName()}); - default: - return forbiddenResponse(user.getPermLevel(), 0); - } - } - - private Response serverResponse(UUID serverUUID) { - return PageCache.loadPage(PageId.SERVER.of(serverUUID), () -> new AnalysisPageResponse(plugin.getInfoManager())); - } - - private Response playerResponse(String[] args) { - if (args.length < 3) { - return PageCache.loadPage(PageId.NOT_FOUND.id(), NotFoundResponse::new); - } - - String playerName = args[2].trim(); - UUID uuid = UUIDUtility.getUUIDOf(playerName); - - if (uuid == null) { - String error = "Player has no UUID"; - return PageCache.loadPage(PageId.NOT_FOUND.of(error), () -> new NotFoundResponse(error)); - } - - if (plugin.getDB().wasSeenBefore(uuid)) { - plugin.getInfoManager().cachePlayer(uuid); - Response response = PageCache.loadPage(PageId.PLAYER.of(uuid)); - // TODO Create a new method that places NotFoundResponse to PageCache instead. - if (response == null || response.getContent().contains("No Bukkit Servers were online to process this request")) { - PageCache.cachePage(PageId.PLAYER.of(uuid), () -> { - try { - return new InspectPageResponse(plugin.getInfoManager(), uuid); - } catch (ParseException e) { - return new InternalErrorResponse(e, this.getClass().getName()); - } - }); - response = PageCache.loadPage(PageId.PLAYER.of(uuid)); - } - return response; - } - return new NotFoundResponse("Player has not played on this server."); - } - - private Response notFoundResponse() { - String error = "404 Not Found"; - return PageCache.loadPage(PageId.NOT_FOUND.of("Wrong Page"), () -> { - String url = plugin.getInfoManager().getWebServerAddress(); - return new NotFoundResponse("Make sure you're accessing a link given by a command, Examples:

    " - + "

    " + url + "/player/Playername
    " + - url + "/server

    "); - } - ); - } - - -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/WebServerSystem.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/WebServerSystem.java deleted file mode 100644 index 31d58cf46..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/WebServerSystem.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver; - -import com.djrapitops.plan.api.exceptions.PlanEnableException; -import com.djrapitops.plan.systems.SubSystem; -import com.djrapitops.plan.systems.Systems; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plugin.api.Check; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public class WebServerSystem implements SubSystem { - - private WebServer webServer; - - public WebServerSystem() { - - } - - public static WebServerSystem getInstance() { - return Systems.getInstance().getWebServerSystem(); - } - - @Override - public void init() throws PlanEnableException { - webServer = new WebServer(MiscUtils.getIPlan()); - webServer.initServer(); - if (Check.isBungeeAvailable() && !webServer.isEnabled()) { - throw new PlanEnableException("WebServer did not initialize!"); - } - } - - @Override - public void close() { - // TODO Remove after WebServer setting requirement is gone. - if (webServer != null) { - webServer.stop(); - } - } - - public static boolean isWebServerEnabled() { - WebServer webServer = getInstance().webServer; - return webServer != null && webServer.isEnabled(); - } - - public WebServer getWebServer() { - return webServer; - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/pagecache/PageCache.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/pagecache/PageCache.java deleted file mode 100644 index 583cb448f..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/pagecache/PageCache.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.djrapitops.plan.systems.webserver.pagecache; - -import com.djrapitops.plan.systems.webserver.response.InspectPageResponse; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; - -import java.util.Map; -import java.util.function.Predicate; - -/** - * This class contains the page cache. - *

    - * It caches all Responses with their matching identifiers. - * This reduces CPU cycles and the time to wait for loading the pages. - * This is especially useful in situations where multiple clients are accessing the server. - *

    - * This cache uses the Google Guava {@link Cache}. - * - * @author Fuzzlemann - * @since 3.6.0 - */ -public class PageCache { - - private static final Cache pageCache = CacheBuilder.newBuilder() - .build(); - - /** - * Constructor used to hide the public constructor - */ - private PageCache() { - throw new IllegalStateException("Utility class"); - } - - /** - * Loads the page from the page cache. - *

    - * If the {@link Response} isn't cached, {@link PageLoader#createResponse()} in the {@code loader} - * is called to create the Response. - *

    - * If the Response is created, it's automatically cached. - * - * @param identifier The identifier of the page - * @param loader The {@link PageLoader} (How should it load the page if it's not cached) - * @return The Response that was cached or created by the {@link PageLoader loader} - */ - public static Response loadPage(String identifier, PageLoader loader) { - Response response = loadPage(identifier); - - if (response != null) { - return response; - } - - response = loader.createResponse(); - - pageCache.put(identifier, response); - - return response; - } - - /** - * Loads the page from the page cache. - * - * @param identifier The identifier of the page - * @return The Response that was cached or {@code null} if it wasn't - */ - public static Response loadPage(String identifier) { - return pageCache.getIfPresent(identifier); - } - - /** - * Returns a copy some responses - * - * Currently supported copyable responses: InspectPageResponse - * - * @param identifier The identifier of the page - * @return Copied Response of loadPage, so that cache contents are not changed. - */ - public static Response copyPage(String identifier, PageLoader loader) { - Response response = loadPage(identifier, loader); - if (response instanceof InspectPageResponse) { - return InspectPageResponse.copyOf((InspectPageResponse) response); - } - return response; - } - - /** - * Puts the page into the page cache. - *

    - * If the cache already inherits that {@code identifier}, it's renewed. - * - * @param identifier The identifier of the page - * @param loader The {@link PageLoader} (How it should load the page) - */ - public static void cachePage(String identifier, PageLoader loader) { - Response response = loader.createResponse(); - pageCache.put(identifier, response); - } - - /** - * Checks if the page is cached. - * - * @param identifier The identifier of the page - * @return true if the page is cached - */ - public static boolean isCached(String identifier) { - return pageCache.asMap().containsKey(identifier); - } - - /** - * Removes all of the elements of this cache that satisfy the given predicate. - * - * @param filter a predicate which returns true for entries to be removed - */ - public static void removeIf(Predicate filter) { - Map pageCacheMap = pageCache.asMap(); - - for (String identifier : pageCacheMap.keySet()) { - if (filter.test(identifier)) { - pageCache.invalidate(identifier); - } - } - } - - /** - * Clears the cache from all its contents. - */ - public static void clearCache() { - pageCache.invalidateAll(); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/pagecache/PageLoader.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/pagecache/PageLoader.java deleted file mode 100644 index dff2a8e92..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/pagecache/PageLoader.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.djrapitops.plan.systems.webserver.pagecache; - -import com.djrapitops.plan.systems.webserver.response.Response; - -/** - * This interface is used for providing the method to load the page. - * - * @author Fuzzlemann - * @since 3.6.0 - */ -public interface PageLoader { - - Response createResponse(); - -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/AnalysisPageResponse.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/AnalysisPageResponse.java deleted file mode 100644 index 9af6991c2..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/AnalysisPageResponse.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.djrapitops.plan.systems.webserver.response; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.data.AnalysisData; -import com.djrapitops.plan.systems.info.BukkitInformationManager; -import com.djrapitops.plan.systems.info.InformationManager; -import com.djrapitops.plugin.task.AbsRunnable; -import com.djrapitops.plugin.task.RunnableFactory; - -/** - * @author Rsl1122 - * @since 3.5.2 - */ -public class AnalysisPageResponse extends Response { - - /** - * Constructor. - * - * @param informationManager InformationManager to use for getting the Html - * @throws NullPointerException if AnalysisData has not been cached after 1 second. - */ - public AnalysisPageResponse(InformationManager informationManager) { - super.setHeader("HTTP/1.1 200 OK"); - - if (informationManager instanceof BukkitInformationManager) { - AnalysisData analysisData = ((BukkitInformationManager) informationManager).getAnalysisData(); - if (analysisData == null) { - RunnableFactory.createNew("OnRequestAnalysisRefreshTask", new AbsRunnable() { - @Override - public void run() { - informationManager.refreshAnalysis(Plan.getServerUUID()); - } - }).runTaskAsynchronously(); - - ErrorResponse analysisRefreshPage = new ErrorResponse(); - analysisRefreshPage.setTitle("Analysis is being refreshed.."); - analysisRefreshPage.setParagraph(" Analysis is being run, refresh the page after a few seconds.. (F5)"); - analysisRefreshPage.replacePlaceholders(); - super.setContent(analysisRefreshPage.getContent()); - - return; - } - } - super.setContent(informationManager.getAnalysisHtml()); - } - - public AnalysisPageResponse(String html) { - super.setHeader("HTTP/1.1 200 OK"); - super.setContent(html); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/InspectPageResponse.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/InspectPageResponse.java deleted file mode 100644 index 1a12057db..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/InspectPageResponse.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.djrapitops.plan.systems.webserver.response; - -import com.djrapitops.plan.api.exceptions.ParseException; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.systems.info.InformationManager; -import org.apache.commons.lang3.text.StrSubstitutor; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * @author Rsl1122 - * @since 3.5.2 - */ -public class InspectPageResponse extends Response { - - private final UUID uuid; - - public InspectPageResponse(InformationManager infoManager, UUID uuid) throws ParseException { - this.uuid = uuid; - super.setHeader("HTTP/1.1 200 OK"); - super.setContent(infoManager.getPlayerHtml(uuid)); - setInspectPagePluginsTab(infoManager.getPluginsTabContent(uuid)); - } - - public InspectPageResponse(InformationManager infoManager, UUID uuid, String html) { - this.uuid = uuid; - super.setHeader("HTTP/1.1 200 OK"); - super.setContent(Theme.replaceColors(html)); - setInspectPagePluginsTab(infoManager.getPluginsTabContent(uuid)); - } - - private InspectPageResponse(InspectPageResponse response) { - this.uuid = response.uuid; - super.setHeader(response.getHeader()); - super.setContent(response.getContent()); - } - - public void setInspectPagePluginsTab(String[] inspectPagePluginsTab) { - Map replaceMap = new HashMap<>(); - replaceMap.put("navPluginsTabs", inspectPagePluginsTab[0]); - replaceMap.put("pluginsTabs", inspectPagePluginsTab[1]); - - setContent(StrSubstitutor.replace(getContent(), replaceMap)); - } - - public static InspectPageResponse copyOf(InspectPageResponse response) { - return new InspectPageResponse(response); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/PromptAuthorizationResponse.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/PromptAuthorizationResponse.java deleted file mode 100644 index ae1de29f7..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/response/PromptAuthorizationResponse.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.djrapitops.plan.systems.webserver.response; - -import com.djrapitops.plan.utilities.html.Html; - -/** - * @author Rsl1122 - * @since 3.5.2 - */ -public class PromptAuthorizationResponse extends ErrorResponse { - - public PromptAuthorizationResponse() { - super.setHeader("HTTP/1.1 401 Access Denied\r\n" - + "WWW-Authenticate: Basic realm=\"/\";"); - super.setTitle(Html.FONT_AWESOME_ICON.parse("lock")+" 401 Unauthorized"); - super.setParagraph("Authentication Failed.
    " - + "- Ensure you have registered a user with /plan register
    " - + "- Check that the username and password are correct
    " - + "- Username and password are case-sensitive
    " - + "
    If you have forgotten your password, ask a staff member to delete your old user and re-register."); - super.replacePlaceholders(); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/WebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/WebAPI.java deleted file mode 100644 index 29ff40401..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/WebAPI.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi; - -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.*; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.webserver.pagecache.PageCache; -import com.djrapitops.plan.systems.webserver.pagecache.PageId; -import com.djrapitops.plan.systems.webserver.response.NotFoundResponse; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.response.api.BadRequestResponse; -import com.djrapitops.plan.systems.webserver.response.api.SuccessResponse; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.utilities.Verify; - -import javax.net.ssl.*; -import java.io.DataOutputStream; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.SocketTimeoutException; -import java.net.URL; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; - -/** - * @author Rsl1122 - */ -public abstract class WebAPI { - - private Map variables; - - public WebAPI() { - this.variables = new HashMap<>(); - } - - public Response processRequest(IPlan plugin, Map variables) { - String sender = variables.get("sender"); - if (sender == null) { - Log.debug(getClass().getSimpleName() + ": Sender not Found"); - return badRequest("Sender not present"); - } else { - try { - UUID.fromString(sender); - } catch (Exception e) { - Log.debug(getClass().getSimpleName() + ": Invalid Sender UUID"); - return badRequest("Faulty Sender value"); - } - } - return onRequest(plugin, variables); - } - - public abstract Response onRequest(IPlan plugin, Map variables); - - public void sendRequest(String address) throws WebAPIException { - Verify.nullCheck(address); - - try { - URL url = new URL(address + "/api/" + this.getClass().getSimpleName().toLowerCase()); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - if (address.startsWith("https")) { - HttpsURLConnection httpsConn = (HttpsURLConnection) connection; - - // Disables unsigned certificate & hostname check, because we're trusting the user given certificate. - - // This allows https connections internally to local ports. - httpsConn.setHostnameVerifier((hostname, session) -> true); - - // This allows connecting to connections with invalid certificate - // Drawback: MitM attack possible between connections to servers that are not local. - // Scope: WebAPI transmissions - // Risk: Attacker sets up a server between Bungee and Bukkit WebServers - // - Negotiates SSL Handshake with both servers - // - Receives the SSL encrypted data, but decrypts it in the MitM server. - // -> Access to valid ServerUUID for POST requests - // -> Access to sending Html to the (Bungee) WebServer - // Mitigating factors: - // - If Server owner has access to all routing done on the domain (IP/Address) - // - If Direct IPs are used to transfer between servers - // Alternative solution: WebAPI run only on HTTP, HTTP can be read during transmission, - // would require running two WebServers when HTTPS is used. - httpsConn.setSSLSocketFactory(getRelaxedSocketFactory()); - } - connection.setConnectTimeout(10000); - connection.setDoOutput(true); - connection.setInstanceFollowRedirects(false); - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - - connection.setRequestProperty("charset", "UTF-8"); - - String parameters = parseVariables(); - - connection.setRequestProperty("Content-Length", Integer.toString(parameters.length())); - - byte[] toSend = parameters.getBytes(); - - connection.setUseCaches(false); - Log.debug("Sending WebAPI Request: " + this.getClass().getSimpleName() + " to " + address); - try (DataOutputStream out = new DataOutputStream(connection.getOutputStream())) { - out.write(toSend); - } - - int responseCode = connection.getResponseCode(); - Log.debug("Response: " + responseCode); - switch (responseCode) { - case 200: - return; - case 400: - throw new WebAPIFailException("Bad Request: " + url.toString() + "|" + parameters); - case 403: - throw new WebAPIForbiddenException(url.toString()); - case 404: - throw new WebAPINotFoundException(); - case 500: - throw new WebAPIInternalErrorException(); - default: - throw new WebAPIException(url.toString() + "| Wrong response code " + responseCode); - } - } catch (SocketTimeoutException e) { - throw new WebAPIConnectionFailException("Connection timed out after 10 seconds.", e); - } catch (NoSuchAlgorithmException | KeyManagementException | IOException e) { - if (Settings.DEV_MODE.isTrue()) { - Log.toLog(this.getClass().getName(), e); - } - throw new WebAPIConnectionFailException("API connection failed. address: " + address, e); - } - } - - protected void addVariable(String key, String value) { - variables.put(key, value); - } - - public Map getVariables() { - return variables; - } - - private SSLSocketFactory getRelaxedSocketFactory() throws NoSuchAlgorithmException, KeyManagementException { - SSLContext sc = SSLContext.getInstance("SSL"); - sc.init(null, trustAllCerts, new java.security.SecureRandom()); - return sc.getSocketFactory(); - } - - private static TrustManager[] trustAllCerts = new TrustManager[]{ - new X509TrustManager() { - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { - //No need to implement. - } - - public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { - //No need to implement. - } - } - }; - - protected Response success() { - return PageCache.loadPage(PageId.TRUE.id(), SuccessResponse::new); - } - - protected Response fail(String reason) { - return PageCache.loadPage(PageId.FALSE.id(), () -> { - NotFoundResponse notFoundResponse = new NotFoundResponse(""); - notFoundResponse.setContent(reason); - return notFoundResponse; - }); - } - - protected Response badRequest(String error) { - return PageCache.loadPage(PageId.ERROR.of(error), () -> new BadRequestResponse(error)); - } - - private String parseVariables() { - StringBuilder parameters = new StringBuilder(); - String serverUUID = MiscUtils.getIPlan().getServerUuid().toString(); - parameters.append("sender=").append(serverUUID); - for (Map.Entry entry : variables.entrySet()) { - parameters.append(";&variable;").append(entry.getKey()).append("=").append(entry.getValue()); - } - return parameters.toString(); - } - - public static Map readVariables(String requestBody) { - String[] variables = requestBody.split(";&variable;"); - - return Arrays.stream(variables) - .map(variable -> variable.split("=", 2)) - .filter(splitVariables -> splitVariables.length == 2) - .collect(Collectors.toMap(splitVariables -> splitVariables[0], splitVariables -> splitVariables[1], (a, b) -> b)); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/WebAPIManager.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/WebAPIManager.java deleted file mode 100644 index 2048afac5..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/WebAPIManager.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi; - -import com.djrapitops.plan.utilities.PassEncryptUtil; - -import java.util.*; - -/** - * @author Fuzzlemann and Rsl1122 - */ -public class WebAPIManager { - - private final Map registry; - private static final Set accessKeys = new HashSet<>(); - - /** - * Constructor used to hide the public constructor - */ - public WebAPIManager() { - registry = new HashMap<>(); - } - - public void registerNewAPI(WebAPI... api) { - for (WebAPI webAPI : api) { - registerNewAPI(webAPI); - } - } - - public boolean isAuthorized(String key) { - return accessKeys.contains(key); - } - - public void authorize(String key) { - accessKeys.remove(key); - } - - public String generateNewAccessKey() throws Exception { - String key = PassEncryptUtil.createHash(UUID.randomUUID().toString().substring(0, 5)).split(":")[4]; - accessKeys.add(key); - return key; - } - - public void registerNewAPI(WebAPI api) { - registry.put(api.getClass().getSimpleName().toLowerCase(), api); - } - - public T getAPI(Class api) { - WebAPI webAPI = getAPI(api.getSimpleName()); - return (T) webAPI; - } - - public WebAPI getAPI(String apiName) { - return registry.get(apiName.toLowerCase()); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/AnalysisReadyWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/AnalysisReadyWebAPI.java deleted file mode 100644 index c8af2ab5c..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/AnalysisReadyWebAPI.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bukkit; - -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; - -import java.util.Map; -import java.util.UUID; - -/** - * @author Rsl1122 - */ -public class AnalysisReadyWebAPI extends WebAPI { - @Override - public Response onRequest(IPlan plugin, Map variables) { - String serverUUIDS = variables.get("serverUUID"); - if (serverUUIDS == null) { - return badRequest("serverUUID was not present"); - } - UUID serverUUID = UUID.fromString(serverUUIDS); - plugin.getInfoManager().analysisReady(serverUUID); - return success(); - } - - @Override - public void sendRequest(String address) throws WebAPIException { - throw new IllegalStateException("Wrong method call for this WebAPI, call sendRequest(String, UUID, UUID) instead."); - } - - public void sendRequest(String address, UUID serverUUID) throws WebAPIException { - addVariable("serverUUID", serverUUID.toString()); - super.sendRequest(address); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/AnalyzeWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/AnalyzeWebAPI.java deleted file mode 100644 index da92785a8..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/AnalyzeWebAPI.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bukkit; - -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; - -import java.util.Map; -import java.util.UUID; - -/** - * @author Rsl1122 - */ -public class AnalyzeWebAPI extends WebAPI { - @Override - public Response onRequest(IPlan plugin, Map variables) { - String serverUUIDS = variables.get("serverUUID"); - if (serverUUIDS == null) { - return badRequest("serverUUID was not present"); - } - UUID serverUUID = UUID.fromString(serverUUIDS); - plugin.getInfoManager().refreshAnalysis(serverUUID); - return success(); - } - - @Override - public void sendRequest(String address) throws WebAPIException { - throw new IllegalStateException("Wrong method call for this WebAPI, call sendRequest(String, UUID, UUID) instead."); - } - - public void sendRequest(String address, UUID serverUUID) throws WebAPIException { - addVariable("serverUUID", serverUUID.toString()); - super.sendRequest(address); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/ConfigurationWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/ConfigurationWebAPI.java deleted file mode 100644 index 41fad8403..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/ConfigurationWebAPI.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bukkit; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.settings.ServerSpecificSettings; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; -import com.djrapitops.plugin.api.Check; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.utilities.Verify; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * @author Fuzzlemann - */ -public class ConfigurationWebAPI extends WebAPI { - - @Override - public Response onRequest(IPlan plugin, Map variables) { - if (!Check.isBukkitAvailable()) { - Log.debug("Called a wrong server type"); - return badRequest("Called a Bungee Server"); - } - if (Settings.BUNGEE_COPY_CONFIG.isFalse() || Settings.BUNGEE_OVERRIDE_STANDALONE_MODE.isTrue()) { - Log.info("Bungee Config settings overridden on this server."); - Log.debug(plugin.getMainConfig().getConfigNode("Plugin.Bungee-Override").getChildren().toString()); - return success(); - } - ServerSpecificSettings.updateSettings((Plan) plugin, variables); - return success(); - } - - @Override - public void sendRequest(String address) throws WebAPIException { - throw new IllegalStateException("Wrong method call for this WebAPI, call sendRequest(String, UUID, UUID) instead."); - } - - public void sendRequest(String address, UUID serverUUID, String accessKey) throws WebAPIException { - if (accessKey != null) { - addVariable("accessKey", accessKey); - } - addVariable("webAddress", PlanBungee.getInstance().getWebServer().getAccessAddress()); - - sendRequest(address, serverUUID); - } - - public void sendRequest(String address, UUID serverUUID) throws WebAPIException { - Map configValues = getConfigValues(serverUUID); - for (Map.Entry entry : configValues.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - if (!Verify.notNull(key, value)) { - continue; - } - addVariable(key, value.toString()); - } - super.sendRequest(address); - } - - private void addConfigValue(Map configValues, Settings setting, Object value) { - if (value != null) { - configValues.put(setting.getPath(), value); - } - } - - private Map getConfigValues(UUID serverUUID) throws WebAPIException { - Map configValues = new HashMap<>(); - if (!Check.isBungeeAvailable()) { - throw new WebAPIException("Attempted to send config values from Bukkit to Bungee."); - } - addConfigValue(configValues, Settings.DB_TYPE, "mysql"); - Settings[] sameStrings = new Settings[]{ - Settings.DB_HOST, Settings.DB_USER, Settings.DB_PASS, - Settings.DB_DATABASE, Settings.FORMAT_DECIMALS, Settings.FORMAT_SECONDS, - Settings.FORMAT_DAY, Settings.FORMAT_DAYS, Settings.FORMAT_HOURS, - Settings.FORMAT_MINUTES, Settings.FORMAT_MONTHS, Settings.FORMAT_MONTH, - Settings.FORMAT_YEAR, Settings.FORMAT_YEARS, Settings.FORMAT_ZERO_SECONDS - }; - for (Settings setting : sameStrings) { - addConfigValue(configValues, setting, setting.toString()); - } - addConfigValue(configValues, Settings.DB_PORT, Settings.DB_PORT.getNumber()); - addServerSpecificValues(configValues, serverUUID); - - return configValues; - } - - private void addServerSpecificValues(Map configValues, UUID serverUUID) { - ServerSpecificSettings settings = Settings.serverSpecific(); - - String theme = settings.getString(serverUUID, Settings.THEME_BASE); - Integer port = settings.getInt(serverUUID, Settings.WEBSERVER_PORT); - String name = settings.getString(serverUUID, Settings.SERVER_NAME); - - if (!Verify.isEmpty(theme)) { - addConfigValue(configValues, Settings.THEME_BASE, theme); - } - if (port != null && port != 0) { - addConfigValue(configValues, Settings.WEBSERVER_PORT, port); - } - if (!Verify.isEmpty(name)) { - addConfigValue(configValues, Settings.SERVER_NAME, name); - } - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/InspectWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/InspectWebAPI.java deleted file mode 100644 index d25d65e35..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/InspectWebAPI.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bukkit; - -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; - -import java.util.Map; -import java.util.UUID; - -/** - * @author Rsl1122 - */ -public class InspectWebAPI extends WebAPI { - @Override - public Response onRequest(IPlan plugin, Map variables) { - String uuidS = variables.get("uuid"); - if (uuidS == null) { - return badRequest("UUID not included"); - } - UUID uuid = UUID.fromString(uuidS); - - plugin.getInfoManager().cachePlayer(uuid); - - return success(); - } - - @Override - public void sendRequest(String address) throws WebAPIException { - throw new IllegalStateException("Wrong method call for this WebAPI, call sendRequest(String, UUID, UUID) instead."); - } - - public void sendRequest(String address, UUID uuid) throws WebAPIException { - addVariable("uuid", uuid.toString()); - super.sendRequest(address); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/IsOnlineWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/IsOnlineWebAPI.java deleted file mode 100644 index e4badd9cb..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/IsOnlineWebAPI.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bukkit; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; -import org.bukkit.entity.Player; - -import java.util.Map; -import java.util.UUID; - -/** - * @author Fuzzlemann - */ -public class IsOnlineWebAPI extends WebAPI { - @Override - public Response onRequest(IPlan plugin, Map variables) { - String uuidS = variables.get("uuid"); - if (uuidS == null) { - return badRequest("UUID not included"); - } - UUID uuid = UUID.fromString(uuidS); - - Player player = Plan.getInstance().getServer().getPlayer(uuid); - - if (player != null && player.isOnline()) { - return success(); - } else { - return fail("Not Online"); - } - } - - @Override - public void sendRequest(String address) throws WebAPIException { - throw new IllegalStateException("Wrong method call for this WebAPI, call sendRequest(String, UUID, UUID) instead."); - } - - public void sendRequest(String address, UUID uuid) throws WebAPIException { - addVariable("uuid", uuid.toString()); - super.sendRequest(address); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/RequestInspectPluginsTabBukkitWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/RequestInspectPluginsTabBukkitWebAPI.java deleted file mode 100644 index 716760529..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bukkit/RequestInspectPluginsTabBukkitWebAPI.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bukkit; - -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.systems.info.BukkitInformationManager; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; -import com.djrapitops.plugin.api.Check; - -import java.util.Map; -import java.util.UUID; - -/** - * WebAPI for requesting Inspect plugins tab contents from a Bukkit Server. - *

    - * Call: Bungee to Bukkit - *

    - * Bad Requests: - * - Called a Bungee Server - * - Did not include uuid variable - * - * @author Rsl1122 - */ -public class RequestInspectPluginsTabBukkitWebAPI extends WebAPI { - - @Override - public Response onRequest(IPlan plugin, Map variables) { - if (!Check.isBukkitAvailable()) { - return badRequest("Called a Bungee Server"); - } - - String uuidS = variables.get("uuid"); - if (uuidS == null) { - return badRequest("UUID not included"); - } - UUID uuid = UUID.fromString(uuidS); - - ((BukkitInformationManager) plugin.getInfoManager()).cacheInspectPluginsTab(uuid, this.getClass()); - return success(); - } - - @Override - public void sendRequest(String address) throws WebAPIException { - throw new IllegalStateException("Wrong method call for this WebAPI, call sendRequest(String, UUID, UUID) instead."); - } - - public void sendRequest(String address, UUID uuid) throws WebAPIException { - addVariable("uuid", uuid.toString()); - super.sendRequest(address); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/IsCachedWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/IsCachedWebAPI.java deleted file mode 100644 index de5ed9e3d..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/IsCachedWebAPI.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bungee; - -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.api.exceptions.WebAPINotFoundException; -import com.djrapitops.plan.systems.info.InformationManager; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; - -import java.util.Map; -import java.util.UUID; - -/** - * WebAPI for checking if a page is in webserver cache. - * - * @author Rsl1122 - */ -public class IsCachedWebAPI extends WebAPI { - - @Override - public Response onRequest(IPlan plugin, Map variables) { - try { - String target = variables.get("target"); - InformationManager infoManager = plugin.getInfoManager(); - boolean cached = false; - switch (target) { - case "inspectPage": - if (infoManager.isCached(UUID.fromString(variables.get("uuid")))) { - cached = true; - } - break; - case "analysisPage": - if (infoManager.isAnalysisCached(UUID.fromString(variables.get("serverUUID")))) { - cached = true; - } - break; - default: - return badRequest("Faulty Target"); - } - if (cached) { - return success(); - } else { - return fail("Not Cached"); - } - } catch (NullPointerException e) { - return badRequest(e.toString()); - } - } - - @Override - public void sendRequest(String address) throws WebAPIException { - throw new IllegalStateException("Wrong method call for this WebAPI, call sendRequest(String, UUID, UUID) instead."); - } - - public boolean isInspectCached(String address, UUID uuid) throws WebAPIException { - addVariable("uuid", uuid.toString()); - addVariable("target", "inspectPage"); - try { - super.sendRequest(address); - return true; - } catch (WebAPINotFoundException e) { - return false; - } - } - - public boolean isAnalysisCached(String address, UUID serverUUID) throws WebAPIException { - addVariable("serverUUID", serverUUID.toString()); - addVariable("target", "analysisPage"); - try { - super.sendRequest(address); - return true; - } catch (WebAPINotFoundException e) { - return false; - } - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostHtmlWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostHtmlWebAPI.java deleted file mode 100644 index 18a8569f4..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostHtmlWebAPI.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bungee; - -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.info.InformationManager; -import com.djrapitops.plan.systems.webserver.pagecache.PageCache; -import com.djrapitops.plan.systems.webserver.pagecache.PageId; -import com.djrapitops.plan.systems.webserver.response.AnalysisPageResponse; -import com.djrapitops.plan.systems.webserver.response.InspectPageResponse; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; -import com.djrapitops.plan.utilities.file.export.HtmlExport; -import com.djrapitops.plugin.api.utility.log.Log; -import org.apache.commons.lang3.text.StrSubstitutor; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * WebAPI for posting Html pages such as Inspect or server pages. - * - * @author Rsl1122 - */ -public class PostHtmlWebAPI extends WebAPI { - - @Override - public Response onRequest(IPlan plugin, Map variables) { - try { - String htmlVariable = variables.get("html"); - if (htmlVariable == null) { - return badRequest("Html was null"); - } - if (!htmlVariable.startsWith("")) { - String[] split = htmlVariable.split("", 2); - if (split.length <= 1) { - Log.debug(htmlVariable); - return badRequest("Html did not start with "); - } - htmlVariable = "" + split[1]; - } - String html = htmlVariable; - - String target = variables.get("target"); - InformationManager infoManager = plugin.getInfoManager(); - switch (target) { - case "inspectPage": - String uuid = variables.get("uuid"); - - Map map = new HashMap<>(); - map.put("networkName", Settings.BUNGEE_NETWORK_NAME.toString()); - - PageCache.cachePage(PageId.PLAYER.of(uuid), () -> new InspectPageResponse(infoManager, UUID.fromString(uuid), StrSubstitutor.replace(html, map))); - if (Settings.ANALYSIS_EXPORT.isTrue()) { - HtmlExport.exportPlayer(plugin, UUID.fromString(uuid)); - } - break; - case "analysisPage": - String sender = variables.get("sender"); - PageCache.cachePage(PageId.SERVER.of(sender), () -> new AnalysisPageResponse(html)); - if (Settings.ANALYSIS_EXPORT.isTrue()) { - HtmlExport.exportServer(plugin, UUID.fromString(sender)); - } - break; - default: - return badRequest("Faulty Target"); - } - return success(); - } catch (NullPointerException e) { - return badRequest(e.toString()); - } - } - - @Override - public void sendRequest(String address) throws WebAPIException { - throw new IllegalStateException("Wrong method call for this WebAPI, call sendRequest(String, UUID, UUID) instead."); - } - - public void sendInspectHtml(String address, UUID uuid, String html) throws WebAPIException { - addVariable("uuid", uuid.toString()); - addVariable("target", "inspectPage"); - addVariable("html", html); - super.sendRequest(address); - } - - public void sendAnalysisHtml(String address, String html) throws WebAPIException { - addVariable("html", html); - addVariable("target", "analysisPage"); - super.sendRequest(address); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostInspectPluginsTabWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostInspectPluginsTabWebAPI.java deleted file mode 100644 index efb6f3ef2..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostInspectPluginsTabWebAPI.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bungee; - -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.systems.info.BungeeInformationManager; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; - -import java.util.Map; -import java.util.UUID; - -/** - * WebAPI for posting Inspect page Plugins tab contents to the Bungee server. - *

    - * Call: Bukkit to Bungee - *

    - * Bad Requests: - * - Did not include uuid - * - * @author Rsl1122 - */ -public class PostInspectPluginsTabWebAPI extends WebAPI { - @Override - public Response onRequest(IPlan plugin, Map variables) { - String uuidS = variables.get("uuid"); - if (uuidS == null) { - return badRequest("uuid not included"); - } - - UUID uuid = UUID.fromString(uuidS); - UUID serverUUID = UUID.fromString(variables.get("sender")); - String nav = variables.get("nav"); - if (nav == null) { - return badRequest("nav not included"); - } - String html = variables.get("html"); - if (html == null) { - return badRequest("html not included"); - } - String[] content = new String[]{nav, html}; - - ((BungeeInformationManager) plugin.getInfoManager()).cachePluginsTabContent(serverUUID, uuid, content); - - return success(); - } - - @Override - public void sendRequest(String address) throws WebAPIException { - throw new IllegalStateException("Wrong method call for this WebAPI, call sendRequest(String, UUID, UUID) instead."); - } - - public void sendPluginsTab(String address, UUID uuid, String[] html) throws WebAPIException { - addVariable("uuid", uuid.toString()); - addVariable("nav", html[0]); - addVariable("html", html[1]); - super.sendRequest(address); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostNetworkPageContentWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostNetworkPageContentWebAPI.java deleted file mode 100644 index 835bf735e..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostNetworkPageContentWebAPI.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bungee; - - -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.systems.info.BungeeInformationManager; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; -import com.djrapitops.plugin.api.Check; - -import java.util.Map; -import java.util.UUID; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public class PostNetworkPageContentWebAPI extends WebAPI { - @Override - public Response onRequest(IPlan plugin, Map variables) { - if (Check.isBukkitAvailable()) { - return badRequest("Called a Bukkit server."); - } - - UUID serverUUID = UUID.fromString(variables.get("sender")); - String html = variables.get("html"); - if (html == null) { - return badRequest("html not present"); - } - - ((BungeeInformationManager) plugin.getInfoManager()).cacheNetworkPageContent(serverUUID, html); - return success(); - } - - @Override - public void sendRequest(String address) throws WebAPIException { - throw new IllegalStateException("Wrong method call for this WebAPI, call sendRequest(String, UUID, UUID) instead."); - } - - public void sendNetworkContent(String address, String html) throws WebAPIException { - addVariable("html", html); - super.sendRequest(address); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostOriginalBukkitSettingsWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostOriginalBukkitSettingsWebAPI.java deleted file mode 100644 index 764dd1bbf..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/PostOriginalBukkitSettingsWebAPI.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bungee; - - -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; -import com.djrapitops.plugin.api.Check; -import com.djrapitops.plugin.utilities.Verify; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public class PostOriginalBukkitSettingsWebAPI extends WebAPI { - - @Override - public Response onRequest(IPlan plugin, Map variables) { - if (Check.isBukkitAvailable()) { - return badRequest("Called a Bukkit Server"); - } - Map settings = new HashMap<>(); - - String webServerPortS = variables.get("WebServerPort"); - String serverName = variables.get("ServerName"); - String themeBase = variables.get("ThemeBase"); - if (!Verify.notNull(webServerPortS, serverName, themeBase)) { - return badRequest("Not all variables were set"); - } - - int webServerPort = Integer.parseInt(webServerPortS); - settings.put("WebServerPort", webServerPort); - settings.put("ServerName", serverName); - settings.put("ThemeBase", themeBase); - Settings.serverSpecific().addOriginalBukkitSettings((PlanBungee) plugin, UUID.fromString(variables.get("sender")), settings); - return success(); - } - - @Override - public void sendRequest(String address) throws WebAPIException { - addVariable("WebServerPort", Integer.toString(Settings.WEBSERVER_PORT.getNumber())); - addVariable("ServerName", Settings.SERVER_NAME.toString().replaceAll("[^a-zA-Z0-9_\\s]", "_")); - addVariable("ThemeBase", Settings.THEME_BASE.toString()); - super.sendRequest(address); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/RequestPluginsTabWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/RequestPluginsTabWebAPI.java deleted file mode 100644 index dd6adaf36..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/RequestPluginsTabWebAPI.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bungee; - - -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.systems.info.server.ServerInfo; -import com.djrapitops.plan.systems.processing.Processor; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; -import com.djrapitops.plan.systems.webserver.webapi.bukkit.RequestInspectPluginsTabBukkitWebAPI; -import com.djrapitops.plugin.api.Check; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.sql.SQLException; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -/** - * WebAPI for requesting Bungee Server to request Plugins tab contents from every server. - *

    - * Call: Bukkit to Bungee - *

    - * Bad Requests: - * - Called a Bukkit Server - * - Did not include uuid variable - * - * @author Rsl1122 - */ -public class RequestPluginsTabWebAPI extends WebAPI { - @Override - public Response onRequest(IPlan plugin, Map variables) { - if (!Check.isBungeeAvailable()) { - return badRequest("Called a Bukkit Server"); - } - - String uuidS = variables.get("uuid"); - if (uuidS == null) { - return badRequest("UUID not included"); - } - UUID uuid = UUID.fromString(uuidS); - - sendRequestsToBukkitServers(plugin, uuid); - return success(); - } - - @Override - public void sendRequest(String address) throws WebAPIException { - throw new IllegalStateException("Wrong method call for this WebAPI, call sendRequest(String, UUID, UUID) instead."); - } - - public void sendRequest(String address, UUID uuid) throws WebAPIException { - addVariable("uuid", uuid.toString()); - super.sendRequest(address); - } - - public void sendRequestsToBukkitServers(IPlan plugin, UUID uuid) { - plugin.addToProcessQueue(new Processor(uuid) { - @Override - public void process() { - try { - List bukkitServers = plugin.getDB().getServerTable().getBukkitServers(); - for (ServerInfo server : bukkitServers) { - String webAddress = server.getWebAddress(); - try { - plugin.getWebServer().getWebAPI().getAPI(RequestInspectPluginsTabBukkitWebAPI.class).sendRequest(webAddress, uuid); - } catch (WebAPIException ignore) { - /* ignored */ - } - } - } catch (SQLException e) { - Log.toLog(this.getClass().getName(), e); - } - } - }); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/RequestSetupWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/RequestSetupWebAPI.java deleted file mode 100644 index 6e05413ba..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/bungee/RequestSetupWebAPI.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.bungee; - - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.systems.info.server.ServerInfo; -import com.djrapitops.plan.systems.webserver.response.ForbiddenResponse; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; -import com.djrapitops.plugin.api.Check; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.utilities.Verify; - -import java.util.Map; -import java.util.UUID; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public class RequestSetupWebAPI extends WebAPI { - - @Override - public Response onRequest(IPlan plugin, Map variables) { - if (!Check.isBungeeAvailable()) { - return badRequest("Called a Bukkit server."); - } - - if (!((PlanBungee) plugin).isSetupAllowed()) { - return new ForbiddenResponse("Setup mode disabled, use /planbungee setup to enable"); - } - - String serverUUIDS = variables.get("sender"); - String webAddress = variables.get("webAddress"); - String accessCode = variables.get("accessKey"); - if (!Verify.notNull(serverUUIDS, webAddress, accessCode)) { - return badRequest("Variable was null"); - } - ServerInfo serverInfo = new ServerInfo(-1, UUID.fromString(serverUUIDS), "", webAddress, 0); - - ((PlanBungee) plugin).getServerInfoManager().attemptConnection(serverInfo, accessCode); - return success(); - } - - @Override - public void sendRequest(String address) throws WebAPIException { - if (!Check.isBukkitAvailable()) { - throw new IllegalStateException("Not supposed to be called on Bungee"); - } - - Plan plugin = Plan.getInstance(); - try { - addVariable("accessKey", plugin.getWebServer().getWebAPI().generateNewAccessKey()); - } catch (Exception e) { - Log.toLog(this.getClass().getName(), e); - } - addVariable("webAddress", plugin.getWebServer().getAccessAddress()); - super.sendRequest(address); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/universal/PingWebAPI.java b/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/universal/PingWebAPI.java deleted file mode 100644 index 9717887dd..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/systems/webserver/webapi/universal/PingWebAPI.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.systems.webserver.webapi.universal; - - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.api.exceptions.WebAPIException; -import com.djrapitops.plan.systems.info.BukkitInformationManager; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.systems.webserver.webapi.WebAPI; -import com.djrapitops.plan.utilities.MiscUtils; -import com.djrapitops.plugin.api.Check; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.io.IOException; -import java.util.Map; -import java.util.UUID; - -/** - * @author Rsl1122 - */ -public class PingWebAPI extends WebAPI { - @Override - public Response onRequest(IPlan plugin, Map variables) { - if (Check.isBungeeAvailable()) { - if (!((PlanBungee) plugin).getServerInfoManager().serverConnected(UUID.fromString(variables.get("sender")))) { - return fail("Server info not found from the database"); - } - } else if (!plugin.getInfoManager().isUsingAnotherWebServer()) { - try { - String webAddress = variables.get("webAddress"); - if (webAddress != null) { - ((Plan) plugin).getServerInfoManager().saveBungeeConnectionAddress(webAddress); - } - - ((BukkitInformationManager) plugin.getInfoManager()).updateConnection(); - } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); - } - } - return success(); - } - - @Override - public void sendRequest(String address) throws WebAPIException { - if (Check.isBukkitAvailable()) { - super.sendRequest(address); - } else { - addVariable("webAddress", PlanBungee.getInstance().getWebServer().getAccessAddress()); - super.sendRequest(address); - } - } - - public void sendRequest(String address, String accessCode) throws WebAPIException { - addVariable("accessKey", accessCode); - addVariable("version", MiscUtils.getIPlan().getVersion()); - sendRequest(address); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/Base64Util.java b/Plan/src/main/java/com/djrapitops/plan/utilities/Base64Util.java new file mode 100644 index 000000000..64d15d04b --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/Base64Util.java @@ -0,0 +1,32 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.utilities; + +import java.util.Base64; + +/** + * Utility for performing Base64 operations. + * + * @author Rsl1122 + */ +public class Base64Util { + + /** + * Hides public constructor. + */ + private Base64Util() { + } + + public static String encode(String decoded) { + byte[] encoded = Base64.getEncoder().encode(decoded.getBytes()); + return new String(encoded); + } + + public static String decode(String encoded) { + byte[] decoded = Base64.getDecoder().decode(encoded.getBytes()); + return new String(decoded); + } + +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/FormatUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/FormatUtils.java index a53f38463..d63beb564 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/FormatUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/FormatUtils.java @@ -1,11 +1,16 @@ package com.djrapitops.plan.utilities; -import com.djrapitops.plan.settings.Settings; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.utilities.Format; import org.apache.commons.lang3.StringUtils; import org.bukkit.Location; import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; /** * @author Rsl1122 @@ -42,16 +47,64 @@ public class FormatUtils { return formatMilliseconds(Math.abs(after - before)); } - public static String formatTimeStamp(long epochMs) { - return com.djrapitops.plugin.utilities.FormatUtils.formatTimeStamp(epochMs); + public static String formatTimeStampDay(long epochMs) { + String format = "MMMMM d"; + + if (Settings.FORMAT_DATE_RECENT_DAYS.isTrue()) { + format = replaceRecentDays(epochMs, format, "MMMMM"); + } + + return format(epochMs, format); + } + + public static String formatTimeStampClock(long epochMs) { + String format = Settings.FORMAT_DATE_CLOCK.toString(); + + return format(epochMs, format); + } + + private static String format(long epochMs, String format) { + String locale = Settings.LOCALE.toString(); + Locale usedLocale = locale.equalsIgnoreCase("default") ? Locale.ENGLISH : Locale.forLanguageTag(locale); + SimpleDateFormat dateFormat = new SimpleDateFormat(format, usedLocale); + return dateFormat.format(epochMs); } public static String formatTimeStampSecond(long epochMs) { - return com.djrapitops.plugin.utilities.FormatUtils.formatTimeStampSecond(epochMs); + String format = Settings.FORMAT_DATE_FULL.toString(); + + if (Settings.FORMAT_DATE_RECENT_DAYS.isTrue()) { + format = replaceRecentDays(epochMs, format); + } + + return format(epochMs, format); + } + + private static String replaceRecentDays(long epochMs, String format) { + return replaceRecentDays(epochMs, format, Settings.FORMAT_DATE_RECENT_DAYS_PATTERN.toString()); + } + + private static String replaceRecentDays(long epochMs, String format, String pattern) { + long now = MiscUtils.getTime(); + + long fromStartOfDay = now % TimeAmount.DAY.ms(); + if (epochMs > now - fromStartOfDay) { + format = format.replace(pattern, "'Today'"); + } else if (epochMs > now - TimeAmount.DAY.ms() - fromStartOfDay) { + format = format.replace(pattern, "'Yesterday'"); + } else if (epochMs > now - TimeAmount.DAY.ms() * 5L) { + format = format.replace(pattern, "EEEE"); + } + return format; } public static String formatTimeStampYear(long epochMs) { - return com.djrapitops.plugin.utilities.FormatUtils.formatTimeStampYear(epochMs); + String format = Settings.FORMAT_DATE_NO_SECONDS.toString(); + + if (Settings.FORMAT_DATE_RECENT_DAYS.isTrue()) { + format = replaceRecentDays(epochMs, format); + } + return format(epochMs, format); } /** @@ -212,20 +265,6 @@ public class FormatUtils { return df.format(d); } - public static String[] readableActivityIndex(double activityIndex) { - if (activityIndex >= 3.5) { - return new String[]{"green", "Very Active"}; - } else if (activityIndex >= 1.75) { - return new String[]{"green", "Active"}; - } else if (activityIndex >= 1.0) { - return new String[]{"lime", "Regular"}; - } else if (activityIndex >= 0.5) { - return new String[]{"amber", "Irregular"}; - } else { - return new String[]{"blue-gray", "Inactive"}; - } - } - public static String formatIP(String ip) { StringBuilder b = new StringBuilder(); int i = 0; @@ -241,4 +280,29 @@ public class FormatUtils { return b.append("xx").toString(); } + + /** + * Gets lines for stack trace recursively. + * + * @param throwable Throwable element + * @return lines of stack trace. + */ + public static List getStackTrace(Throwable throwable) { + List stackTrace = new ArrayList<>(); + stackTrace.add(throwable.toString()); + for (StackTraceElement element : throwable.getStackTrace()) { + stackTrace.add(" " + element.toString()); + } + + Throwable cause = throwable.getCause(); + if (cause != null) { + List causeTrace = getStackTrace(cause); + if (!causeTrace.isEmpty()) { + causeTrace.set(0, "Caused by: " + causeTrace.get(0)); + stackTrace.addAll(causeTrace); + } + } + + return stackTrace; + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/ManageUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/ManageUtils.java index 6877ce531..ce6b6923c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/ManageUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/ManageUtils.java @@ -1,11 +1,11 @@ package com.djrapitops.plan.utilities; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.DatabaseInitException; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.database.databases.SQLiteDB; -import com.djrapitops.plan.database.tables.move.BatchOperationTable; -import com.djrapitops.plan.systems.file.database.DBSystem; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.SQLiteDB; +import com.djrapitops.plan.system.database.databases.sql.tables.move.BatchOperationTable; import com.djrapitops.plugin.api.utility.log.Log; import java.sql.SQLException; @@ -29,8 +29,7 @@ public class ManageUtils { * @param dbName Name of database (mysql/sqlite) * @param copyFromDB Database you want to backup. */ - public static void backup(String dbName, Database copyFromDB) throws DatabaseInitException, SQLException { - Plan plugin = Plan.getInstance(); + public static void backup(String dbName, Database copyFromDB) throws DBInitException, SQLException { String timeStamp = new Date().toString().substring(4, 10).replace(" ", "-"); String fileName = dbName + "-backup-" + timeStamp; SQLiteDB backupDB = new SQLiteDB(fileName); @@ -52,9 +51,9 @@ public class ManageUtils { public static Collection getUUIDS(Database db) { final Set uuids = new HashSet<>(); try { - uuids.addAll(db.getSavedUUIDs()); - } catch (SQLException e) { - Log.toLog("ManageUtils.getUUIDS", e); + uuids.addAll(db.fetch().getSavedUUIDs()); + } catch (DBException e) { + Log.toLog(ManageUtils.class, e); } return uuids; } @@ -67,15 +66,10 @@ public class ManageUtils { * @param copyFromDB Database where data will be copied from */ public static void clearAndCopy(Database clearAndCopyToDB, Database copyFromDB) throws SQLException { - BatchOperationTable toDB = new BatchOperationTable(clearAndCopyToDB); - BatchOperationTable fromDB = new BatchOperationTable(copyFromDB); + BatchOperationTable toDB = new BatchOperationTable((SQLDB) clearAndCopyToDB); + BatchOperationTable fromDB = new BatchOperationTable((SQLDB) copyFromDB); toDB.removeAllData(); fromDB.copyEverything(toDB); } - - @Deprecated - public static Database getDB(String dbName) throws DatabaseInitException { - return DBSystem.getActiveDatabase(dbName); - } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/MiscUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/MiscUtils.java index d96406674..722d24b52 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/MiscUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/MiscUtils.java @@ -2,12 +2,12 @@ package com.djrapitops.plan.utilities; import com.djrapitops.plan.Plan; import com.djrapitops.plan.PlanBungee; -import com.djrapitops.plan.api.IPlan; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Permissions; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.settings.Permissions; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plugin.api.Check; import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.api.utility.log.Log; @@ -16,7 +16,6 @@ import com.djrapitops.plugin.command.ISender; import java.io.Closeable; import java.io.IOException; -import java.sql.SQLException; import java.util.*; import java.util.stream.Collectors; @@ -96,19 +95,19 @@ public class MiscUtils { * @return Alphabetically sorted list of matching player names. */ public static List getMatchingPlayerNames(String search) { - Database db = getIPlan().getDB(); + Database db = Database.getActive(); List matches; try { - matches = db.getUsersTable().getMatchingNames(search); - } catch (SQLException e) { - Log.toLog("MiscUtils.getMatchingPlayerNames", e); + matches = db.search().matchingPlayers(search); + } catch (DBException e) { + Log.toLog(MiscUtils.class, e); return new ArrayList<>(); } Collections.sort(matches); return matches; } - public static List flatMap(Collection> coll) { + public static List flatMap(Collection> coll) { return coll.stream().flatMap(Collection::stream).collect(Collectors.toList()); } @@ -117,8 +116,11 @@ public class MiscUtils { if (c != null) { try { c.close(); - } catch (IOException ignored) { - /* Ignored */ + } catch (IOException e) { + if (Settings.DEV_MODE.isTrue()) { + Log.warn("THIS ERROR IS ONLY LOGGED IN DEV MODE:"); + Log.toLog(MiscUtils.class, e); + } } } } @@ -129,8 +131,11 @@ public class MiscUtils { if (c != null) { try { c.close(); - } catch (Exception ignored) { - /* Ignored */ + } catch (Exception e) { + if (Settings.DEV_MODE.isTrue()) { + Log.warn("THIS ERROR IS ONLY LOGGED IN DEV MODE:"); + Log.toLog(MiscUtils.class, e); + } } } } @@ -143,12 +148,4 @@ public class MiscUtils { return PlanBungee.getInstance().getDescription().getVersion(); } } - - public static IPlan getIPlan() { - if (Check.isBukkitAvailable()) { - return Plan.getInstance(); - } else { - return PlanBungee.getInstance(); - } - } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java b/Plan/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java index 1bab17985..fa5115f27 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java @@ -1,5 +1,7 @@ package com.djrapitops.plan.utilities; +import com.djrapitops.plan.api.exceptions.PassEncryptException; + import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.xml.bind.DatatypeConverter; @@ -167,7 +169,7 @@ public class PassEncryptUtil { } @SuppressWarnings("serial") - public static class InvalidHashException extends Exception { + public static class InvalidHashException extends PassEncryptException { InvalidHashException(String message) { super(message); @@ -179,7 +181,7 @@ public class PassEncryptUtil { } @SuppressWarnings("serial") - public static class CannotPerformOperationException extends Exception { + public static class CannotPerformOperationException extends PassEncryptException { CannotPerformOperationException() { super("Unsupported hash type."); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Analysis.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Analysis.java index fcc1b951b..0df7dc81f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Analysis.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Analysis.java @@ -1,29 +1,26 @@ package com.djrapitops.plan.utilities.analysis; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.data.AnalysisData; +import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.data.PlayerProfile; import com.djrapitops.plan.data.ServerProfile; +import com.djrapitops.plan.data.calculation.AnalysisData; import com.djrapitops.plan.data.element.AnalysisContainer; import com.djrapitops.plan.data.plugin.BanData; +import com.djrapitops.plan.data.plugin.HookHandler; import com.djrapitops.plan.data.plugin.PluginData; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.cache.SessionCache; -import com.djrapitops.plan.systems.info.BukkitInformationManager; -import com.djrapitops.plan.systems.info.InformationManager; -import com.djrapitops.plan.systems.tasks.PlanTaskSystem; -import com.djrapitops.plan.systems.tasks.TaskSystem; -import com.djrapitops.plan.systems.webserver.response.ErrorResponse; -import com.djrapitops.plan.systems.webserver.response.InternalErrorResponse; +import com.djrapitops.plan.system.cache.DataCache; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.locale.Locale; +import com.djrapitops.plan.system.settings.locale.Msg; +import com.djrapitops.plan.system.tasks.BukkitTaskSystem; +import com.djrapitops.plan.system.tasks.TaskSystem; +import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.StaticHolder; import com.djrapitops.plugin.api.Benchmark; import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.task.AbsRunnable; -import com.djrapitops.plugin.task.RunnableFactory; import java.util.*; import java.util.stream.Collectors; @@ -33,134 +30,61 @@ import java.util.stream.Collectors; */ public class Analysis { - private final Plan plugin; - private int taskId = -1; + private static Long refreshDate; + private final UUID serverUUID; + private final Database database; + private static ServerProfile serverProfile; + private final DataCache dataCache; + private boolean analysingThisServer; - /** - * Class Constructor. - * - * @param plugin Current instance of Plan - */ - public Analysis(Plan plugin) { - this.plugin = plugin; + private Analysis(UUID serverUUID, Database database, DataCache dataCache) { + this.serverUUID = serverUUID; + analysingThisServer = ServerInfo.getServerUUID().equals(serverUUID); + this.database = database; + this.dataCache = dataCache; + } + + public static Optional getRefreshDate() { + return Optional.ofNullable(refreshDate); + } + + public static AnalysisData runAnalysisFor(UUID serverUUID, Database database, DataCache dataCache) throws Exception { + return new Analysis(serverUUID, database, dataCache).runAnalysis(); } /** - * Analyzes the data of all offline players on the server. + * Only available during Analysis. * - * @param infoManager InformationManager of the plugin. + * @return ServerProfile being analyzed or null if analysis is not being run. */ - public void runAnalysis(InformationManager infoManager) { - if (isAnalysisBeingRun()) { - return; - } + public static ServerProfile getServerProfile() { + return serverProfile; + } - ((PlanTaskSystem) TaskSystem.getInstance()).cancelBootAnalysis(); + private AnalysisData runAnalysis() throws Exception { + ((BukkitTaskSystem) TaskSystem.getInstance()).cancelBootAnalysis(); - Benchmark.start("Analysis"); + Benchmark.start("Analysis: Total"); log(Locale.get(Msg.ANALYSIS_START).toString()); - // Async task for Analysis - RunnableFactory.createNew(new AbsRunnable("AnalysisTask") { - @Override - public void run() { - try { - ErrorResponse analysisRefreshPage = new ErrorResponse(); - analysisRefreshPage.setTitle("Analysis is being refreshed.."); - analysisRefreshPage.setParagraph(" Analysis is being run, refresh the page after a few seconds.. (F5)"); - analysisRefreshPage.replacePlaceholders(); - ((BukkitInformationManager) plugin.getInfoManager()).cacheAnalysisHtml(analysisRefreshPage.getContent()); - taskId = this.getTaskId(); - analyze(infoManager, plugin.getDB()); - } catch (Exception e) { - Log.toLog(this.getClass().getName() + ":" + this.getTaskName(), e); - } finally { - taskId = -1; - this.cancel(); - } - - } - }).runTaskAsynchronously(); + return analyze(); } - /** - * Caches analyzed data of db to the provided cache analysisCache. - * - * @param infoManager InformationManager of the plugin. - * method. - * @param db Database which data will be analyzed. - * @return Whether or not analysis was successful. - */ - public boolean analyze(InformationManager infoManager, Database db) { - log(Locale.get(Msg.ANALYSIS_FETCH).toString()); - Benchmark.start("Fetch Phase"); - Log.logDebug("Database", "Analysis Fetch"); - Log.logDebug("Analysis", "Analysis Fetch Phase"); - - - return analyzeData(infoManager, db); + private static void updateRefreshDate() { + Analysis.refreshDate = MiscUtils.getTime(); } - /** - * Analyze data in the db about this server. - * - * @param infoManager InformationManager of the plugin. - * @return Success? - */ - public boolean analyzeData(InformationManager infoManager, Database db) { - try { - Benchmark.start("Create Empty dataset"); - - AnalysisData analysisData = new AnalysisData(); - - Benchmark.stop("Analysis", "Create Empty dataset"); - Benchmark.start("Fetch Phase"); - ServerProfile profile = db.getServerProfile(Plan.getServerUUID()); - DataCache dataCache = plugin.getDataCache(); - profile.addActiveSessions(new HashMap<>(SessionCache.getActiveSessions())); - serverProfile = profile; - - updatePlayerNameCache(profile, dataCache); - - long fetchPhaseLength = Benchmark.stop("Analysis", "Fetch Phase"); - setBannedByPlugins(profile); - - Benchmark.start("Analysis Phase"); - Log.logDebug("Analysis", "Analysis Phase"); - - log(Locale.get(Msg.ANALYSIS_PHASE_START).parse(profile.getPlayerCount(), fetchPhaseLength)); - - analysisData.analyze(profile); - - Benchmark.stop("Analysis", "Analysis Phase"); - - log(Locale.get(Msg.ANALYSIS_3RD_PARTY).toString()); - Log.logDebug("Analysis", "Analyzing additional data sources (3rd party)"); - analysisData.parsePluginsSection(analyzeAdditionalPluginData(profile.getUuids())); - ((BukkitInformationManager) infoManager).cacheAnalysisData(analysisData); - } catch (Exception e) { - Log.toLog(this.getClass().getName(), e); - ((BukkitInformationManager) plugin.getInfoManager()).cacheAnalysisHtml(new InternalErrorResponse(e, "Analysis").getContent()); - Log.logDebug("Analysis", "Error: " + e); - return false; - } finally { - long time = Benchmark.stop("Analysis", "Analysis"); - Log.logDebug("Analysis"); - Log.info(Locale.get(Msg.ANALYSIS_FINISHED).parse(time, "")); - serverProfile = null; - } - return true; - } - - private void updatePlayerNameCache(ServerProfile profile, DataCache dataCache) { + private void updatePlayerNameCache(ServerProfile profile) { for (PlayerProfile player : profile.getPlayers()) { dataCache.updateNames(player.getUuid(), player.getName(), null); } } private void setBannedByPlugins(ServerProfile profile) { - UUID serverUUID = Plan.getServerUUID(); - List banPlugins = plugin.getHookHandler().getAdditionalDataSources().stream() + if (!analysingThisServer) { + return; + } + List banPlugins = HookHandler.getInstance().getAdditionalDataSources().stream() .filter(p -> p instanceof BanData) .map(p -> (BanData) p) .collect(Collectors.toList()); @@ -186,16 +110,20 @@ public class Analysis { } private Map analyzeAdditionalPluginData(Set uuids) { + if (!analysingThisServer) { + return new HashMap<>(); + } Map containers = new HashMap<>(); - Benchmark.start("Analysis", "3rd party Analysis"); - List sources = plugin.getHookHandler().getAdditionalDataSources(); + Benchmark.start("Analysis", "Analysis: 3rd party"); + List sources = HookHandler.getInstance().getAdditionalDataSources(); Log.logDebug("Analysis", "Additional Sources: " + sources.size()); sources.parallelStream().forEach(source -> { + PlanPlugin plugin = PlanPlugin.getInstance(); StaticHolder.saveInstance(this.getClass(), plugin.getClass()); try { - Benchmark.start("Analysis", "Source " + source.getSourcePlugin()); + Benchmark.start("Analysis", "Analysis: Source " + source.getSourcePlugin()); AnalysisContainer container = source.getServerData(uuids, new AnalysisContainer()); if (container != null && !container.isEmpty()) { @@ -204,30 +132,60 @@ public class Analysis { } catch (Exception | NoClassDefFoundError | NoSuchFieldError | NoSuchMethodError e) { Log.error("A PluginData-source caused an exception: " + source.getSourcePlugin()); - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } finally { - Benchmark.stop("Analysis", "Source " + source.getSourcePlugin()); + Benchmark.stop("Analysis", "Analysis: Source " + source.getSourcePlugin()); } }); - Benchmark.stop("Analysis", "3rd party Analysis"); + Benchmark.stop("Analysis", "Analysis: 3rd party"); return containers; } - /** - * Condition whether or not analysis is being run. - * - * @return true / false (state) - */ - public boolean isAnalysisBeingRun() { - return taskId != -1; + public static boolean isAnalysisBeingRun() { + return serverProfile != null; } - /** - * Only available during Analysis. - * - * @return ServerProfile being analyzed or null if analysis is not being run. - */ - public static ServerProfile getServerProfile() { - return serverProfile; + private static void setServerProfile(ServerProfile serverProfile) { + Analysis.serverProfile = serverProfile; + } + + private AnalysisData analyze() throws Exception { + log(Locale.get(Msg.ANALYSIS_FETCH).toString()); + Log.logDebug("Analysis", "Analysis Fetch Phase"); + Benchmark.start("Analysis", "Analysis: Fetch Phase"); + try { + AnalysisData analysisData = new AnalysisData(); + + ServerProfile server = database.fetch().getServerProfile(serverUUID); + if (analysingThisServer) { + server.addActiveSessions(new HashMap<>(SessionCache.getActiveSessions())); + } + Analysis.setServerProfile(server); + + updatePlayerNameCache(server); + + long fetchPhaseLength = Benchmark.stop("Analysis", "Analysis: Fetch Phase"); + setBannedByPlugins(server); + + Benchmark.start("Analysis", "Analysis: Data Analysis"); + Log.logDebug("Analysis", "Analysis Phase"); + + log(Locale.get(Msg.ANALYSIS_PHASE_START).parse(server.getPlayerCount(), fetchPhaseLength)); + + analysisData.analyze(server); + + Benchmark.stop("Analysis", "Analysis: Data Analysis"); + + log(Locale.get(Msg.ANALYSIS_3RD_PARTY).toString()); + Log.logDebug("Analysis", "Analyzing additional data sources (3rd party)"); + analysisData.parsePluginsSection(analyzeAdditionalPluginData(server.getUuids())); + return analysisData; + } finally { + Analysis.updateRefreshDate(); + long time = Benchmark.stop("Analysis", "Analysis: Total"); + Log.logDebug("Analysis"); + Log.info(Locale.get(Msg.ANALYSIS_FINISHED).parse(time, "")); + Analysis.setServerProfile(null); + } } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java index e6a36458d..368f09872 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java @@ -1,17 +1,11 @@ package com.djrapitops.plan.utilities.analysis; -import com.djrapitops.plan.api.IPlan; import com.djrapitops.plan.data.PlayerProfile; +import com.djrapitops.plan.data.calculation.ActivityIndex; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.container.StickyData; -import com.djrapitops.plan.data.time.GMTimes; -import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.utilities.FormatUtils; -import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.api.TimeAmount; -import com.djrapitops.plugin.api.utility.log.Log; -import java.sql.SQLException; import java.util.*; import java.util.stream.Collectors; @@ -39,6 +33,22 @@ public class AnalysisUtils { return newPlayers; } + public static int getUniquePlayers(Map> sessions, long after) { + Set uuids = new HashSet<>(); + + for (Map.Entry> entry : sessions.entrySet()) { + UUID uuid = entry.getKey(); + for (Session session : entry.getValue()) { + if (session.getSessionStart() >= after) { + uuids.add(uuid); + break; + } + } + } + + return uuids.size(); + } + public static int getUniqueJoinsPerDay(Map> sessions, long after) { Map> uniqueJoins = new HashMap<>(); @@ -123,7 +133,7 @@ public class AnalysisUtils { } public static double getAveragePerDay(long after, long before, long total) { - return total / getNumberOfDaysBetween(after, before); + return (double) total / getNumberOfDaysBetween(after, before); } public static long getNumberOfDaysBetween(long start, long end) { @@ -134,23 +144,7 @@ public class AnalysisUtils { test += day; value++; } - return value; - } - - public static void addMissingWorlds(WorldTimes worldTimes) { - try { - // Add 0 time for worlds not present. - Set nonZeroWorlds = worldTimes.getWorldTimes().keySet(); - IPlan plugin = MiscUtils.getIPlan(); - for (String world : plugin.getDB().getWorldTable().getWorldNames(plugin.getServerUuid())) { - if (nonZeroWorlds.contains(world)) { - continue; - } - worldTimes.setGMTimesForWorld(world, new GMTimes()); - } - } catch (SQLException e) { - Log.toLog("AnalysisUtils.addMissingWorlds", e); - } + return value == 0 ? 1 : value; } public static Map> sortSessionsByUser(Map>> allSessions) { @@ -197,7 +191,7 @@ public class AnalysisUtils { stickM++; } } - probability *= (stickM / similarM.size()); + probability *= ((double) stickM / similarM.size()); } if (!similarW.isEmpty()) { @@ -208,7 +202,7 @@ public class AnalysisUtils { } } - probability *= (stickW / similarW.size()); + probability *= ((double) stickW / similarW.size()); } return probability; @@ -219,13 +213,13 @@ public class AnalysisUtils { if (!players.isEmpty()) { for (PlayerProfile player : players) { for (long date = time; date >= time - TimeAmount.MONTH.ms() * 2L; date -= TimeAmount.WEEK.ms()) { - double activityIndex = player.getActivityIndex(date); - String index = FormatUtils.readableActivityIndex(activityIndex)[1]; + ActivityIndex activityIndex = player.getActivityIndex(date); + String activityGroup = activityIndex.getGroup(); Map> map = activityData.getOrDefault(date, new HashMap<>()); - Set uuids = map.getOrDefault(index, new HashSet<>()); + Set uuids = map.getOrDefault(activityGroup, new HashSet<>()); uuids.add(player.getUuid()); - map.put(index, uuids); + map.put(activityGroup, uuids); activityData.put(date, map); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/MathUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/MathUtils.java index f1969c196..5078a1433 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/MathUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/MathUtils.java @@ -3,7 +3,9 @@ package com.djrapitops.plan.utilities.analysis; import java.io.Serializable; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; -import java.util.*; +import java.util.Collection; +import java.util.Locale; +import java.util.OptionalDouble; import java.util.stream.Stream; /** @@ -153,34 +155,6 @@ public class MathUtils { .sum(); } - /** - * Gets the biggest Integer in a Collection with Integer as Entry - * If the Collection is empty, it will return 1. - * - * @param values The Collection with Integer as the Entry - * @return The biggest Integer - * @see #getBiggestLong(Collection) - */ - public static int getBiggest(Collection values) { - OptionalInt biggest = values.stream().mapToInt(i -> i).max(); - - return biggest.isPresent() ? biggest.getAsInt() : 1; - } - - /** - * Gets the biggest Long in a Collection with Long as Entry - * If the Collection is empty, it will return 1. - * - * @param values The Collection with Long as the Entry - * @return The biggest Integer - * @see #getBiggest(Collection) - */ - public static long getBiggestLong(Collection values) { - OptionalLong biggest = values.stream().mapToLong(i -> i).max(); - - return biggest.isPresent() ? biggest.getAsLong() : 1; - } - /** * Rounds the double to a double with two digits at the end. * Output: #.## diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/HasDateComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/HasDateComparator.java deleted file mode 100644 index b7afe27c5..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/HasDateComparator.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.utilities.comparators; - -import com.djrapitops.plan.data.HasDate; - -import java.util.Comparator; - -/** - * Comparator for HasDate interface Objects. - * - * @author Rsl1122 - */ -public class HasDateComparator implements Comparator { - - private final boolean reversed; - - public HasDateComparator() { - this(false); - } - - public HasDateComparator(boolean reversed) { - this.reversed = reversed; - } - - @Override - public int compare(HasDate o1, HasDate o2) { - return (reversed ? -1 : 1) * Long.compare(o1.getDate(), o2.getDate()); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/LocaleEntryComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/LocaleEntryComparator.java index c9614867c..eb16cf4e0 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/LocaleEntryComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/LocaleEntryComparator.java @@ -1,7 +1,7 @@ package com.djrapitops.plan.utilities.comparators; -import com.djrapitops.plan.settings.locale.Message; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.settings.locale.Message; +import com.djrapitops.plan.system.settings.locale.Msg; import java.util.Comparator; import java.util.Map; diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/MapComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/MapComparator.java index 129de42f2..b537e44ce 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/MapComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/MapComparator.java @@ -31,18 +31,4 @@ public class MapComparator { return sortedList; } - /** - * Sorts a Map of String, Long by the Values of the Map. - * - * @param map Map to sort - * @return List with String Array, where first value is the value and second - * is the key. - */ - public static List sortByValueLong(Map map) { - List sortedList = new ArrayList<>(); - map.keySet().forEach(key -> sortedList.add(new String[]{String.valueOf(map.get(key)), key})); - sortedList.sort(Comparator.comparing(strings -> Long.valueOf(strings[0]))); - return sortedList; - } - } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PieSliceComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PieSliceComparator.java index 1be438a05..2ac257394 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PieSliceComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PieSliceComparator.java @@ -1,4 +1,4 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ @@ -9,7 +9,9 @@ import com.djrapitops.plan.utilities.html.graphs.pie.PieSlice; import java.util.Comparator; /** - * Compares PieSlices to descending Percentage order. + * Comparator for PieSlices to descending Percentage order. + * + * @author Rsl1122 */ public class PieSliceComparator implements Comparator { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/KillDataComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PlayerKillComparator.java similarity index 81% rename from Plan/src/main/java/com/djrapitops/plan/utilities/comparators/KillDataComparator.java rename to Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PlayerKillComparator.java index 6ed0c3101..4b5b4c316 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/KillDataComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PlayerKillComparator.java @@ -7,7 +7,7 @@ import java.util.Comparator; /** * @author Fuzzlemann */ -public class KillDataComparator implements Comparator { +public class PlayerKillComparator implements Comparator { @Override public int compare(PlayerKill o1, PlayerKill o2) { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PluginDataNameComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PluginDataNameComparator.java index 519640e9a..16ebaf43b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PluginDataNameComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PluginDataNameComparator.java @@ -10,7 +10,7 @@ import com.djrapitops.plan.data.plugin.PluginData; import java.util.Comparator; /** - * Comparator for UserInfo for Alphabetical Name order. + * Comparator for PluginData for Alphabetical Name order. * * @author Rsl1122 */ diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PointComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PointComparator.java index b26a12adc..61859e8fc 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PointComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/PointComparator.java @@ -5,11 +5,13 @@ */ package com.djrapitops.plan.utilities.comparators; -import com.djrapitops.plan.utilities.analysis.Point; +import com.djrapitops.plan.utilities.html.graphs.line.Point; import java.util.Comparator; /** + * Comparator for Points for ascending x value order. + * * @author Rsl1122 * @since 3.5.2 */ diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionLengthComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionLengthComparator.java index d1c90df18..04e8478ad 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionLengthComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionLengthComparator.java @@ -5,6 +5,8 @@ import com.djrapitops.plan.data.container.Session; import java.util.Comparator; /** + * Comparator for Sessions in descending length order. + * * @author Rsl1122 */ public class SessionLengthComparator implements Comparator { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionStartComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionStartComparator.java index f783df30b..14056d10b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionStartComparator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/SessionStartComparator.java @@ -5,6 +5,8 @@ import com.djrapitops.plan.data.container.Session; import java.util.Comparator; /** + * Comparator for Sessions in descending start order (Latest first). + * * @author Rsl1122 */ public class SessionStartComparator implements Comparator { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/file/FileUtil.java b/Plan/src/main/java/com/djrapitops/plan/utilities/file/FileUtil.java index f45d67eeb..dfb176f5c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/file/FileUtil.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/file/FileUtil.java @@ -1,6 +1,6 @@ package com.djrapitops.plan.utilities.file; -import com.djrapitops.plan.api.IPlan; +import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.utilities.Verify; @@ -24,14 +24,14 @@ public class FileUtil { public static String getStringFromResource(String fileName) throws IOException { StringBuilder html = new StringBuilder(); - IPlan plugin = MiscUtils.getIPlan(); + PlanPlugin plugin = PlanPlugin.getInstance(); - lines(MiscUtils.getIPlan(), new File(plugin.getDataFolder(), fileName.replace("/", File.separator)), fileName) + lines(PlanPlugin.getInstance(), new File(plugin.getDataFolder(), fileName.replace("/", File.separator)), fileName) .forEach(line -> html.append(line).append("\r\n")); return html.toString(); } - public static List lines(IPlan plugin, File savedFile, String defaults) throws IOException { + public static List lines(PlanPlugin plugin, File savedFile, String defaults) throws IOException { if (savedFile.exists()) { return lines(savedFile); } else { @@ -72,7 +72,7 @@ public class FileUtil { return null; } - public static List lines(IPlan plugin, String resource) throws IOException { + public static List lines(PlanPlugin plugin, String resource) throws IOException { List lines = new ArrayList<>(); Scanner scanner = null; try (InputStream inputStream = plugin.getResource(resource)) { @@ -81,7 +81,7 @@ public class FileUtil { lines.add(scanner.nextLine()); } } catch (NullPointerException e) { - Log.infoColor("§ea Resource was not found inside the jar, Plan does not support /reload or updates using " + + Log.infoColor("§ea Resource was not found inside the jar (" + resource + "), Plan does not support /reload or updates using " + "Plugin Managers, restart the server and see if the error persists."); throw new FileNotFoundException("File not found inside jar: " + resource); } finally { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/AnalysisExport.java b/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/AnalysisExport.java index 896efa2cd..d61cae6e1 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/AnalysisExport.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/AnalysisExport.java @@ -4,6 +4,8 @@ */ package com.djrapitops.plan.utilities.file.export; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plugin.api.Check; import com.djrapitops.plugin.api.utility.log.Log; import java.io.IOException; @@ -11,7 +13,7 @@ import java.util.ConcurrentModificationException; import java.util.UUID; /** - * Task that exports a single Analysis page if it is in PageCache. + * Task that exports a single Analysis page if it is in ResponseCache. * * @author Rsl1122 */ @@ -29,9 +31,13 @@ public class AnalysisExport extends SpecificExport { @Override public void run() { try { + if (Check.isBukkitAvailable() && ConnectionSystem.getInstance().isServerAvailable()) { + return; + } + exportAvailableServerPage(serverUUID, serverName); } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } finally { try { this.cancel(); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/HtmlExport.java b/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/HtmlExport.java index 5d171327e..d9563ec0b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/HtmlExport.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/HtmlExport.java @@ -4,19 +4,22 @@ */ package com.djrapitops.plan.utilities.file.export; -import com.djrapitops.plan.api.IPlan; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.api.exceptions.database.DBException; import com.djrapitops.plan.data.container.UserInfo; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.settings.theme.ThemeVal; -import com.djrapitops.plan.systems.webserver.response.PlayersPageResponse; -import com.djrapitops.plan.systems.webserver.webapi.bungee.PostHtmlWebAPI; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.ThemeVal; +import com.djrapitops.plan.system.webserver.response.pages.PlayersPageResponse; import com.djrapitops.plan.utilities.file.FileUtil; +import com.djrapitops.plugin.api.Check; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.task.RunnableFactory; import java.io.File; import java.io.IOException; -import java.sql.SQLException; +import java.nio.file.Files; import java.util.*; /** @@ -26,38 +29,37 @@ import java.util.*; */ public class HtmlExport extends SpecificExport { - private final IPlan plugin; + private final PlanPlugin plugin; - public HtmlExport(IPlan plugin) { + public HtmlExport(PlanPlugin plugin) { super("HtmlExportTask"); this.plugin = plugin; } - public static void exportServer(IPlan plugin, UUID serverUUID) { + public static void exportServer(UUID serverUUID) { try { - Optional serverName = plugin.getDB().getServerTable().getServerName(serverUUID); + Optional serverName = Database.getActive().fetch().getServerName(serverUUID); serverName.ifPresent(s -> RunnableFactory.createNew(new AnalysisExport(serverUUID, s)).runTaskAsynchronously()); - } catch (SQLException e) { - Log.toLog(PostHtmlWebAPI.class.getClass().getName(), e); + } catch (DBException e) { + Log.toLog(HtmlExport.class.getClass().getName(), e); } } - public static void exportPlayer(IPlan plugin, UUID playerUUID) { + public static void exportPlayer(UUID playerUUID) { try { - String playerName = plugin.getDB().getUsersTable().getPlayerName(playerUUID); + String playerName = Database.getActive().fetch().getPlayerName(playerUUID); if (playerName != null) { RunnableFactory.createNew(new PlayerExport(playerUUID, playerName)).runTaskAsynchronously(); } - } catch (SQLException e) { - Log.toLog(PostHtmlWebAPI.class.getClass().getName(), e); + } catch (DBException e) { + Log.toLog(HtmlExport.class.getClass().getName(), e); } } @Override public void run() { try { - boolean usingAnotherWebServer = plugin.getInfoManager().isUsingAnotherWebServer(); - if (usingAnotherWebServer) { + if (Check.isBukkitAvailable() && ConnectionSystem.getInstance().isServerAvailable()) { return; } @@ -68,8 +70,8 @@ public class HtmlExport extends SpecificExport { exportAvailableServerPages(); exportAvailablePlayers(); exportPlayersPage(); - } catch (IOException | SQLException e) { - Log.toLog(this.getClass().getName(), e); + } catch (IOException | DBException e) { + Log.toLog(this.getClass(), e); } finally { try { this.cancel(); @@ -94,14 +96,14 @@ public class HtmlExport extends SpecificExport { export(exportFile, lines); } - private void exportAvailablePlayers() throws SQLException, IOException { - for (Map.Entry entry : plugin.getDB().getUsersTable().getUsers().entrySet()) { + private void exportAvailablePlayers() throws DBException, IOException { + for (Map.Entry entry : Database.getActive().fetch().getUsers().entrySet()) { exportAvailablePlayerPage(entry.getKey(), entry.getValue().getName()); } } - private void exportAvailableServerPages() throws SQLException, IOException { - Map serverNames = plugin.getDB().getServerTable().getServerNames(); + private void exportAvailableServerPages() throws IOException, DBException { + Map serverNames = Database.getActive().fetch().getServerNames(); for (Map.Entry entry : serverNames.entrySet()) { exportAvailableServerPage(entry.getKey(), entry.getValue()); @@ -115,7 +117,7 @@ public class HtmlExport extends SpecificExport { "web/css/style.css", "web/css/themes/all-themes.css" }; - copyFromJar(resources, true); + copyFromJar(resources); } private void exportJs() { @@ -124,7 +126,7 @@ public class HtmlExport extends SpecificExport { "web/js/helpers.js", "web/js/script.js", "web/js/charts/activityPie.js", - "web/js/charts/activityStackGraph.js", + "web/js/charts/stackGraph.js", "web/js/charts/performanceGraph.js", "web/js/charts/playerGraph.js", "web/js/charts/playerGraphNoNav.js", @@ -137,7 +139,7 @@ public class HtmlExport extends SpecificExport { "web/js/charts/worldPie.js", "web/js/charts/healthGauge.js" }; - copyFromJar(resources, false); + copyFromJar(resources); try { String demo = FileUtil.getStringFromResource("web/js/demo.js") @@ -147,12 +149,13 @@ public class HtmlExport extends SpecificExport { outputFolder.mkdirs(); export(new File(outputFolder, "demo.js"), lines); } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } } private void exportPlugins() { String[] resources = new String[]{ + "web/plugins/font-awesome/fa-script.js", "web/plugins/bootstrap/css/bootstrap.css", "web/plugins/node-waves/waves.css", "web/plugins/node-waves/waves.js", @@ -163,29 +166,30 @@ public class HtmlExport extends SpecificExport { "web/plugins/jquery-datatable/skin/bootstrap/js/dataTables.bootstrap.js", "web/plugins/jquery-datatable/jquery.dataTables.js" }; - copyFromJar(resources, true); + copyFromJar(resources); } - - private void copyFromJar(String[] resources, boolean overwrite) { + private void copyFromJar(String[] resources) { for (String resource : resources) { try { - copyFromJar(resource, overwrite); + copyFromJar(resource); } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } } } - private void copyFromJar(String resource, boolean overwrite) throws IOException { + private void copyFromJar(String resource) throws IOException { String possibleFile = resource.replace("web/", "").replace("/", File.separator); List lines = FileUtil.lines(plugin, new File(plugin.getDataFolder(), possibleFile), resource); String outputFile = possibleFile.replace("web/", ""); File to = new File(outputFolder, outputFile); to.getParentFile().mkdirs(); if (to.exists()) { - to.delete(); - to.createNewFile(); + Files.delete(to.toPath()); + if (to.createNewFile()) { + return; + } } export(to, lines); } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/PlayerExport.java b/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/PlayerExport.java index 3d9a50fcc..7224c3552 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/PlayerExport.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/PlayerExport.java @@ -4,6 +4,8 @@ */ package com.djrapitops.plan.utilities.file.export; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plugin.api.Check; import com.djrapitops.plugin.api.utility.log.Log; import java.io.IOException; @@ -29,9 +31,13 @@ public class PlayerExport extends SpecificExport { @Override public void run() { try { + if (Check.isBukkitAvailable() && ConnectionSystem.getInstance().isServerAvailable()) { + return; + } + exportAvailablePlayerPage(uuid, name); } catch (IOException e) { - Log.toLog(this.getClass().getName(), e); + Log.toLog(this.getClass(), e); } finally { try { this.cancel(); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/SpecificExport.java b/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/SpecificExport.java index 212f94786..389d76db2 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/SpecificExport.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/file/export/SpecificExport.java @@ -4,11 +4,12 @@ */ package com.djrapitops.plan.utilities.file.export; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.webserver.pagecache.PageCache; -import com.djrapitops.plan.systems.webserver.pagecache.PageId; -import com.djrapitops.plan.systems.webserver.response.Response; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.cache.PageId; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; import com.djrapitops.plugin.api.Check; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.task.AbsRunnable; @@ -51,7 +52,7 @@ public abstract class SpecificExport extends AbsRunnable { } return folder; } - File dataFolder = MiscUtils.getIPlan().getDataFolder(); + File dataFolder = PlanPlugin.getInstance().getDataFolder(); File folder = new File(dataFolder, path); folder.mkdirs(); return folder; @@ -74,7 +75,7 @@ public abstract class SpecificExport extends AbsRunnable { } protected void exportAvailablePlayerPage(UUID uuid, String name) throws IOException { - Response response = PageCache.loadPage(PageId.PLAYER.of(uuid)); + Response response = ResponseCache.loadResponse(PageId.PLAYER.of(uuid)); if (response == null) { return; } @@ -91,7 +92,7 @@ public abstract class SpecificExport extends AbsRunnable { protected void exportAvailableServerPage(UUID serverUUID, String serverName) throws IOException { - Response response = PageCache.loadPage(PageId.SERVER.of(serverUUID)); + Response response = ResponseCache.loadResponse(PageId.SERVER.of(serverUUID)); if (response == null) { return; } @@ -102,9 +103,9 @@ public abstract class SpecificExport extends AbsRunnable { .replace("src=\"plugins/", "src=\"../plugins/") .replace("src=\"js/", "src=\"../js/"); - File htmlLocation = null; + File htmlLocation; if (usingBungee) { - if (serverUUID.equals(MiscUtils.getIPlan().getServerUuid())) { + if (serverUUID.equals(ServerInfo.getServerUUID())) { htmlLocation = new File(outputFolder, "network"); } else { htmlLocation = new File(getServerFolder(), serverName.replace(" ", "%20").replace(".", "%2E")); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/Html.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/Html.java index fe6a68183..72b01ed68 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/Html.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/Html.java @@ -51,10 +51,16 @@ public enum Html { DIV_W_CLASS_STYLE("

    ${2}
    "), // ROW("
    ${0}
    "), + CARD("
    ${0}
    "), + BODY("
    ${0}
    "), + PANEL("
    ${0}
    "), + PANEL_BODY("
    ${0}
    "), + // TABLE_END(""), TABLE(""), TABLE_SCROLL("
    "), + TABLE_JQUERY("
    "), TABLE_COLORED("
    "), TABLE_HEAD("${0}"), TABLE_BODY("${0}"), diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/HtmlStructure.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/HtmlStructure.java index ca66fc41f..3a504e3bb 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/HtmlStructure.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/HtmlStructure.java @@ -1,23 +1,24 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan.utilities.html; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.ServerVariableHolder; +import com.djrapitops.plan.api.exceptions.database.DBException; import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.systems.info.BukkitInformationManager; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.info.server.ServerProperties; +import com.djrapitops.plan.system.settings.Settings; import com.djrapitops.plan.utilities.FormatUtils; -import com.djrapitops.plan.utilities.html.graphs.line.PlayerActivityGraph; +import com.djrapitops.plan.utilities.analysis.Analysis; +import com.djrapitops.plan.utilities.html.graphs.line.OnlineActivityGraph; import com.djrapitops.plan.utilities.html.structure.SessionTabStructureCreator; import com.djrapitops.plan.utilities.html.tables.SessionsTableCreator; import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.utilities.Verify; -import java.sql.SQLException; import java.util.*; /** @@ -106,27 +107,29 @@ public class HtmlStructure { return b.toString(); } - public static String createServerContainer(Plan plugin) { - ServerVariableHolder variable = plugin.getVariable(); - int maxPlayers = variable.getMaxPlayers(); - int online = plugin.getServer().getOnlinePlayers().size(); - Optional analysisRefreshDate = ((BukkitInformationManager) plugin.getInfoManager()).getAnalysisRefreshDate(); - String refresh = analysisRefreshDate.map(FormatUtils::formatTimeStamp).orElse("-"); + public static String createServerContainer() { + ServerProperties properties = ServerInfo.getServerProperties(); + int maxPlayers = properties.getMaxPlayers(); + int online = properties.getOnlinePlayers(); + Optional analysisRefreshDate = Analysis.getRefreshDate(); + String refresh = analysisRefreshDate.map(FormatUtils::formatTimeStampClock).orElse("-"); - String serverName = plugin.getServerInfoManager().getServerName(); - String serverType = variable.getVersion(); + Server server = ServerInfo.getServer(); + + String serverName = server.getName(); + String serverType = properties.getVersion(); String address = "../server/" + serverName; - - Database db = plugin.getDB(); - UUID serverUUID = plugin.getServerUuid(); + Database db = Database.getActive(); + UUID serverUUID = server.getUuid(); String id = serverUUID.toString().replace("-", ""); - int playerCount = db.getUserInfoTable().getServerUserCount(serverUUID); + int playerCount = 0; String playerData = "[]"; try { - playerData = PlayerActivityGraph.createSeries(db.getTpsTable().getTPSData(serverUUID)); - } catch (SQLException e) { + playerCount = db.count().getServerPlayerCount(serverUUID); + playerData = new OnlineActivityGraph(db.fetch().getTPSData(serverUUID)).toHighChartsSeries(); + } catch (DBException e) { Log.toLog(HtmlStructure.class.getClass().getName(), e); } @@ -175,15 +178,6 @@ public class HtmlStructure { "})"; } - public static String parseOfflineServerContainer(String oldContent) { - if (oldContent == null) { - return ""; - } - String[] split = oldContent.split("

    ", 2); - String[] split2 = split[1].split("box-footer", 2); - return split[0] + "

    Offline

    banned, boolean op) { boolean offline = "offline".equalsIgnoreCase(online); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/HtmlUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/HtmlUtils.java index 1f21d0e25..9112bef4a 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/HtmlUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/HtmlUtils.java @@ -1,13 +1,11 @@ package com.djrapitops.plan.utilities.html; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.settings.Settings; import org.apache.commons.lang3.text.StrSubstitutor; import java.io.Serializable; import java.util.Map; -import java.util.UUID; /** * @author Rsl1122 @@ -45,23 +43,11 @@ public class HtmlUtils { if (Settings.SHOW_ALTERNATIVE_IP.isTrue()) { ip = Settings.ALTERNATIVE_IP.toString().replace("%port%", String.valueOf(port)); } else { - ip = MiscUtils.getIPlan().getVariable().getIp() + ":" + port; + ip = ServerInfo.getServerProperties().getIp() + ":" + port; } return ip; } - public static String getProtocol() { - return MiscUtils.getIPlan().getWebServer().getProtocol(); - } - - public static String getRelativeInspectUrl(String playerName) { - return "../player/" + playerName.replace(" ", "%20").replace(".", "%2E"); - } - - public static String getRelativeInspectUrl(UUID uuid) { - return Plan.getPlanAPI().getPlayerInspectPageLink(Plan.getInstance().getDataCache().getName(uuid)); - } - /** * Attempts to remove XSS components. * @@ -94,17 +80,4 @@ public class HtmlUtils { return string.replace("§r", "").replace("§l", "").replace("§m", "").replace("§n", "").replace("§o", "").replace("§k", ""); } - - public static String separateWithQuotes(String... strings) { - StringBuilder build = new StringBuilder(); - for (int i = 0; i < strings.length; i++) { - build.append("\""); - build.append(strings[i]); - build.append("\""); - if (i < strings.length - 1) { - build.append(", "); - } - } - return build.toString(); - } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/ActivityStackGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/ActivityStackGraph.java index d1d8f7d53..70b43d280 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/ActivityStackGraph.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/ActivityStackGraph.java @@ -1,74 +1,56 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan.utilities.html.graphs; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.settings.theme.ThemeVal; +import com.djrapitops.plan.data.calculation.ActivityIndex; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.ThemeVal; import com.djrapitops.plan.utilities.FormatUtils; -import com.djrapitops.plan.utilities.html.graphs.pie.ActivityPie; +import com.djrapitops.plan.utilities.html.graphs.stack.AbstractStackGraph; +import com.djrapitops.plan.utilities.html.graphs.stack.StackDataSet; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.UUID; +import java.util.*; /** - * //TODO Class Javadoc Comment + * Stack Graph that represents evolution of the PlayerBase in terms of ActivityIndex Groups. * * @author Rsl1122 + * @see ActivityIndex + * @since 4.2.0 */ -public class ActivityStackGraph { +public class ActivityStackGraph extends AbstractStackGraph { - private ActivityStackGraph() { - throw new IllegalStateException("Utility Class"); + public ActivityStackGraph(TreeMap>> activityData) { + super(getLabels(activityData.navigableKeySet()), getDataSets(activityData)); } - public static String[] createSeries(TreeMap>> activityData) { - String[] sliceNames = ActivityPie.getSliceNames(); + private static String[] getLabels(NavigableSet dates) { + return dates.stream() + .map(FormatUtils::formatTimeStampDay) + .toArray(String[]::new); + } + + private static StackDataSet[] getDataSets(TreeMap>> activityData) { + String[] groups = ActivityIndex.getGroups(); String[] colors = Theme.getValue(ThemeVal.GRAPH_ACTIVITY_PIE).split(", "); int maxCol = colors.length; + StackDataSet[] dataSets = new StackDataSet[groups.length]; - StringBuilder[] series = new StringBuilder[sliceNames.length + 1]; - for (int i = 0; i <= sliceNames.length; i++) { - series[i] = new StringBuilder(); - } - for (int i = 1; i <= sliceNames.length; i++) { - series[i] = new StringBuilder("{name: '") - .append(sliceNames[i - 1]) - .append("',color:").append(colors[(i - 1) % maxCol]) - .append(",data: ["); + for (int i = 0; i < groups.length; i++) { + dataSets[i] = new StackDataSet(new ArrayList<>(), groups[i], colors[(i) % maxCol]); } - int size = activityData.size(); - int i = 0; for (Long date : activityData.navigableKeySet()) { Map> data = activityData.get(date); - series[0].append("'").append(FormatUtils.formatTimeStamp(date)).append("'"); - for (int j = 1; j <= sliceNames.length; j++) { - Set players = data.get(sliceNames[j - 1]); - series[j].append(players != null ? players.size() : 0); - } - - if (i < size - 1) { - for (int j = 0; j <= sliceNames.length; j++) { - series[j].append(","); - } - } - i++; - } - - StringBuilder seriesBuilder = new StringBuilder("["); - - for (int j = 1; j <= sliceNames.length; j++) { - seriesBuilder.append(series[j].append("]}").toString()); - if (j < sliceNames.length) { - seriesBuilder.append(","); + for (int j = 0; j < groups.length; j++) { + Set players = data.get(groups[j]); + dataSets[j].add((double) (players != null ? players.size() : 0)); } } - return new String[]{series[0].toString(), seriesBuilder.append("]").toString()}; + return dataSets; } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/HighChart.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/HighChart.java new file mode 100644 index 000000000..39e444dd5 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/HighChart.java @@ -0,0 +1,16 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.utilities.html.graphs; + +/** + * Interface for Graphs with HighCharts data support. + * + * @author Rsl1122 + */ +public interface HighChart { + + String toHighChartsSeries(); + +} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/PunchCardGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/PunchCardGraph.java index 6e4db9c7a..567a9f4bf 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/PunchCardGraph.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/PunchCardGraph.java @@ -14,27 +14,26 @@ import java.util.Objects; import java.util.stream.Collectors; /** - * Utility class for creating Punch Card Data Array for the JavaScripts. + * Bubble Chart that represents login "punches" of players. * * @author Rsl1122 - * @since 3.6.0 + * @since 4.2.0 */ -public class PunchCardGraph { +public class PunchCardGraph implements HighChart { + + private final Collection sessions; /** - * Constructor used to hide the public constructor + * Constuctor for the graph. + * + * @param sessions All sessions of All users this PunchCard represents. */ - private PunchCardGraph() { - throw new IllegalStateException("Utility class"); + public PunchCardGraph(Collection sessions) { + this.sessions = sessions; } - /** - * Creates a PunchCard series data Array for HighCharts - * - * @param sessions Sessions (Unique/Player) to be placed into the PunchCard. - * @return Data array as a string. - */ - public static String createSeries(Collection sessions) { + @Override + public String toHighChartsSeries() { List sessionStarts = getSessionStarts(sessions); List daysAndHours = AnalysisUtils.getDaysAndHours(sessionStarts); int[][] dataArray = turnIntoArray(daysAndHours); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/WorldMap.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/WorldMap.java index a14849409..9330a6001 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/WorldMap.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/WorldMap.java @@ -4,57 +4,24 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -public class WorldMap { +/** + * World Map that uses iso-a3 specification of Country codes. + * + * @author Rsl1122 + * @since 4.2.0 + */ +public class WorldMap implements HighChart { - /** - * Constructor used to hide the public constructor - */ - private WorldMap() { - throw new IllegalStateException("Utility class"); - } + private final List geoLocations; - /** - * Creates a data series with iso-a3 specification of Country codes. - * - * @param geoLocations The country names of players - * @return The created data series - */ - public static String createSeries(List geoLocations) { - - Map geoCodeCounts = new HashMap<>(); - Map geoCodes = getGeoCodes(geoCodeCounts); - - for (String geoLocation : geoLocations) { - String countryCode = geoCodes.get(geoLocation); - if (countryCode != null) { - geoCodeCounts.computeIfPresent(countryCode, (computedCountry, amount) -> amount + 1); - } - } - - StringBuilder arrayBuilder = new StringBuilder("["); - - int i = 0; - int size = geoCodeCounts.size(); - for (Map.Entry entry : geoCodeCounts.entrySet()) { - String geoCode = entry.getKey(); - Integer players = entry.getValue(); - - if (players != 0) { - arrayBuilder.append("{'code':'").append(geoCode).append("','value':").append(players).append("}"); - if (i < size - 1) { - arrayBuilder.append(","); - } - } - - i++; - } - - arrayBuilder.append("]"); - return arrayBuilder.toString(); + public WorldMap(List geoLocations) { + this.geoLocations = geoLocations; } private static Map getGeoCodes(Map geoCodeCounts) { Map geoCodes = new HashMap<>(); + // Countries & Codes have been copied from a iso-a3 specification file. + // Each index corresponds to each code. String[] countries = new String[]{"Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antigua and Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas, The", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Brazil", "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burma", "Burundi", "Cabo Verde", "Cambodia", "Cameroon", "Canada", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", "Colombia", "Comoros", "Congo, Democratic Republic of the", "Congo, Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", "Curacao", "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Islas Malvinas)", "Faroe Islands", "Fiji", "Finland", "France", "French Polynesia", "Gabon", "Gambia, The", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guam", "Guatemala", "Guernsey", "Guinea-Bissau", "Guinea", "Guyana", "Haiti", "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Korea, North", "Korea, South", "Kosovo", "Kuwait", "Kyrgyzstan", "Laos", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macau", "Macedonia", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", "Micronesia, Federated States of", "Moldova", "Monaco", "Mongolia", "Montenegro", "Morocco", "Mozambique", "Namibia", "Nepal", "Netherlands", "New Caledonia", "New Zealand", "Nicaragua", "Nigeria", "Niger", "Niue", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Puerto Rico", "Qatar", "Romania", "Russia", "Rwanda", "Saint Kitts and Nevis", "Saint Lucia", "Saint Martin", "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Sint Maarten", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Sudan", "Spain", "Sri Lanka", "Sudan", "Suriname", "Swaziland", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Timor-Leste", "Togo", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "Virgin Islands", "West Bank", "Yemen", "Zambia", "Zimbabwe"}; String[] codes = new String[]{"AFG", "ALB", "DZA", "ASM", "AND", "AGO", "AIA", "ATG", "ARG", "ARM", "ABW", "AUS", "AUT", "AZE", "BHM", "BHR", "BGD", "BRB", "BLR", "BEL", "BLZ", "BEN", "BMU", "BTN", "BOL", "BIH", "BWA", "BRA", "VGB", "BRN", "BGR", "BFA", "MMR", "BDI", "CPV", "KHM", "CMR", "CAN", "CYM", "CAF", "TCD", "CHL", "CHN", "COL", "COM", "COD", "COG", "COK", "CRI", "CIV", "HRV", "CUB", "CUW", "CYP", "CZE", "DNK", "DJI", "DMA", "DOM", "ECU", "EGY", "SLV", "GNQ", "ERI", "EST", "ETH", "FLK", "FRO", "FJI", "FIN", "FRA", "PYF", "GAB", "GMB", "GEO", "DEU", "GHA", "GIB", "GRC", "GRL", "GRD", "GUM", "GTM", "GGY", "GNB", "GIN", "GUY", "HTI", "HND", "HKG", "HUN", "ISL", "IND", "IDN", "IRN", "IRQ", "IRL", "IMN", "ISR", "ITA", "JAM", "JPN", "JEY", "JOR", "KAZ", "KEN", "KIR", "KOR", "PRK", "KSV", "KWT", "KGZ", "LAO", "LVA", "LBN", "LSO", "LBR", "LBY", "LIE", "LTU", "LUX", "MAC", "MKD", "MDG", "MWI", "MYS", "MDV", "MLI", "MLT", "MHL", "MRT", "MUS", "MEX", "FSM", "MDA", "MCO", "MNG", "MNE", "MAR", "MOZ", "NAM", "NPL", "NLD", "NCL", "NZL", "NIC", "NGA", "NER", "NIU", "MNP", "NOR", "OMN", "PAK", "PLW", "PAN", "PNG", "PRY", "PER", "PHL", "POL", "PRT", "PRI", "QAT", "ROU", "RUS", "RWA", "KNA", "LCA", "MAF", "SPM", "VCT", "WSM", "SMR", "STP", "SAU", "SEN", "SRB", "SYC", "SLE", "SGP", "SXM", "SVK", "SVN", "SLB", "SOM", "ZAF", "SSD", "ESP", "LKA", "SDN", "SUR", "SWZ", "SWE", "CHE", "SYR", "TWN", "TJK", "TZA", "THA", "TLS", "TGO", "TON", "TTO", "TUN", "TUR", "TKM", "TUV", "UGA", "UKR", "ARE", "GBR", "USA", "URY", "UZB", "VUT", "VEN", "VNM", "VGB", "WBG", "YEM", "ZMB", "ZWE"}; for (int i = 0; i < countries.length; i++) { @@ -66,4 +33,38 @@ public class WorldMap { } return geoCodes; } + + @Override + public String toHighChartsSeries() { + Map geoCodeCounts = new HashMap<>(); + Map geoCodes = getGeoCodes(geoCodeCounts); + + for (String geoLocation : geoLocations) { + String countryCode = geoCodes.get(geoLocation); + if (countryCode != null) { + geoCodeCounts.computeIfPresent(countryCode, (computedCountry, amount) -> amount + 1); + } + } + + StringBuilder dataBuilder = new StringBuilder("["); + + int i = 0; + int size = geoCodeCounts.size(); + for (Map.Entry entry : geoCodeCounts.entrySet()) { + String geoCode = entry.getKey(); + Integer players = entry.getValue(); + + if (players != 0) { + dataBuilder.append("{'code':'").append(geoCode).append("','value':").append(players).append("}"); + if (i < size - 1) { + dataBuilder.append(","); + } + } + + i++; + } + + dataBuilder.append("]"); + return dataBuilder.toString(); + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/AbstractLineGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/AbstractLineGraph.java new file mode 100644 index 000000000..aa559fea8 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/AbstractLineGraph.java @@ -0,0 +1,77 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.djrapitops.plan.utilities.html.graphs.line; + +import com.djrapitops.plan.utilities.html.graphs.HighChart; +import com.djrapitops.plan.utilities.html.graphs.line.alg.DouglasPeuckerAlgorithm; +import com.djrapitops.plan.utilities.html.graphs.line.alg.ReduceGapTriangles; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This is a LineGraph for any set of Points, thus it is Abstract. + * + * @author Rsl1122 + * @since 4.2.0 + */ +public class AbstractLineGraph implements HighChart { + + protected List points; + protected boolean reduceGapTriangles = false; + protected boolean reducePoints = false; + + public AbstractLineGraph() { + points = new ArrayList<>(); + } + + public AbstractLineGraph(List points) { + this.points = points; + } + + @Override + public String toHighChartsSeries() { + StringBuilder arrayBuilder = new StringBuilder("["); + + if (reducePoints) { + points = DouglasPeuckerAlgorithm.reducePoints(points, 0); + } + if (reduceGapTriangles) { + points = ReduceGapTriangles.reduce(points); + } + + int size = points.size(); + for (int i = 0; i < size; i++) { + Point point = points.get(i); + double y = point.getY(); + long date = (long) point.getX(); + arrayBuilder.append("[").append(date).append(",").append(y).append("]"); + if (i < size - 1) { + arrayBuilder.append(","); + } + } + + arrayBuilder.append("]"); + return arrayBuilder.toString(); + } + + public void reduceGapTriangles() { + this.reduceGapTriangles = true; + } + + public void reducePoints() { + this.reducePoints = true; + } + + public void setPoints(List points) { + this.points = points; + } + + public void addPoints(Collection points) { + this.points.addAll(points); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/CPUGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/CPUGraph.java index 49a9d40c6..20e3df7a4 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/CPUGraph.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/CPUGraph.java @@ -1,24 +1,26 @@ package com.djrapitops.plan.utilities.html.graphs.line; import com.djrapitops.plan.data.container.TPS; -import com.djrapitops.plan.utilities.analysis.Point; import java.util.List; import java.util.stream.Collectors; -public class CPUGraph { +/** + * Graph about CPU Usage gathered by TPSCountTimer. + * + * @author Rsl1122 + * @see com.djrapitops.plan.system.tasks.TPSCountTimer + * @since 4.2.0 + */ +public class CPUGraph extends AbstractLineGraph { - /** - * Constructor used to hide the public constructor - */ - private CPUGraph() { - throw new IllegalStateException("Utility class"); + public CPUGraph(List tpsData) { + super(transformToPoints(tpsData)); } - public static String createSeries(List tpsData) { - List points = tpsData.stream() + private static List transformToPoints(List tpsData) { + return tpsData.stream() .map(tps -> new Point(tps.getDate(), tps.getCPUUsage())) .collect(Collectors.toList()); - return LineSeries.createSeries(points, true); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/ChunkGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/ChunkGraph.java new file mode 100644 index 000000000..58acb3916 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/ChunkGraph.java @@ -0,0 +1,26 @@ +package com.djrapitops.plan.utilities.html.graphs.line; + +import com.djrapitops.plan.data.container.TPS; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Graph about Chunk Counts gathered by TPSCountTimer. + * + * @author Rsl1122 + * @see com.djrapitops.plan.system.tasks.TPSCountTimer + * @since 4.2.0 + */ +public class ChunkGraph extends AbstractLineGraph { + + public ChunkGraph(List tpsData) { + super(turnToPoints(tpsData)); + } + + private static List turnToPoints(List tpsData) { + return tpsData.stream() + .map(tps -> new Point(tps.getDate(), tps.getChunksLoaded())) + .collect(Collectors.toList()); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/EntityGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/EntityGraph.java new file mode 100644 index 000000000..c89ed361a --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/EntityGraph.java @@ -0,0 +1,26 @@ +package com.djrapitops.plan.utilities.html.graphs.line; + +import com.djrapitops.plan.data.container.TPS; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Graph about Entity Counts gathered by TPSCountTimer. + * + * @author Rsl1122 + * @see com.djrapitops.plan.system.tasks.TPSCountTimer + * @since 4.2.0 + */ +public class EntityGraph extends AbstractLineGraph { + + public EntityGraph(List tpsData) { + super(turnToPoints(tpsData)); + } + + private static List turnToPoints(List tpsData) { + return tpsData.stream() + .map(tps -> new Point(tps.getDate(), tps.getEntityCount())) + .collect(Collectors.toList()); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Line.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/Line.java similarity index 85% rename from Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Line.java rename to Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/Line.java index f857d32d7..f26655b38 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Line.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/Line.java @@ -3,10 +3,14 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.djrapitops.plan.utilities.analysis; +package com.djrapitops.plan.utilities.html.graphs.line; /** - * @author ristolah + * This math object is used in Ramer–Douglas–Peucker algorithm. + * + * https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm + * + * @author Rsl1122 */ public class Line { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/LineSeries.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/LineSeries.java deleted file mode 100644 index 932a3938b..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/LineSeries.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.djrapitops.plan.utilities.html.graphs.line; - -import com.djrapitops.plan.utilities.analysis.Point; - -import java.util.List; - -/** - * Abstract scatter graph creator used by other graph creators. - * - * @author Rsl1122 - * @since 3.5.2 - */ -public class LineSeries { - - /** - * Constructor used to hide the public constructor - */ - private LineSeries() { - throw new IllegalStateException("Utility class"); - } - - public static String createSeries(List points, boolean reduceGapTriangles) { - return createSeries(points, reduceGapTriangles, true); - } - - public static String createSeries(List points, boolean reduceGapTriangles, boolean reducePoints) { - StringBuilder arrayBuilder = new StringBuilder("["); - -// if (reducePoints) { -// points = DouglasPeuckerAlgorithm.reducePoints(points, 0); -// } -// -// if (reduceGapTriangles) { -// points = ReduceGapTriangles.reduce(points); -// } - - int size = points.size(); - for (int i = 0; i < size; i++) { - Point point = points.get(i); - double y = point.getY(); - long date = (long) point.getX(); - arrayBuilder.append("[").append(date).append(",").append(y).append("]"); - if (i < size - 1) { - arrayBuilder.append(","); - } - } - - arrayBuilder.append("]"); - return arrayBuilder.toString(); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/OnlineActivityGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/OnlineActivityGraph.java new file mode 100644 index 000000000..04c4b2493 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/OnlineActivityGraph.java @@ -0,0 +1,26 @@ +package com.djrapitops.plan.utilities.html.graphs.line; + +import com.djrapitops.plan.data.container.TPS; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Graph about Player Counts gathered by TPSCountTimer. + * + * @author Rsl1122 + * @see com.djrapitops.plan.system.tasks.TPSCountTimer + * @since 4.2.0 + */ +public class OnlineActivityGraph extends AbstractLineGraph { + + public OnlineActivityGraph(List tpsData) { + super(turnToPoints(tpsData)); + } + + private static List turnToPoints(List tpsData) { + return tpsData.stream() + .map(tps -> new Point(tps.getDate(), tps.getPlayers())) + .collect(Collectors.toList()); + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/PlayerActivityGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/PlayerActivityGraph.java deleted file mode 100644 index 0398fde9d..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/PlayerActivityGraph.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.djrapitops.plan.utilities.html.graphs.line; - -import com.djrapitops.plan.data.container.TPS; -import com.djrapitops.plan.utilities.analysis.Point; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * @author Rsl1122 - */ -public class PlayerActivityGraph { - - /** - * Constructor used to hide the public constructor - */ - private PlayerActivityGraph() { - throw new IllegalStateException("Utility class"); - } - - public static String createSeries(List tpsData) { - List points = tpsData.stream() - .map(tps -> new Point(tps.getDate(), tps.getPlayers())) - .collect(Collectors.toList()); - return LineSeries.createSeries(points, true); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Point.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/Point.java similarity index 76% rename from Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Point.java rename to Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/Point.java index cf74bf1fe..9b7a8d475 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/Point.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/Point.java @@ -1,6 +1,4 @@ -package com.djrapitops.plan.utilities.analysis; - -import org.apache.commons.lang3.builder.ToStringBuilder; +package com.djrapitops.plan.utilities.html.graphs.line; import java.util.Objects; @@ -41,9 +39,8 @@ public class Point { @Override public String toString() { - return new ToStringBuilder(this) - .append("x", x) - .append("y", y) - .toString(); + return "Point{" + + "x=" + x + ", " + + "y=" + y + '}'; } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/RamGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/RamGraph.java index 71340d85e..1208132fd 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/RamGraph.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/RamGraph.java @@ -1,38 +1,26 @@ package com.djrapitops.plan.utilities.html.graphs.line; import com.djrapitops.plan.data.container.TPS; -import com.djrapitops.plan.systems.tasks.TPSCountTimer; -import com.djrapitops.plan.utilities.analysis.Point; import java.util.List; import java.util.stream.Collectors; /** - * Class for creating scatter graph data from RAM Usage snapshots with TPS task. + * Graph about RAM Usage gathered by TPSCountTimer. * * @author Rsl1122 - * @see TPSCountTimer - * @since 3.6.0 + * @see com.djrapitops.plan.system.tasks.TPSCountTimer + * @since 4.2.0 */ -public class RamGraph { +public class RamGraph extends AbstractLineGraph { - /** - * Constructor used to hide the public constructor - */ - private RamGraph() { - throw new IllegalStateException("Utility class"); + public RamGraph(List tpsData) { + super(turnToPoints(tpsData)); } - /** - * Creates a series data string from given data. - * - * @param tpsData TPS Data collected by TPSCountTimer, one data point for each minute. - * @return Series data for HighCharts - */ - public static String createSeries(List tpsData) { - List points = tpsData.stream() + private static List turnToPoints(List tpsData) { + return tpsData.stream() .map(tps -> new Point(tps.getDate(), tps.getUsedMemory())) .collect(Collectors.toList()); - return LineSeries.createSeries(points, true); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/ServerPreferencePie.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/ServerPreferencePie.java deleted file mode 100644 index 0d985a944..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/ServerPreferencePie.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.djrapitops.plan.utilities.html.graphs.line; - -import com.djrapitops.plan.data.time.WorldTimes; - -import java.util.Map; -import java.util.UUID; - -public class ServerPreferencePie { - - private ServerPreferencePie() { - throw new IllegalStateException("Utility Class"); - } - - public static String createSeries(Map serverNames, Map serverWorldTimes) { - StringBuilder seriesBuilder = new StringBuilder("["); - int i = 0; - int size = serverWorldTimes.size(); - for (Map.Entry server : serverWorldTimes.entrySet()) { - String serverName = serverNames.getOrDefault(server.getKey(), "Unknown"); - seriesBuilder.append("{name:'").append(serverName) - .append("',y:").append(server.getValue().getTotal()); - - seriesBuilder.append("}"); - if (i < size - 1) { - seriesBuilder.append(","); - } - i++; - } - seriesBuilder.append("]"); - - return seriesBuilder.toString(); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/TPSGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/TPSGraph.java index 7bf6c63ae..6c77555be 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/TPSGraph.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/TPSGraph.java @@ -1,29 +1,26 @@ package com.djrapitops.plan.utilities.html.graphs.line; import com.djrapitops.plan.data.container.TPS; -import com.djrapitops.plan.utilities.analysis.Point; import java.util.List; import java.util.stream.Collectors; /** + * Graph about TPS gathered by TPSCountTimer. + * * @author Rsl1122 - * @since 3.5.0 + * @see com.djrapitops.plan.system.tasks.TPSCountTimer + * @since 4.2.0 */ -public class TPSGraph { +public class TPSGraph extends AbstractLineGraph { - /** - * Constructor used to hide the public constructor - */ - private TPSGraph() { - throw new IllegalStateException("Utility class"); + public TPSGraph(List tpsData) { + super(turnToPoints(tpsData)); } - public static String createSeries(List tpsData) { - List points = tpsData.stream() + private static List turnToPoints(List tpsData) { + return tpsData.stream() .map(tps -> new Point(tps.getDate(), tps.getTicksPerSecond())) .collect(Collectors.toList()); - return LineSeries.createSeries(points, true); - } } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/WorldLoadGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/WorldLoadGraph.java deleted file mode 100644 index 096474380..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/WorldLoadGraph.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.djrapitops.plan.utilities.html.graphs.line; - -import com.djrapitops.plan.data.container.TPS; -import com.djrapitops.plan.systems.tasks.TPSCountTimer; -import com.djrapitops.plan.utilities.analysis.Point; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * Class for creating scatter graph data from Chunk and Entity load snapshots with TPS task. - * - * @author Rsl1122 - * @see TPSCountTimer - * @since 3.6.0 - */ -public class WorldLoadGraph { - - /** - * Constructor used to hide the public constructor - */ - private WorldLoadGraph() { - throw new IllegalStateException("Utility class"); - } - - /** - * Creates series graph data of entity load. - * - * @param tpsData TPS Data collected by TPSCountTimer, one data point for each minute. - * @return Series data for HighCharts - */ - public static String createSeriesEntities(List tpsData) { - List points = tpsData.stream() - .map(tps -> new Point(tps.getDate(), tps.getEntityCount())) - .collect(Collectors.toList()); - return LineSeries.createSeries(points, true); - } - - /** - * Creates series data of chunk load. - * - * @param tpsData TPS Data collected by TPSCountTimer, one data point for each minute. - * @return Series data for HighCharts - */ - public static String createSeriesChunks(List tpsData) { - List points = tpsData.stream() - .map(tps -> new Point(tps.getDate(), tps.getChunksLoaded())) - .collect(Collectors.toList()); - return LineSeries.createSeries(points, true); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/DouglasPeuckerAlgorithm.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/alg/DouglasPeuckerAlgorithm.java similarity index 82% rename from Plan/src/main/java/com/djrapitops/plan/utilities/analysis/DouglasPeuckerAlgorithm.java rename to Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/alg/DouglasPeuckerAlgorithm.java index c6b550cdd..9108ce055 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/DouglasPeuckerAlgorithm.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/alg/DouglasPeuckerAlgorithm.java @@ -1,12 +1,16 @@ -package com.djrapitops.plan.utilities.analysis; +package com.djrapitops.plan.utilities.html.graphs.line.alg; + +import com.djrapitops.plan.utilities.html.graphs.line.Line; +import com.djrapitops.plan.utilities.html.graphs.line.Point; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** - * Ramer-Douglas-Peucker Point Reduction Algorithm for reducing points from - * graphs. + * Ramer-Douglas-Peucker Point Reduction Algorithm Implementation for reducing points from graphs. + * + * https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm * * @author Rsl1122 * @since 3.5.2 diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/ReduceGapTriangles.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/alg/ReduceGapTriangles.java similarity index 85% rename from Plan/src/main/java/com/djrapitops/plan/utilities/analysis/ReduceGapTriangles.java rename to Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/alg/ReduceGapTriangles.java index 3de42f283..1d0d39700 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/ReduceGapTriangles.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/line/alg/ReduceGapTriangles.java @@ -1,6 +1,7 @@ -package com.djrapitops.plan.utilities.analysis; +package com.djrapitops.plan.utilities.html.graphs.line.alg; import com.djrapitops.plan.utilities.comparators.PointComparator; +import com.djrapitops.plan.utilities.html.graphs.line.Point; import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.utilities.Verify; @@ -9,7 +10,9 @@ import java.util.List; import java.util.Set; /** - * Created by Fuzzlemann on 30.07.2017. + * Utility for reducing Points in LineGraphs. + * + * @author Rsl1122 (Refactored into this class by Fuzzlemann) */ public class ReduceGapTriangles { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/AbstractPieChart.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/AbstractPieChart.java new file mode 100644 index 000000000..00009126d --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/AbstractPieChart.java @@ -0,0 +1,59 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.utilities.html.graphs.pie; + +import com.djrapitops.plan.utilities.html.graphs.HighChart; + +import java.util.ArrayList; +import java.util.List; + +/** + * This is a PieChart for any set of PieSlices, thus it is Abstract. + * + * @author Rsl1122 + * @since 4.2.0 + */ +public class AbstractPieChart implements HighChart { + + protected List slices; + + public AbstractPieChart() { + slices = new ArrayList<>(); + } + + public AbstractPieChart(List slices) { + this.slices = slices; + } + + @Deprecated + public static String createSeries(List slices) { + return new AbstractPieChart(slices).toHighChartsSeries(); + } + + @Override + public String toHighChartsSeries() { + StringBuilder seriesBuilder = new StringBuilder("["); + int i = 0; + int size = slices.size(); + for (PieSlice slice : slices) { + seriesBuilder.append(slice.toString()); + if (i < size - 1) { + seriesBuilder.append(","); + } + i++; + } + seriesBuilder.append("]"); + + return seriesBuilder.toString(); + } + + public void setSlices(List slices) { + this.slices = slices; + } + + public void addSlices(List slices) { + this.slices.addAll(slices); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/AbstractPieChartWithDrilldown.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/AbstractPieChartWithDrilldown.java new file mode 100644 index 000000000..8044b0955 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/AbstractPieChartWithDrilldown.java @@ -0,0 +1,25 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.utilities.html.graphs.pie; + +import java.util.List; + +/** + * PieChart with a Pie about each slice as well. + * + * @author Rsl1122 + */ +public abstract class AbstractPieChartWithDrilldown extends AbstractPieChart { + + public AbstractPieChartWithDrilldown() { + } + + public AbstractPieChartWithDrilldown(List slices) { + super(slices); + } + + public abstract String toHighChartsDrilldown(); + +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/ActivityPie.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/ActivityPie.java index 1ab72b2f7..afdc6d8d7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/ActivityPie.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/ActivityPie.java @@ -1,43 +1,42 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan.utilities.html.graphs.pie; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.settings.theme.ThemeVal; +import com.djrapitops.plan.data.calculation.ActivityIndex; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.ThemeVal; import java.util.*; /** - * //TODO Class Javadoc Comment + * Pie about different Activity Groups defined by ActivityIndex. * * @author Rsl1122 + * @see ActivityIndex + * @since 4.2.0 */ -public class ActivityPie { +public class ActivityPie extends AbstractPieChart { - private ActivityPie() { - throw new IllegalStateException("Utility Class"); + public ActivityPie(Map> activityData) { + super(turnToSlices(activityData)); } - public static String[] getSliceNames() { - return new String[]{"Very Active", "Active", "Regular", "Irregular", "Inactive"}; - } - - public static String createSeries(Map> activityData) { + private static List turnToSlices(Map> activityData) { String[] colors = Theme.getValue(ThemeVal.GRAPH_ACTIVITY_PIE).split(", "); int maxCol = colors.length; List slices = new ArrayList<>(); int i = 0; - for (String slice : getSliceNames()) { - Set players = activityData.getOrDefault(slice, new HashSet<>()); + for (String group : ActivityIndex.getGroups()) { + Set players = activityData.getOrDefault(group, new HashSet<>()); int num = players.size(); - slices.add(new PieSlice(slice, num, colors[i % maxCol], false)); + slices.add(new PieSlice(group, num, colors[i % maxCol], false)); i++; } - return PieSeries.createSeries(slices); + return slices; } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/PieSeries.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/PieSeries.java deleted file mode 100644 index bc71845a3..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/PieSeries.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.utilities.html.graphs.pie; - -import java.util.List; - -/** - * PieSeries data creation utility class. - * - * @author Rsl1122 - */ -public class PieSeries { - private PieSeries() { - throw new IllegalStateException("Utility Class"); - } - - public static String createSeries(List slices) { - StringBuilder seriesBuilder = new StringBuilder("["); - int i = 0; - int size = slices.size(); - for (PieSlice slice : slices) { - seriesBuilder.append(slice.toString()); - if (i < size - 1) { - seriesBuilder.append(","); - } - i++; - } - seriesBuilder.append("]"); - - return seriesBuilder.toString(); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/PieSlice.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/PieSlice.java index 01c5628ea..180be2ad1 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/PieSlice.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/PieSlice.java @@ -1,4 +1,4 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ @@ -15,6 +15,18 @@ public class PieSlice { private final String color; private final boolean drilldown; + public PieSlice(String name, long y) { + this(name, y, null, false); + } + + public PieSlice(String name, long y, String color) { + this(name, y, color, false); + } + + public PieSlice(String name, long y, boolean drilldown) { + this(name, y, null, drilldown); + } + public PieSlice(String name, long y, String color, boolean drilldown) { this.name = name; this.y = y; @@ -25,8 +37,8 @@ public class PieSlice { @Override public String toString() { return "{name:'" + name + "'," + - "y:" + y + "," + - "color:" + color + "y:" + y + + (color != null ? "," + "color:" + color : "") + (drilldown ? "," + "drilldown: '" + name + "'" : "") + "}"; } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/ServerPreferencePie.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/ServerPreferencePie.java new file mode 100644 index 000000000..81791d328 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/ServerPreferencePie.java @@ -0,0 +1,31 @@ +package com.djrapitops.plan.utilities.html.graphs.pie; + +import com.djrapitops.plan.data.time.WorldTimes; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class ServerPreferencePie extends AbstractPieChart { + + public ServerPreferencePie(Map serverNames, Map serverWorldTimes) { + super(turnToSlices(serverNames, serverWorldTimes)); + } + + private static List turnToSlices(Map serverNames, Map serverWorldTimes) { + List slices = new ArrayList<>(); + + for (Map.Entry server : serverWorldTimes.entrySet()) { + UUID serverUUID = server.getKey(); + WorldTimes worldTimes = server.getValue(); + + String serverName = serverNames.getOrDefault(serverUUID, "Unknown"); + long num = worldTimes.getTotal(); + + slices.add(new PieSlice(serverName, num)); + } + + return slices; + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/WorldPie.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/WorldPie.java index d15ff8076..79e5d0b84 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/WorldPie.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/pie/WorldPie.java @@ -2,39 +2,27 @@ package com.djrapitops.plan.utilities.html.graphs.pie; import com.djrapitops.plan.data.time.GMTimes; import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.WorldAliasSettings; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.settings.theme.ThemeVal; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.WorldAliasSettings; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.ThemeVal; import com.djrapitops.plan.utilities.comparators.PieSliceComparator; import java.util.*; import java.util.stream.Collectors; -public class WorldPie { +public class WorldPie extends AbstractPieChartWithDrilldown { - private WorldPie() { - throw new IllegalStateException("Utility Class"); - } + private WorldTimes worldTimes; - /** - * Used to create HighCharts series string for series and drilldown. - * - * @param worldTimes WorldTimes object. - * @return String array, index 0: Series data, 1: drilldown data - */ - public static String[] createSeries(WorldTimes worldTimes) { - List slices = turnIntoSlices(worldTimes); + public WorldPie(WorldTimes worldTimes) { + super(turnIntoSlices(worldTimes)); + + this.worldTimes = worldTimes; if (Settings.ORDER_WORLD_PIE_BY_PERC.isTrue()) { slices.sort(new PieSliceComparator()); } - - String seriesData = PieSeries.createSeries(slices); - - String drilldownData = createDrilldown(worldTimes); - - return new String[]{seriesData, drilldownData}; } private static List turnIntoSlices(WorldTimes worldTimes) { @@ -59,6 +47,7 @@ public class WorldPie { } i++; } + return slices; } @@ -68,8 +57,9 @@ public class WorldPie { return transformToAliases(playtimePerWorld, aliases); } + // TODO Move to another class public static Map transformToAliases(Map playtimePerWorld, Map aliases) { - // TODO Optimization is possible + // TODO Optimization is possible (WorldAliasSettings) WorldAliasSettings aliasSettings = new WorldAliasSettings(); Map playtimePerAlias = new HashMap<>(); @@ -89,7 +79,8 @@ public class WorldPie { return playtimePerAlias; } - private static String createDrilldown(WorldTimes worldTimes) { + @Override + public String toHighChartsDrilldown() { StringBuilder drilldownBuilder = new StringBuilder(); int i = 0; @@ -118,8 +109,8 @@ public class WorldPie { return drilldownBuilder.toString(); } - private static Map transformToGMAliases(Map gmTimesMap) { - // TODO Optimization is possible + private Map transformToGMAliases(Map gmTimesMap) { + // TODO Optimization is possible (WorldAliasSettings) WorldAliasSettings aliasSettings = new WorldAliasSettings(); Map aliases = aliasSettings.getAliases(); @@ -138,16 +129,16 @@ public class WorldPie { String alias = aliases.get(worldName); - GMTimes aliasGMtimes = gmTimesPerAlias.getOrDefault(alias, new GMTimes()); + GMTimes aliasGMTimes = gmTimesPerAlias.getOrDefault(alias, new GMTimes()); for (String gm : gms) { - aliasGMtimes.addTime(gm, gmTimes.getTime(gm)); + aliasGMTimes.addTime(gm, gmTimes.getTime(gm)); } - gmTimesPerAlias.put(alias, aliasGMtimes); + gmTimesPerAlias.put(alias, aliasGMTimes); } return gmTimesPerAlias; } - private static void appendGMTimesForWorld(StringBuilder drilldownBuilder, Map.Entry world) { + private void appendGMTimesForWorld(StringBuilder drilldownBuilder, Map.Entry world) { Map gmTimes = world.getValue().getTimes(); int smallSize = gmTimes.size(); int j = 0; diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/stack/AbstractStackGraph.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/stack/AbstractStackGraph.java new file mode 100644 index 000000000..a96e9d3ad --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/stack/AbstractStackGraph.java @@ -0,0 +1,78 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.utilities.html.graphs.stack; + +import com.djrapitops.plan.utilities.html.graphs.HighChart; + +/** + * Utility for creating HighCharts Stack graphs. + * + * @author Rsl1122 + */ +public class AbstractStackGraph implements HighChart { + + private final StackDataSet[] dataSets; + private final String[] labels; + + public AbstractStackGraph(String[] labels, StackDataSet... dataSets) { + this.dataSets = dataSets; + this.labels = labels; + } + + public String toHighChartsLabels() { + StringBuilder labelBuilder = new StringBuilder("["); + + int length = this.labels.length; + int i = 0; + for (String label : this.labels) { + labelBuilder.append("'").append(label).append("'"); + + if (i < length - 1) { + labelBuilder.append(","); + } + i++; + } + + return labelBuilder.append("]").toString(); + } + + private String toSeries(StackDataSet dataSet) { + StringBuilder dataSetBuilder = new StringBuilder("{name: '"); + + dataSetBuilder.append(dataSet.getName()).append("',") + .append("color:").append(dataSet.getColor()) + .append(",data: ["); + + int size = dataSet.size(); + int i = 0; + for (Double value : dataSet) { + dataSetBuilder.append(value); + if (i < size - 1) { + dataSetBuilder.append(","); + } + i++; + } + + return dataSetBuilder.append("]}").toString(); + } + + @Override + public String toHighChartsSeries() { + StringBuilder seriesBuilder = new StringBuilder("["); + + int size = dataSets.length; + int i = 0; + for (StackDataSet dataSet : dataSets) { + seriesBuilder.append(toSeries(dataSet)); + + if (i < size - 1) { + seriesBuilder.append(","); + } + i++; + } + + return seriesBuilder.append("]").toString(); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/stack/StackDataSet.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/stack/StackDataSet.java new file mode 100644 index 000000000..641e23737 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/graphs/stack/StackDataSet.java @@ -0,0 +1,37 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.utilities.html.graphs.stack; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a value set for a Stack graph. + *

    + * Stack graphs have labels that are defined separately and each StackDataSet represents a "line" in the stack graph. + *

    + * Each StackDataSet can have a HTML color hex. + * + * @author Rsl1122 + */ +public class StackDataSet extends ArrayList { + + private final String name; + private final String color; + + public StackDataSet(List values, String name, String color) { + super(values); + this.name = name; + this.color = color; + } + + public String getName() { + return name; + } + + public String getColor() { + return color; + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/AnalysisPluginsTabContentCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/AnalysisPluginsTabContentCreator.java index afc536bbd..b826c875f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/AnalysisPluginsTabContentCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/AnalysisPluginsTabContentCreator.java @@ -1,4 +1,4 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ @@ -36,7 +36,7 @@ public class AnalysisPluginsTabContentCreator { generalTab.append("

    "); - boolean hasGeneralBoxes = false; + boolean displayGeneralTab = false; for (PluginData pluginData : order) { AnalysisContainer container = containers.get(pluginData); @@ -48,20 +48,19 @@ public class AnalysisPluginsTabContentCreator { case WHOLE: if (!container.hasOnlyValues()) { appendWhole(pluginData, container, generalTab); - hasGeneralBoxes = true; - break; + displayGeneralTab = true; } - + break; case TWO_THIRDS: if (!container.hasOnlyValues()) { appendTwoThirds(pluginData, container, generalTab); - hasGeneralBoxes = true; - break; + displayGeneralTab = true; } + break; case THIRD: default: appendThird(pluginData, container, generalTab); - hasGeneralBoxes = true; + displayGeneralTab = true; break; } } @@ -80,9 +79,9 @@ public class AnalysisPluginsTabContentCreator { "
    "; return new String[]{ - (hasGeneralBoxes ? "
  • General
  • " : "") + (displayGeneralTab ? "
  • General
  • " : "") + "
  • Player Data
  • " + nav.toString(), - (hasGeneralBoxes ? generalTab.toString() : "") + playerListTab + otherTabs.toString() + (displayGeneralTab ? generalTab.toString() : "") + playerListTab + otherTabs.toString() }; } diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/InspectPluginsTabContentCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/InspectPluginsTabContentCreator.java deleted file mode 100644 index 68f4cc4f5..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/InspectPluginsTabContentCreator.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.utilities.html.structure; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.data.element.InspectContainer; -import com.djrapitops.plan.data.plugin.PluginData; -import com.djrapitops.plan.systems.info.server.BukkitServerInfoManager; -import com.djrapitops.plan.utilities.comparators.PluginDataNameComparator; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -public class InspectPluginsTabContentCreator { - - public static String[] createContent(Map containers) { - BukkitServerInfoManager serverInfoManager = Plan.getInstance().getServerInfoManager(); - String serverName = serverInfoManager.getServerName(); - String actualServerName = serverName.equals("Plan") ? "Server " + serverInfoManager.getServerID() : serverName; - - if (containers.isEmpty()) { - return new String[]{"
  • " + actualServerName + "(No Data)
  • ", - ""}; - } - - String nav = "
  • " + actualServerName + "
  • "; - - StringBuilder tab = new StringBuilder(); - tab.append("
    "); - - List order = new ArrayList<>(containers.keySet()); - order.sort(new PluginDataNameComparator()); - - for (PluginData pluginData : order) { - InspectContainer container = containers.get(pluginData); - AnalysisPluginsTabContentCreator.appendThird(pluginData, container, tab); - } - - tab.append("
    "); - - return new String[]{nav, tab.toString()}; - } - -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/ServerAccordionCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/ServerAccordionCreator.java index df1ec82cf..ef48fa76f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/ServerAccordionCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/ServerAccordionCreator.java @@ -7,10 +7,9 @@ package com.djrapitops.plan.utilities.html.structure; import com.djrapitops.plan.data.PlayerProfile; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.settings.theme.ThemeVal; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.ThemeVal; import com.djrapitops.plan.utilities.FormatUtils; -import com.djrapitops.plan.utilities.analysis.AnalysisUtils; import com.djrapitops.plan.utilities.analysis.MathUtils; import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie; import com.djrapitops.plugin.utilities.Format; @@ -20,7 +19,7 @@ import java.util.Map; import java.util.UUID; /** - * //TODO Class Javadoc Comment + * HTML utility class for creating a Server Accordion. * * @author Rsl1122 */ @@ -66,9 +65,8 @@ public class ServerAccordionCreator { String htmlID = "server_" + sanitizedServerName; String worldId = "worldPieServer" + sanitizedServerName; - AnalysisUtils.addMissingWorlds(worldTimes); - String[] worldData = WorldPie.createSeries(worldTimes); + WorldPie worldPie = new WorldPie(worldTimes); // Accordion panel header html.append("
    ") @@ -104,8 +102,8 @@ public class ServerAccordionCreator { .append("
    ") // World Pie data script .append("") .append("
    ") // Right col-6 .append("") // Closes row clearfix diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/SessionTabStructureCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/SessionTabStructureCreator.java index 59f6928bc..cc53771a7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/SessionTabStructureCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/SessionTabStructureCreator.java @@ -4,18 +4,18 @@ */ package com.djrapitops.plan.utilities.html.structure; -import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.PlanAPI; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.theme.Theme; -import com.djrapitops.plan.settings.theme.ThemeVal; +import com.djrapitops.plan.system.cache.DataCache; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.djrapitops.plan.system.settings.theme.ThemeVal; import com.djrapitops.plan.utilities.FormatUtils; -import com.djrapitops.plan.utilities.analysis.AnalysisUtils; import com.djrapitops.plan.utilities.html.Html; import com.djrapitops.plan.utilities.html.HtmlStructure; import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie; -import com.djrapitops.plan.utilities.html.tables.KillsTableCreator; +import com.djrapitops.plan.utilities.html.tables.KillsTable; import com.djrapitops.plan.utilities.html.tables.SessionsTableCreator; import com.djrapitops.plugin.utilities.Verify; @@ -25,7 +25,7 @@ import java.util.Map; import java.util.UUID; /** - * //TODO Class Javadoc Comment + * HTML utility class used for creating main element on Sessions tabs. * * @author Rsl1122 */ @@ -51,7 +51,7 @@ public class SessionTabStructureCreator { maxSessions = 50; } - boolean appendWorldPerc = Settings.APPEND_WORLD_PERC.isTrue(); + boolean appendWorldPercentage = Settings.APPEND_WORLD_PERC.isTrue(); for (Session session : allSessions) { if (i >= maxSessions) { @@ -69,36 +69,36 @@ public class SessionTabStructureCreator { int playerKillCount = session.getPlayerKills().size(); - String name = Plan.getInstance().getDataCache().getName(uuid); - String link = Plan.getPlanAPI().getPlayerInspectPageLink(name); + String name = DataCache.getInstance().getName(uuid); + String link = PlanAPI.getInstance().getPlayerInspectPageLink(name); - String dotSeparated2 = appendWorldPerc + String info = appendWorldPercentage ? HtmlStructure.separateWithDots(sessionStart, SessionsTableCreator.getLongestWorldPlayed(session)) : sessionStart; - String dotSeparated = appendName ? - HtmlStructure.separateWithDots(name, dotSeparated2) : - HtmlStructure.separateWithDots(serverName, dotSeparated2); + String nameAndInfo = appendName ? + HtmlStructure.separateWithDots(name, info) : + HtmlStructure.separateWithDots(serverName, info); String htmlID = "" + session.getSessionStart() + sessionID + i; String worldId = "worldPie" + session.getSessionStart() + i; WorldTimes worldTimes = session.getWorldTimes(); - AnalysisUtils.addMissingWorlds(worldTimes); - String[] worldData = WorldPie.createSeries(worldTimes); + WorldPie worldPie = new WorldPie(worldTimes); - String killTable = KillsTableCreator.createTable(session.getPlayerKills()); + String killTable = new KillsTable(session.getPlayerKills()).parseHtml(); // Accordion panel header html.append("
    ") .append(""); // Closes panel heading @@ -130,8 +130,8 @@ public class SessionTabStructureCreator { .append("
    ") // World Pie data script .append("") .append("
    ") // Right col-6 .append("") // Closes row clearfix diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/TabsElement.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/TabsElement.java new file mode 100644 index 000000000..3cb8d7c25 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/structure/TabsElement.java @@ -0,0 +1,70 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.utilities.html.structure; + +import com.djrapitops.plugin.utilities.Format; + +/** + * Represents a structural HTML element that has Tabs on the top. + * + * @author Rsl1122 + */ +public class TabsElement { + + private final Tab[] tabs; + + public TabsElement(Tab... tabs) { + this.tabs = tabs; + } + + public String[] toHtml() { + StringBuilder nav = new StringBuilder(); + StringBuilder content = new StringBuilder(); + + nav.append("
      "); + content.append("
      "); + boolean first = true; + for (Tab tab : tabs) { + String id = tab.getId(); + String navText = tab.getNavText(); + String contentHtml = tab.getContentHtml(); + + nav.append("
    • ") + .append(navText).append("
    • "); + content.append("
      ") + .append(contentHtml).append("
      "); + first = false; + } + content.append(""); + nav.append("
    "); + + return new String[]{nav.toString(), content.toString()}; + } + + public static class Tab { + + private final String navText; + private final String contentHtml; + + public Tab(String navText, String contentHtml) { + this.navText = navText; + this.contentHtml = contentHtml; + } + + public String getNavText() { + return navText; + } + + public String getContentHtml() { + return contentHtml; + } + + public String getId() { + return "tab_" + new Format(navText).removeSymbols().removeWhitespace().lowerCase().toString(); + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/ActionsTable.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/ActionsTable.java new file mode 100644 index 000000000..fefbd24dd --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/ActionsTable.java @@ -0,0 +1,45 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.utilities.html.tables; + +import com.djrapitops.plan.data.container.Action; +import com.djrapitops.plan.data.element.TableContainer; +import com.djrapitops.plan.utilities.FormatUtils; +import com.djrapitops.plan.utilities.html.HtmlUtils; + +import java.util.List; + +/** + * Utility Class for creating Actions Table for inspect page. + * + * @author Rsl1122 + */ +public class ActionsTable extends TableContainer { + + public ActionsTable(List actions) { + super("Date", "Action", "Info"); + + if (actions.isEmpty()) { + addRow("No Actions"); + } else { + addValues(actions); + } + } + + private void addValues(List actions) { + int i = 0; + for (Action action : actions) { + if (i > 50) { + break; + } + addRow( + FormatUtils.formatTimeStampYear(action.getDate()), + action.getDoneAction().toString(), + HtmlUtils.swapColorsToSpan(action.getAdditionalInfo()) + ); + i++; + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/ActionsTableCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/ActionsTableCreator.java deleted file mode 100644 index 9a1c29d8a..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/ActionsTableCreator.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.utilities.html.tables; - -import com.djrapitops.plan.data.container.Action; -import com.djrapitops.plan.utilities.FormatUtils; -import com.djrapitops.plan.utilities.html.Html; -import com.djrapitops.plan.utilities.html.HtmlUtils; - -import java.util.List; - -/** - * Utility Class for creating Actions Table for inspect page. - * - * @author Rsl1122 - */ -public class ActionsTableCreator { - - - public ActionsTableCreator() { - throw new IllegalStateException("Utility class"); - } - - public static String createTable(List actions) { - StringBuilder html = new StringBuilder(); - if (actions.isEmpty()) { - html.append(Html.TABLELINE_3.parse("No Actions", "-", "-")); - } else { - int i = 0; - for (Action action : actions) { - if (i >= 100) { - break; - } - - long date = action.getDate(); - - html.append(Html.TABLELINE_3_CUSTOMKEY_1.parse( - String.valueOf(date), FormatUtils.formatTimeStampYear(date), - action.getDoneAction().toString(), - HtmlUtils.swapColorsToSpan(action.getAdditionalInfo()) - )); - - i++; - } - } - return html.toString(); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/CommandUseTable.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/CommandUseTable.java new file mode 100644 index 000000000..72c6a674e --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/CommandUseTable.java @@ -0,0 +1,41 @@ +package com.djrapitops.plan.utilities.html.tables; + +import com.djrapitops.plan.data.element.TableContainer; +import com.djrapitops.plan.utilities.comparators.MapComparator; +import com.djrapitops.plan.utilities.html.HtmlUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * @author Rsl1122 + */ +public class CommandUseTable extends TableContainer { + + public CommandUseTable(Map commandUse) { + super("Command", "Times Used"); + + if (commandUse.isEmpty()) { + addRow("No Commands"); + } else { + addValues(commandUse); + } + } + + private void addValues(Map commandUse) { + List sorted = MapComparator.sortByValue(commandUse); + Collections.reverse(sorted); + + int i = 0; + for (String[] values : sorted) { + if (i >= 500) { + break; + } + String command = HtmlUtils.removeXSS(values[1]); + addRow(command, values[0]); + + i++; + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/CommandUseTableCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/CommandUseTableCreator.java deleted file mode 100644 index 344dd382c..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/CommandUseTableCreator.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.djrapitops.plan.utilities.html.tables; - -import com.djrapitops.plan.utilities.comparators.MapComparator; -import com.djrapitops.plan.utilities.html.Html; -import com.djrapitops.plugin.api.utility.log.Log; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * @author Rsl1122 - */ -public class CommandUseTableCreator { - - /** - * Constructor used to hide the public constructor - */ - private CommandUseTableCreator() { - throw new IllegalStateException("Utility class"); - } - - /** - * @param commandUse The commands and the amount of times casted - * @return The created command use table - */ - public static String createTable(Map commandUse) { - List sorted = MapComparator.sortByValue(commandUse); - - StringBuilder html = new StringBuilder(); - if (sorted.isEmpty()) { - html.append(Html.TABLELINE_2.parse("No Commands", "")); - } else { - Collections.reverse(sorted); - int i = 0; - for (String[] values : sorted) { - if (i >= 500) { - break; - } - - try { - html.append(Html.TABLELINE_2.parse(values[1], values[0])); - } catch (IllegalArgumentException e) { - Log.toLog("CommandUseTable - Cause: " + values[0] + " " + values[1], e); - } - - i++; - } - } - - return html.toString(); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/GeoInfoTable.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/GeoInfoTable.java new file mode 100644 index 000000000..d21c77972 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/GeoInfoTable.java @@ -0,0 +1,40 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.utilities.html.tables; + +import com.djrapitops.plan.data.container.GeoInfo; +import com.djrapitops.plan.data.element.TableContainer; +import com.djrapitops.plan.utilities.FormatUtils; + +import java.util.List; + +/** + * Utility Class for creating IP Table for inspect page. + * + * @author Rsl1122 + */ +public class GeoInfoTable extends TableContainer { + + public GeoInfoTable(List geoInfo) { + super("IP", "Geolocation", "Last Used"); + + if (geoInfo.isEmpty()) { + addRow("No Connections"); + } else { + addValues(geoInfo); + } + } + + private void addValues(List geoInfo) { + for (GeoInfo info : geoInfo) { + long date = info.getLastUsed(); + addRow( + FormatUtils.formatIP(info.getIp()), + info.getGeolocation(), + date != 0 ? FormatUtils.formatTimeStampYear(date) : "-" + ); + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/IpTableCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/IpTableCreator.java deleted file mode 100644 index e3e44b882..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/IpTableCreator.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.utilities.html.tables; - -import com.djrapitops.plan.data.container.GeoInfo; -import com.djrapitops.plan.utilities.FormatUtils; -import com.djrapitops.plan.utilities.comparators.GeoInfoComparator; -import com.djrapitops.plan.utilities.html.Html; - -import java.util.List; - -/** - * Utility Class for creating IP Table for inspect page. - * - * @author Rsl1122 - */ -public class IpTableCreator { - - - public IpTableCreator() { - throw new IllegalStateException("Utility class"); - } - - public static String createTable(List geoInfo) { - geoInfo.sort(new GeoInfoComparator()); - StringBuilder html = new StringBuilder(); - if (geoInfo.isEmpty()) { - html.append(Html.TABLELINE_3.parse("No Connections", "-", "-")); - } else { - for (GeoInfo info : geoInfo) { - long date = info.getDate(); - html.append(Html.TABLELINE_3.parse( - FormatUtils.formatIP(info.getIp()), - info.getGeolocation(), - date != 0 ? FormatUtils.formatTimeStampYear(date) : "-" - )); - } - } - return html.toString(); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/KillsTable.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/KillsTable.java new file mode 100644 index 000000000..457235704 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/KillsTable.java @@ -0,0 +1,52 @@ +package com.djrapitops.plan.utilities.html.tables; + +import com.djrapitops.plan.api.PlanAPI; +import com.djrapitops.plan.data.container.PlayerKill; +import com.djrapitops.plan.data.element.TableContainer; +import com.djrapitops.plan.system.cache.DataCache; +import com.djrapitops.plan.utilities.FormatUtils; +import com.djrapitops.plan.utilities.comparators.PlayerKillComparator; +import com.djrapitops.plan.utilities.html.Html; + +import java.util.Collections; +import java.util.List; + +/** + * @author Rsl1122 + */ +public class KillsTable extends TableContainer { + + public KillsTable(List playerKills) { + super(Html.FONT_AWESOME_ICON.parse("clock-o") + " Time", "Killed", "With"); + + if (playerKills.isEmpty()) { + addRow("No Kills"); + } else { + addValues(playerKills); + } + } + + private void addValues(List playerKills) { + playerKills.sort(new PlayerKillComparator()); + Collections.reverse(playerKills); + + int i = 0; + DataCache dataCache = DataCache.getInstance(); + for (PlayerKill kill : playerKills) { + if (i >= 20) { + break; + } + + long date = kill.getTime(); + + String name = dataCache.getName(kill.getVictim()); + addRow( + FormatUtils.formatTimeStampYear(date), + Html.LINK.parse(PlanAPI.getInstance().getPlayerInspectPageLink(name), name), + kill.getWeapon() + ); + + i++; + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/KillsTableCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/KillsTableCreator.java deleted file mode 100644 index cf14b6e3c..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/KillsTableCreator.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.djrapitops.plan.utilities.html.tables; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.data.container.PlayerKill; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.settings.locale.Msg; -import com.djrapitops.plan.utilities.FormatUtils; -import com.djrapitops.plan.utilities.comparators.KillDataComparator; -import com.djrapitops.plan.utilities.html.Html; - -import java.util.Collections; -import java.util.List; - -/** - * @author Rsl1122 - */ -public class KillsTableCreator { - - /** - * Constructor used to hide the public constructor - */ - private KillsTableCreator() { - throw new IllegalStateException("Utility class"); - } - - /** - * @param playerKills The list of the {@link PlayerKill} Objects from which the kill table should be created - * @return The created kills table - */ - public static String createTable(List playerKills) { - StringBuilder html = new StringBuilder(Html.TABLE_KILLS_START.parse()); - - if (playerKills.isEmpty()) { - html.append(Html.TABLELINE_3.parse(Locale.get(Msg.HTML_TABLE_NO_KILLS).parse(), "", "")); - } else { - playerKills.sort(new KillDataComparator()); - Collections.reverse(playerKills); - - int i = 0; - for (PlayerKill kill : playerKills) { - if (i >= 20) { - break; - } - - long date = kill.getTime(); - - String name = Plan.getInstance().getDataCache().getName(kill.getVictim()); - html.append(Html.TABLELINE_3_CUSTOMKEY_1.parse( - String.valueOf(date), FormatUtils.formatTimeStamp(date), - Html.LINK.parse(Plan.getPlanAPI().getPlayerInspectPageLink(name), name), - kill.getWeapon() - )); - - i++; - } - } - - html.append(Html.TABLE_END.parse()); - - return html.toString(); - } -} diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/NicknameTable.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/NicknameTable.java new file mode 100644 index 000000000..38a2ec0a6 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/NicknameTable.java @@ -0,0 +1,42 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.utilities.html.tables; + +import com.djrapitops.plan.data.element.TableContainer; +import com.djrapitops.plan.utilities.html.HtmlUtils; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * Utility Class for creating Nicknames Table for inspect page. + * + * @author Rsl1122 + */ +public class NicknameTable extends TableContainer { + + public NicknameTable(Map> nicknames, Map serverNames) { + super("Nickname", "Server"); + + if (nicknames.isEmpty()) { + addRow("No Nicknames"); + } else { + addValues(nicknames, serverNames); + } + } + + private void addValues(Map> nicknames, Map serverNames) { + for (Map.Entry> entry : nicknames.entrySet()) { + String serverName = serverNames.getOrDefault(entry.getKey(), "Unknown"); + for (String nick : entry.getValue()) { + addRow( + HtmlUtils.swapColorsToSpan(HtmlUtils.removeXSS(nick)), + serverName + ); + } + } + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/NicknameTableCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/NicknameTableCreator.java deleted file mode 100644 index f67591905..000000000 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/NicknameTableCreator.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.utilities.html.tables; - -import com.djrapitops.plan.utilities.html.Html; -import com.djrapitops.plan.utilities.html.HtmlUtils; - -import java.util.List; -import java.util.Map; -import java.util.UUID; - -/** - * Utility Class for creating Nicknames Table for inspect page. - * - * @author Rsl1122 - */ -public class NicknameTableCreator { - - - public NicknameTableCreator() { - throw new IllegalStateException("Utility class"); - } - - public static String createTable(Map> nicknames, Map serverNames) { - StringBuilder html = new StringBuilder(); - if (nicknames.isEmpty()) { - html.append(Html.TABLELINE_2.parse("No Nicknames", "-")); - } else { - for (Map.Entry> entry : nicknames.entrySet()) { - String serverName = serverNames.getOrDefault(entry.getKey(), "Unknown"); - for (String nick : entry.getValue()) { - html.append(Html.TABLELINE_2.parse(HtmlUtils.swapColorsToSpan(HtmlUtils.removeXSS(nick)), serverName)); - } - } - } - return html.toString(); - } -} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/PlayersTableCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/PlayersTableCreator.java index 50e267a45..07cc2bfb4 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/PlayersTableCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/PlayersTableCreator.java @@ -1,11 +1,13 @@ package com.djrapitops.plan.utilities.html.tables; -import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.PlanAPI; import com.djrapitops.plan.data.PlayerProfile; +import com.djrapitops.plan.data.calculation.ActivityIndex; import com.djrapitops.plan.data.element.AnalysisContainer; import com.djrapitops.plan.data.element.TableContainer; import com.djrapitops.plan.data.plugin.PluginData; -import com.djrapitops.plan.settings.Settings; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.settings.Settings; import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plan.utilities.html.Html; @@ -18,6 +20,7 @@ import java.util.*; /** * @author Rsl1122 */ +// TODO Start using TableContainer for both tables public class PlayersTableCreator { /** @@ -35,7 +38,7 @@ public class PlayersTableCreator { StringBuilder html = new StringBuilder(); long now = MiscUtils.getTime(); - UUID serverUUID = MiscUtils.getIPlan().getServerUuid(); + UUID serverUUID = ServerInfo.getServerUUID(); int i = 0; int maxPlayers = Settings.MAX_PLAYERS.getNumber(); @@ -55,23 +58,24 @@ public class PlayersTableCreator { long lastSeen = profile.getLastSeen(); - double activityIndex = profile.getActivityIndex(now); - String readableIndex = FormatUtils.readableActivityIndex(activityIndex)[1]; - String activityString = FormatUtils.cutDecimals(activityIndex) - + (isBanned ? " (Banned)" : " (" + readableIndex + ")"); + ActivityIndex activityIndex = profile.getActivityIndex(now); + String activityGroup = activityIndex.getGroup(); + String activityString = activityIndex.getFormattedValue() + + (isBanned ? " (Banned)" : " (" + activityGroup + ")"); String geoLocation = profile.getMostRecentGeoInfo().getGeolocation(); html.append(Html.TABLELINE_PLAYERS.parse( - Html.LINK_EXTERNAL.parse(Plan.getPlanAPI().getPlayerInspectPageLink(profile.getName()), profile.getName()), + Html.LINK_EXTERNAL.parse(PlanAPI.getInstance().getPlayerInspectPageLink(profile.getName()), profile.getName()), activityString, - String.valueOf(playtime), FormatUtils.formatTimeAmount(playtime), - String.valueOf(loginTimes), - String.valueOf(registered), FormatUtils.formatTimeStampYear(registered), - String.valueOf(lastSeen), lastSeen != 0 ? FormatUtils.formatTimeStamp(lastSeen) : "-", - String.valueOf(geoLocation) + playtime, FormatUtils.formatTimeAmount(playtime), + loginTimes, + registered, FormatUtils.formatTimeStampYear(registered), + lastSeen, lastSeen != 0 ? FormatUtils.formatTimeStampYear(lastSeen) : "-", + geoLocation )); } catch (NullPointerException e) { if (Settings.DEV_MODE.isTrue()) { + Log.warn("THIS ERROR IS ONLY LOGGED IN DEV MODE:"); Log.toLog(PlayersTableCreator.class.getName(), e); } } @@ -131,7 +135,7 @@ public class PlayersTableCreator { break; } UUID uuid = profile.getUuid(); - String link = Html.LINK_EXTERNAL.parse(Plan.getPlanAPI().getPlayerInspectPageLink(profile.getName()), profile.getName()); + String link = Html.LINK_EXTERNAL.parse(PlanAPI.getInstance().getPlayerInspectPageLink(profile.getName()), profile.getName()); String[] playerData = FormatUtils.mergeArrays(new String[]{link}, sortedData.getOrDefault(uuid, new String[]{})); tableContainer.addRow(ArrayUtils.addAll(playerData)); diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/SessionsTableCreator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/SessionsTableCreator.java index 08362a0c8..db7153c48 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/SessionsTableCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/html/tables/SessionsTableCreator.java @@ -1,16 +1,16 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ package com.djrapitops.plan.utilities.html.tables; -import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.PlanAPI; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.WorldAliasSettings; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.cache.SessionCache; +import com.djrapitops.plan.system.cache.DataCache; +import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.settings.WorldAliasSettings; import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.comparators.SessionStartComparator; import com.djrapitops.plan.utilities.html.Html; @@ -20,10 +20,11 @@ import java.util.*; import java.util.stream.Collectors; /** - * //TODO Class Javadoc Comment + * Utility for creating HTML {@code
    }-element with Sessions inside it. * * @author Rsl1122 */ +// TODO start using TableContainer public class SessionsTableCreator { private static Map getUUIDsByID(Map> sessionsByUser) { @@ -53,7 +54,7 @@ public class SessionsTableCreator { Set recentLoginsNames = new HashSet<>(); - DataCache dataCache = Plan.getInstance().getDataCache(); + Map uuidBySessionStart = new HashMap<>(); for (Map.Entry entry : SessionCache.getActiveSessions().entrySet()) { @@ -64,6 +65,8 @@ public class SessionsTableCreator { if (maxSessions <= 0) { maxSessions = 50; } + + DataCache dataCache = DataCache.getInstance(); for (Session session : allSessions) { if (i >= maxSessions) { break; @@ -77,11 +80,11 @@ public class SessionsTableCreator { } String name = dataCache.getName(uuid); - String start = FormatUtils.formatTimeStamp(session.getSessionStart()); + String start = FormatUtils.formatTimeStampYear(session.getSessionStart()); String length = session.getSessionEnd() != -1 ? FormatUtils.formatTimeAmount(session.getLength()) : "Online"; String world = getLongestWorldPlayed(session); - String inspectUrl = Plan.getPlanAPI().getPlayerInspectPageLink(name); + String inspectUrl = PlanAPI.getInstance().getPlayerInspectPageLink(name); String toolTip = "Session ID: " + (session.isFetchedFromDB() ? session.getSessionID() : "Not Saved."); sessionTableBuilder.append(Html.TABLELINE_4.parse( Html.LINK_TOOLTIP.parse(inspectUrl, name, toolTip), diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/BStats.java b/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/BStats.java index b278f043e..751e0fdbd 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/BStats.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/BStats.java @@ -1,8 +1,10 @@ package com.djrapitops.plan.utilities.metrics; - import com.djrapitops.plan.Plan; -import com.djrapitops.plan.settings.Settings; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.info.connection.ConnectionSystem; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.system.webserver.WebServer; import com.djrapitops.plugin.api.Check; import com.djrapitops.plugin.api.utility.log.Log; @@ -27,13 +29,11 @@ public class BStats { } private void registerConfigSettingGraphs() { - // TODO Write a Module bar graph - String serverType = plugin.getServer().getName(); if ("CraftBukkit".equals(serverType) && Check.isSpigotAvailable()) { serverType = "Spigot"; - } - String databaseType = plugin.getDB().getName(); + } + String databaseType = Database.getActive().getName(); String analysisRefreshPeriod = Integer.toString(Settings.ANALYSIS_AUTO_REFRESH.getNumber()); String themeBase = Settings.THEME_BASE.toString(); @@ -41,7 +41,7 @@ public class BStats { addStringSettingPie("database_type", databaseType); addStringSettingPie("analysis_periodic_refresh", analysisRefreshPeriod); addStringSettingPie("theme_base", themeBase); - + addFeatureBarChart("features"); } @@ -53,14 +53,14 @@ public class BStats { metrics.addCustomChart(new Metrics.AdvancedBarChart(id, () -> { Map map = new HashMap<>(); - map.put("HTTPS", isEnabled("HTTPS".equals(plugin.getWebServer().getProtocol().toUpperCase()))); + map.put("HTTPS", isEnabled("HTTPS".equals(WebServer.getInstance().getProtocol().toUpperCase()))); map.put("HTML Export", isEnabled(Settings.ANALYSIS_EXPORT.isTrue())); - boolean isConnectedToBungee = plugin.getInfoManager().isUsingAnotherWebServer(); + boolean isConnectedToBungee = ConnectionSystem.getInstance().isServerAvailable(); map.put("BungeeCord Connected", isEnabled(isConnectedToBungee)); if (isConnectedToBungee) { map.put("Copy Bungee Config Values", isEnabled(Settings.BUNGEE_COPY_CONFIG.isTrue())); map.put("Standalone Override", isEnabled(Settings.BUNGEE_OVERRIDE_STANDALONE_MODE.isTrue())); - } + } map.put("Log Unknown Commands", isEnabled(Settings.LOG_UNKNOWN_COMMANDS.isTrue())); map.put("Combine Command Aliases", isEnabled(Settings.COMBINE_COMMAND_ALIASES.isTrue())); return map; diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/Metrics.java b/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/Metrics.java index e026a02f3..20a6cd319 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/Metrics.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/metrics/Metrics.java @@ -28,6 +28,7 @@ import java.util.zip.GZIPOutputStream; *

    * Condition out https://bStats.org/ to learn more about bStats! */ +@SuppressWarnings("unchecked") public class Metrics { // The version of this bStats class @@ -59,11 +60,6 @@ public class Metrics { // A list with all custom charts private final List charts = new ArrayList<>(); - /** - * Class constructor. - * - * @param plugin The plugin which stats should be submitted. - */ public Metrics(JavaPlugin plugin) { if (plugin == null) { throw new IllegalArgumentException("Plugin cannot be null!"); @@ -328,19 +324,10 @@ public class Metrics { }).start(); } - /** - * Represents a custom chart. - */ public abstract static class CustomChart { - // The id of the chart final String chartId; - /** - * Class constructor. - * - * @param chartId The id of the chart. - */ CustomChart(String chartId) { if (chartId == null || chartId.isEmpty()) { throw new IllegalArgumentException("ChartId cannot be null or empty!"); @@ -371,9 +358,6 @@ public class Metrics { } - /** - * Represents a custom simple pie. - */ public static class SimplePie extends CustomChart { private final Callable callable; @@ -402,9 +386,6 @@ public class Metrics { } } - /** - * Represents a custom advanced pie. - */ public static class AdvancedPie extends CustomChart { private final Callable> callable; @@ -446,9 +427,6 @@ public class Metrics { } } - /** - * Represents a custom drilldown pie. - */ public static class DrilldownPie extends CustomChart { private final Callable>> callable; @@ -495,9 +473,6 @@ public class Metrics { } } - /** - * Represents a custom single line chart. - */ public static class SingleLineChart extends CustomChart { private final Callable callable; @@ -527,9 +502,6 @@ public class Metrics { } - /** - * Represents a custom multi line chart. - */ public static class MultiLineChart extends CustomChart { private final Callable> callable; @@ -572,9 +544,6 @@ public class Metrics { } - /** - * Represents a custom simple bar chart. - */ public static class SimpleBarChart extends CustomChart { private final Callable> callable; @@ -610,9 +579,6 @@ public class Metrics { } - /** - * Represents a custom advanced bar chart. - */ public static class AdvancedBarChart extends CustomChart { private final Callable> callable; diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/queue/Consumer.java b/Plan/src/main/java/com/djrapitops/plan/utilities/queue/Consumer.java similarity index 88% rename from Plan/src/main/java/com/djrapitops/plan/systems/queue/Consumer.java rename to Plan/src/main/java/com/djrapitops/plan/utilities/queue/Consumer.java index 62268296b..7cd1cc621 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/queue/Consumer.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/queue/Consumer.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.systems.queue; +package com.djrapitops.plan.utilities.queue; import com.djrapitops.plugin.task.AbsRunnable; @@ -42,12 +42,10 @@ public abstract class Consumer extends AbsRunnable { run = false; try { super.cancel(); - } catch (NullPointerException ignore) { + } catch (NullPointerException | IllegalArgumentException ignore) { /*ignored*/ } } - protected abstract void clearVariables(); - protected abstract void consume(T toConsume); } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/queue/Queue.java b/Plan/src/main/java/com/djrapitops/plan/utilities/queue/Queue.java similarity index 88% rename from Plan/src/main/java/com/djrapitops/plan/systems/queue/Queue.java rename to Plan/src/main/java/com/djrapitops/plan/utilities/queue/Queue.java index 126c395be..35b407e32 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/queue/Queue.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/queue/Queue.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.systems.queue; +package com.djrapitops.plan.utilities.queue; import java.util.ArrayList; import java.util.List; @@ -12,6 +12,7 @@ import java.util.concurrent.BlockingQueue; */ public abstract class Queue { + protected boolean run = true; protected final BlockingQueue queue; protected Setup setup; @@ -30,7 +31,9 @@ public abstract class Queue { * @param object Object to add. */ public void add(T object) { - queue.add(object); + if (run) { + queue.add(object); + } } /** @@ -39,6 +42,7 @@ public abstract class Queue { * @return List of unprocessed objects. */ public List stopAndReturnLeftovers() { + run = false; try { if (setup != null) { setup.stop(); @@ -54,6 +58,7 @@ public abstract class Queue { * Stops all activity and clears the queue. */ public void stop() { + run = false; if (setup != null) { setup.stop(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/systems/queue/Setup.java b/Plan/src/main/java/com/djrapitops/plan/utilities/queue/Setup.java similarity index 94% rename from Plan/src/main/java/com/djrapitops/plan/systems/queue/Setup.java rename to Plan/src/main/java/com/djrapitops/plan/utilities/queue/Setup.java index 694da7a74..f0031cdc1 100644 --- a/Plan/src/main/java/com/djrapitops/plan/systems/queue/Setup.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/queue/Setup.java @@ -1,4 +1,4 @@ -package com.djrapitops.plan.systems.queue; +package com.djrapitops.plan.utilities.queue; import com.djrapitops.plugin.task.RunnableFactory; diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/uuid/UUIDUtility.java b/Plan/src/main/java/com/djrapitops/plan/utilities/uuid/UUIDUtility.java index d33fde425..14f248ea5 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/uuid/UUIDUtility.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/uuid/UUIDUtility.java @@ -5,14 +5,14 @@ */ package com.djrapitops.plan.utilities.uuid; -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.api.exceptions.database.FatalDBException; +import com.djrapitops.plan.system.cache.DataCache; +import com.djrapitops.plan.system.database.databases.Database; import com.djrapitops.plugin.api.Check; import com.djrapitops.plugin.api.utility.UUIDFetcher; import com.djrapitops.plugin.api.utility.log.Log; -import java.sql.SQLException; import java.util.UUID; /** @@ -35,7 +35,7 @@ public class UUIDUtility { */ public static UUID getUUIDOf(String playerName) { try { - return getUUIDOf(playerName, MiscUtils.getIPlan().getDB()); + return getUUIDOf(playerName, Database.getActive()); } catch (Exception e) { return null; } @@ -48,18 +48,20 @@ public class UUIDUtility { * @param db Database to check from. * @return UUID of the player */ - public static UUID getUUIDOf(String playerName, Database db) { + private static UUID getUUIDOf(String playerName, Database db) { UUID uuid = null; if (Check.isBukkitAvailable()) { - UUID uuidOf = Plan.getInstance().getDataCache().getUUIDof(playerName); + UUID uuidOf = DataCache.getInstance().getUUIDof(playerName); if (uuidOf != null) { return uuidOf; } } try { - uuid = db.getUsersTable().getUuidOf(playerName); - } catch (SQLException e) { - Log.toLog("UUIDUtility", e); + uuid = db.fetch().getUuidOf(playerName); + } catch (FatalDBException e) { + Log.toLog(UUIDUtility.class, e); + } catch (DBException e) { + /* Ignored */ } try { if (uuid == null) { diff --git a/Plan/src/main/resources/DefaultServerInfoFile.yml b/Plan/src/main/resources/DefaultServerInfoFile.yml index 1afc6c0e9..3978cd4d5 100644 --- a/Plan/src/main/resources/DefaultServerInfoFile.yml +++ b/Plan/src/main/resources/DefaultServerInfoFile.yml @@ -2,6 +2,3 @@ # Thread with caution. Server: UUID: -Bungee: - WebAddress: '' - Fail: 1 diff --git a/Plan/src/main/resources/bungee.yml b/Plan/src/main/resources/bungee.yml index 683079089..4e3f5d37c 100644 --- a/Plan/src/main/resources/bungee.yml +++ b/Plan/src/main/resources/bungee.yml @@ -1,4 +1,4 @@ name: Plan author: Rsl1122 main: com.djrapitops.plan.PlanBungee -version: 4.1.4 \ No newline at end of file +version: 4.1.5 \ No newline at end of file diff --git a/Plan/src/main/resources/config.yml b/Plan/src/main/resources/config.yml index 3e489f416..dfc7fed33 100644 --- a/Plan/src/main/resources/config.yml +++ b/Plan/src/main/resources/config.yml @@ -35,7 +35,7 @@ WebServer: Alias: 'alias' # For those that want to serve Html from their own WebServer instead. # Set up Html Export (https://github.com/Rsl1122/Plan-PlayerAnalytics/wiki/External-WebServer-Use) - # ATTENTION: On BungeeCord systems it is not possible to disable the WebServer on the plugin due to WebAPI requirements. + # ATTENTION: On BungeeCord systems it is not possible to disable the WebServer on the plugin due to connection requirements. # If the WebServer is disabled with this setting BungeeCord systems will cease to function. DisableWebServer: false ExternalWebServerAddress: "https://www.example.address" @@ -89,6 +89,17 @@ Customization: PlayerTableFooter: true Formatting: DecimalPoints: '#.##' + # Dates settings use Java SimpleDateFormat. + # You can find the patterns & examples here: + # https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html + Dates: + # RecentDays replaces date with Today, Yesterday, Wednesday etc. + RecentDays: true + # Non-regex pattern to replace + DatePattern: 'MMM d YYYY' + Full: 'MMM d YYYY, HH:mm:ss' + NoSeconds: 'MMM d YYYY, HH:mm' + JustClock: 'HH:mm:ss' TimeAmount: Year: '1 year, ' Years: '%years% years, ' @@ -123,3 +134,6 @@ Plugins: Towny: HideTowns: - ExampleTown + BuyCraft: + # http://help.buycraft.net/article/36-where-to-find-the-secret-key + Secret: "-" diff --git a/Plan/src/main/resources/plugin.yml b/Plan/src/main/resources/plugin.yml index dc978003e..d9572022f 100644 --- a/Plan/src/main/resources/plugin.yml +++ b/Plan/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: Plan author: Rsl1122 main: com.djrapitops.plan.Plan -version: 4.1.4 +version: 4.1.5 softdepend: - EssentialsX - Towny diff --git a/Plan/src/main/resources/web/css/main.css b/Plan/src/main/resources/web/css/main.css index 3a2be7d2c..0f11586e4 100644 --- a/Plan/src/main/resources/web/css/main.css +++ b/Plan/src/main/resources/web/css/main.css @@ -81,7 +81,6 @@ .main-limiter { width: 100%; - height: 100%; overflow-x: hidden; margin: 0; padding: 0; @@ -89,7 +88,6 @@ .tab { width: 0; - height: 100%; float: left; } @@ -157,24 +155,9 @@ font-size: 19px; } } -@media only screen and (max-width: 850px) { - header h1 { - font-weight: 400; - font-size: 30px; - } -} @media only screen and (max-width: 780px) { .scrollbar { overflow-x: auto; width: 100%; } - .nav-bar { - flex-direction: row; - } - .row { - flex-direction: column; - } - header p { - display: none; - } } \ No newline at end of file diff --git a/Plan/src/main/resources/web/css/style.css b/Plan/src/main/resources/web/css/style.css index a2ba0a027..6bb4a8702 100644 --- a/Plan/src/main/resources/web/css/style.css +++ b/Plan/src/main/resources/web/css/style.css @@ -2402,7 +2402,7 @@ a { animation: none !important; } section.content { - margin: 100px 15px 0 315px; + margin: 100px 15px 0 235px; -moz-transition: 0.5s; -o-transition: 0.5s; -webkit-transition: 0.5s; @@ -7475,7 +7475,7 @@ fieldset[disabled] .form-control { transition: all 0.5s; font-family: "Roboto", sans-serif; background: #fdfdfd; - width: 300px; + width: 225px; overflow: hidden; display: inline-block; height: calc(100vh - 70px); diff --git a/Plan/src/main/resources/web/error.html b/Plan/src/main/resources/web/error.html index 2a66c50cc..36b937778 100644 --- a/Plan/src/main/resources/web/error.html +++ b/Plan/src/main/resources/web/error.html @@ -236,7 +236,7 @@ - + diff --git a/Plan/src/main/resources/web/js/charts/performanceGraph.js b/Plan/src/main/resources/web/js/charts/performanceGraph.js index 8796a31f9..4914a317a 100644 --- a/Plan/src/main/resources/web/js/charts/performanceGraph.js +++ b/Plan/src/main/resources/web/js/charts/performanceGraph.js @@ -1,32 +1,72 @@ function performanceChart(id, playersOnlineSeries, tpsSeries, cpuSeries, ramSeries, entitySeries, chunkSeries) { - Highcharts.stockChart(id, { - rangeSelector: { - selected: 2, - buttons: [{ - type: 'hour', - count: 12, - text: '12h' - },{ - type: 'hour', - count: 24, - text: '24h' - },{ - type: 'day', - count: 7, - text: '7d' - },{ - type: 'month', - count: 1, - text: '30d' - },{ - type: 'all', - text: 'All' - }] - }, - title: {text: ''}, - legend: { - enabled: true, + Highcharts.stockChart(id, { + rangeSelector: { + selected: 2, + buttons: [{ + type: 'hour', + count: 12, + text: '12h' + }, { + type: 'hour', + count: 24, + text: '24h' + }, { + type: 'day', + count: 7, + text: '7d' + }, { + type: 'month', + count: 1, + text: '30d' + }, { + type: 'all', + text: 'All' + }] }, - series: [playersOnlineSeries, tpsSeries, cpuSeries, ramSeries, entitySeries, chunkSeries] - }); + title: {text: ''}, + yAxis: [{ + labels: { + formatter: function () { + return this.value + ' P'; + } + } + }, { + opposite: true, + labels: { + formatter: function () { + return this.value + ' TPS'; + } + } + }, { + opposite: true, + labels: { + formatter: function () { + return this.value + '%'; + } + } + }, { + labels: { + formatter: function () { + return this.value + ' MB'; + } + } + }, { + opposite: true, + labels: { + formatter: function () { + return this.value + ' E'; + } + } + }, { + labels: { + formatter: function () { + return this.value + ' C'; + } + } + }], + legend: { + enabled: true + }, + series: [playersOnlineSeries, tpsSeries, cpuSeries, ramSeries, entitySeries, chunkSeries] + }); } \ No newline at end of file diff --git a/Plan/src/main/resources/web/js/charts/punchCard.js b/Plan/src/main/resources/web/js/charts/punchCard.js index a16775f47..f7c3280f9 100644 --- a/Plan/src/main/resources/web/js/charts/punchCard.js +++ b/Plan/src/main/resources/web/js/charts/punchCard.js @@ -1,22 +1,30 @@ function punchCard(id, punchcardSeries) { - Highcharts.chart(id, { - chart: { - defaultSeriesType: 'scatter' - }, - title: {text: ''}, - xAxis: { - type: 'datetime', - dateTimeLabelFormats: { - hour: '%I %P' - }, - tickInterval: 3600000 - }, - yAxis: { - categories: ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'] - }, - tooltip: { - pointFormat: 'Activity: {point.z}' - }, - series: [punchcardSeries] - }); + Highcharts.chart(id, { + chart: { + defaultSeriesType: 'scatter' + }, + title: {text: ''}, + xAxis: { + type: 'datetime', + dateTimeLabelFormats: { + hour: '%I %P', + day: '%H %P' + }, + tickInterval: 3600000 + }, + time: { + timezoneOffset: 0 + }, + yAxis: { + title: { + text: "Day of the Week" + }, + reversed: true, + categories: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] + }, + tooltip: { + pointFormat: 'Activity: {point.z}' + }, + series: [punchcardSeries] + }); } \ No newline at end of file diff --git a/Plan/src/main/resources/web/js/charts/resourceGraph.js b/Plan/src/main/resources/web/js/charts/resourceGraph.js index b949c9ec7..6d411fa63 100644 --- a/Plan/src/main/resources/web/js/charts/resourceGraph.js +++ b/Plan/src/main/resources/web/js/charts/resourceGraph.js @@ -1,40 +1,60 @@ function resourceChart(id, cpuSeries, ramSeries, playersOnlineSeries) { - Highcharts.stockChart(id, { - rangeSelector: { - selected: 1, - buttons: [{ - type: 'hour', - count: 12, - text: '12h' - },{ - type: 'hour', - count: 24, - text: '24h' - },{ - type: 'day', - count: 7, - text: '7d' - },{ - type: 'month', - count: 1, - text: '30d' - },{ - type: 'all', - text: 'All' - }] - }, - tooltip: { - split: true - }, - title: {text: ''}, - plotOptions: { - areaspline: { - fillOpacity: 0.4 - } - }, - legend: { - enabled: true, + Highcharts.stockChart(id, { + rangeSelector: { + selected: 1, + buttons: [{ + type: 'hour', + count: 12, + text: '12h' + }, { + type: 'hour', + count: 24, + text: '24h' + }, { + type: 'day', + count: 7, + text: '7d' + }, { + type: 'month', + count: 1, + text: '30d' + }, { + type: 'all', + text: 'All' + }] }, - series: [cpuSeries, ramSeries, playersOnlineSeries] - }); + tooltip: { + split: true + }, + title: {text: ''}, + plotOptions: { + areaspline: { + fillOpacity: 0.4 + } + }, + yAxis: [{ + labels: { + formatter: function () { + return this.value + ' Players'; + } + } + }, { + opposite: true, + labels: { + formatter: function () { + return this.value + '%'; + } + } + }, { + labels: { + formatter: function () { + return this.value + ' MB'; + } + } + }], + legend: { + enabled: true + }, + series: [cpuSeries, ramSeries, playersOnlineSeries] + }); } \ No newline at end of file diff --git a/Plan/src/main/resources/web/js/charts/activityStackGraph.js b/Plan/src/main/resources/web/js/charts/stackGraph.js similarity index 66% rename from Plan/src/main/resources/web/js/charts/activityStackGraph.js rename to Plan/src/main/resources/web/js/charts/stackGraph.js index c04b8bdce..20cfb987e 100644 --- a/Plan/src/main/resources/web/js/charts/activityStackGraph.js +++ b/Plan/src/main/resources/web/js/charts/stackGraph.js @@ -1,4 +1,4 @@ -function activityStackChart(id, categories, activitySeries) { +function stackChart(id, categories, series, label) { Highcharts.chart(id, { chart: { type: 'area' @@ -15,7 +15,7 @@ function activityStackChart(id, categories, activitySeries) { }, yAxis: { title: { - text: 'Players' + text: label }, labels: { formatter: function () { @@ -25,20 +25,14 @@ function activityStackChart(id, categories, activitySeries) { }, tooltip: { split: true, - valueSuffix: ' Players' + valueSuffix: ' ' + label }, plotOptions: { area: { stacking: 'normal', - // lineColor: '#666666', lineWidth: 1 - // , - // marker: { - // lineWidth: 1, - // lineColor: '#666666' - // } } }, - series: activitySeries + series: series }); } \ No newline at end of file diff --git a/Plan/src/main/resources/web/js/charts/tpsGraph.js b/Plan/src/main/resources/web/js/charts/tpsGraph.js index 5ecb4dd7a..5985a1566 100644 --- a/Plan/src/main/resources/web/js/charts/tpsGraph.js +++ b/Plan/src/main/resources/web/js/charts/tpsGraph.js @@ -1,40 +1,54 @@ function tpsChart(id, tpsSeries, playersOnlineSeries) { - Highcharts.stockChart(id, { - rangeSelector: { - selected: 1, - buttons: [{ - type: 'hour', - count: 12, - text: '12h' - },{ - type: 'hour', - count: 24, - text: '24h' - },{ - type: 'day', - count: 7, - text: '7d' - },{ - type: 'month', - count: 1, - text: '30d' - },{ - type: 'all', - text: 'All' - }] - }, - tooltip: { - split: true - }, - title: {text: ''}, - plotOptions: { - areaspline: { - fillOpacity: 0.4 - } - }, - legend: { - enabled: true, + Highcharts.stockChart(id, { + rangeSelector: { + selected: 1, + buttons: [{ + type: 'hour', + count: 12, + text: '12h' + }, { + type: 'hour', + count: 24, + text: '24h' + }, { + type: 'day', + count: 7, + text: '7d' + }, { + type: 'month', + count: 1, + text: '30d' + }, { + type: 'all', + text: 'All' + }] }, - series: [tpsSeries, playersOnlineSeries] - }); + tooltip: { + split: true + }, + title: {text: ''}, + plotOptions: { + areaspline: { + fillOpacity: 0.4 + } + }, + yAxis: [{ + labels: { + formatter: function () { + return this.value + ' Players'; + } + } + }, { + opposite: true, + labels: { + formatter: function () { + return this.value + ' TPS'; + } + } + }], + legend: { + enabled: true + }, + series: [tpsSeries, playersOnlineSeries] + }); } \ No newline at end of file diff --git a/Plan/src/main/resources/web/js/charts/worldGraph.js b/Plan/src/main/resources/web/js/charts/worldGraph.js index ae0636288..32b85cc66 100644 --- a/Plan/src/main/resources/web/js/charts/worldGraph.js +++ b/Plan/src/main/resources/web/js/charts/worldGraph.js @@ -1,40 +1,60 @@ function worldChart(id, entitySeries, chunkSeries, playersOnlineSeries) { - Highcharts.stockChart(id, { - rangeSelector: { - selected: 1, - buttons: [{ - type: 'hour', - count: 12, - text: '12h' - },{ - type: 'hour', - count: 24, - text: '24h' - },{ - type: 'day', - count: 7, - text: '7d' - },{ - type: 'month', - count: 1, - text: '30d' - },{ - type: 'all', - text: 'All' - }] - }, - tooltip: { - split: true - }, - title: {text: ''}, - plotOptions: { - areaspline: { - fillOpacity: 0.4 - } - }, - legend: { - enabled: true, + Highcharts.stockChart(id, { + rangeSelector: { + selected: 1, + buttons: [{ + type: 'hour', + count: 12, + text: '12h' + }, { + type: 'hour', + count: 24, + text: '24h' + }, { + type: 'day', + count: 7, + text: '7d' + }, { + type: 'month', + count: 1, + text: '30d' + }, { + type: 'all', + text: 'All' + }] }, - series: [entitySeries, chunkSeries, playersOnlineSeries] - }); + tooltip: { + split: true + }, + title: {text: ''}, + plotOptions: { + areaspline: { + fillOpacity: 0.4 + } + }, + yAxis: [{ + labels: { + formatter: function () { + return this.value + ' Players'; + } + } + }, { + opposite: true, + labels: { + formatter: function () { + return this.value + ' Entities'; + } + } + }, { + labels: { + formatter: function () { + return this.value + ' Chunks'; + } + } + }], + legend: { + enabled: true + }, + series: [entitySeries, chunkSeries, playersOnlineSeries] + }); } \ No newline at end of file diff --git a/Plan/src/main/resources/web/js/charts/worldMap.js b/Plan/src/main/resources/web/js/charts/worldMap.js index 797d01c84..db66ebd4e 100644 --- a/Plan/src/main/resources/web/js/charts/worldMap.js +++ b/Plan/src/main/resources/web/js/charts/worldMap.js @@ -4,6 +4,12 @@ function worldMap(id, colorMin, colorMax, mapSeries) { animation: true }, title: {text: ''}, + + mapNavigation: { + enabled: true, + enableDoubleClickZoomTo: true + }, + colorAxis: { min: 1, type: 'logarithmic', diff --git a/Plan/src/main/resources/web/js/charts/worldPie.js b/Plan/src/main/resources/web/js/charts/worldPie.js index 3d72cc926..ccca32c8f 100644 --- a/Plan/src/main/resources/web/js/charts/worldPie.js +++ b/Plan/src/main/resources/web/js/charts/worldPie.js @@ -1,14 +1,25 @@ function worldPie(id, worldSeries, gmSeries) { - Highcharts.chart(id, { + var defaultTitle = ''; + var defaultSubtitle = 'Click the slices to view used GameMode'; + + var chart = Highcharts.chart(id, { chart: { plotBackgroundColor: null, plotBorderWidth: null, plotShadow: false, - type: 'pie' + type: 'pie', + events: { + drilldown: function (e) { + chart.setTitle({text: '' + e.point.name}, {text: ''}); + }, + drillup: function (e) { + chart.setTitle({text: defaultTitle}, {text: defaultSubtitle}); + } + } }, - title: {text: ''}, + title: {text: defaultTitle}, subtitle: { - text: 'Click the slices to view used GameMode' + text: defaultSubtitle }, plotOptions: { pie: { diff --git a/Plan/src/main/resources/web/network.html b/Plan/src/main/resources/web/network.html index be5cb1b74..e3ee8d3e2 100644 --- a/Plan/src/main/resources/web/network.html +++ b/Plan/src/main/resources/web/network.html @@ -305,7 +305,7 @@ - + @@ -317,11 +317,10 @@ - + @@ -588,11 +588,10 @@ - + diff --git a/Plan/src/main/resources/web/plugins/font-awesome/fa-script.js b/Plan/src/main/resources/web/plugins/font-awesome/fa-script.js new file mode 100644 index 000000000..d458e983c --- /dev/null +++ b/Plan/src/main/resources/web/plugins/font-awesome/fa-script.js @@ -0,0 +1,18 @@ +window.FontAwesomeCdnConfig = { + autoA11y: { + enabled: false + }, + asyncLoading: { + enabled: true + }, + reporting: { + + enabled: true, + domains: "localhost, *.dev" + + }, + useUrl: "use.fontawesome.com", + faCdnUrl: "https://cdn.fontawesome.com:443", + code: "df48eb908b" +}; +!function(){function a(a){var b,c=[],d=document,e=d.documentElement.doScroll,f="DOMContentLoaded",g=(e?/^loaded|^c/:/^loaded|^i|^c/).test(d.readyState);g||d.addEventListener(f,b=function(){for(d.removeEventListener(f,b),g=1;b=c.shift();)b()}),g?setTimeout(a,0):c.push(a)}function b(a,b){var c=!1;return a.split(",").forEach(function(a){var d=new RegExp(a.trim().replace(".","\\.").replace("*","(.*)"));b.match(d)&&(c=!0)}),c}function c(a){"undefined"!=typeof MutationObserver&&new MutationObserver(a).observe(document,{childList:!0,subtree:!0})}function d(a){var b,c,d,e;a=a||"fa",b=document.querySelectorAll("."+a),Array.prototype.forEach.call(b,function(a){c=a.getAttribute("title"),a.setAttribute("aria-hidden","true"),d=a.nextElementSibling?!a.nextElementSibling.classList.contains("sr-only"):!0,c&&d&&(e=document.createElement("span"),e.innerHTML=c,e.classList.add("sr-only"),a.parentNode.insertBefore(e,a.nextSibling))})}!function(){"use strict";function a(a){l.push(a),1==l.length&&k()}function b(){for(;l.length;)l[0](),l.shift()}function c(a){this.a=m,this.b=void 0,this.f=[];var b=this;try{a(function(a){f(b,a)},function(a){g(b,a)})}catch(c){g(b,c)}}function d(a){return new c(function(b,c){c(a)})}function e(a){return new c(function(b){b(a)})}function f(a,b){if(a.a==m){if(b==a)throw new TypeError;var c=!1;try{var d=b&&b.then;if(null!=b&&"object"==typeof b&&"function"==typeof d)return void d.call(b,function(b){c||f(a,b),c=!0},function(b){c||g(a,b),c=!0})}catch(e){return void(c||g(a,e))}a.a=0,a.b=b,h(a)}}function g(a,b){if(a.a==m){if(b==a)throw new TypeError;a.a=1,a.b=b,h(a)}}function h(b){a(function(){if(b.a!=m)for(;b.f.length;){var a=b.f.shift(),c=a[0],d=a[1],e=a[2],a=a[3];try{0==b.a?e("function"==typeof c?c.call(void 0,b.b):b.b):1==b.a&&("function"==typeof d?e(d.call(void 0,b.b)):a(b.b))}catch(f){a(f)}}})}function i(a){return new c(function(b,c){function d(c){return function(d){g[c]=d,f+=1,f==a.length&&b(g)}}var f=0,g=[];0==a.length&&b(g);for(var h=0;h=i?b():document.fonts.load(j(f,f.family),h).then(function(b){1<=b.length?a():setTimeout(c,25)},function(){b()})}c()}),o=new Promise(function(a,b){setTimeout(b,i)});Promise.race([o,n]).then(function(){a(f)},function(){e(f)})}else b(function(){function b(){var b;(b=-1!=q&&-1!=r||-1!=q&&-1!=s||-1!=r&&-1!=s)&&((b=q!=r&&q!=s&&r!=s)||(null===k&&(b=/AppleWebKit\/([0-9]+)(?:\.([0-9]+))/.exec(window.navigator.userAgent),k=!!b&&(536>parseInt(b[1],10)||536===parseInt(b[1],10)&&11>=parseInt(b[2],10))),b=k&&(q==t&&r==t&&s==t||q==u&&r==u&&s==u||q==v&&r==v&&s==v)),b=!b),b&&(w.parentNode&&w.parentNode.removeChild(w),clearTimeout(x),a(f))}function m(){if((new Date).getTime()-l>=i)w.parentNode&&w.parentNode.removeChild(w),e(f);else{var a=document.hidden;!0!==a&&void 0!==a||(q=n.a.offsetWidth,r=o.a.offsetWidth,s=p.a.offsetWidth,b()),x=setTimeout(m,50)}}var n=new c(h),o=new c(h),p=new c(h),q=-1,r=-1,s=-1,t=-1,u=-1,v=-1,w=document.createElement("div"),x=0;w.dir="ltr",d(n,j(f,"sans-serif")),d(o,j(f,"serif")),d(p,j(f,"monospace")),w.appendChild(n.a),w.appendChild(o.a),w.appendChild(p.a),document.body.appendChild(w),t=n.a.offsetWidth,u=o.a.offsetWidth,v=p.a.offsetWidth,m(),g(n,function(a){q=a,b()}),d(n,j(f,'"'+f.family+'",sans-serif')),g(o,function(a){r=a,b()}),d(o,j(f,'"'+f.family+'",serif')),g(p,function(a){s=a,b()}),d(p,j(f,'"'+f.family+'",monospace'))})})},f=h}();var g={observe:function(a,b){for(var c=b.prefix,d=function(a){var b=a.weight?"-"+a.weight:"",d=a.style?"-"+a.style:"",e=a.className?"-"+a.className:"",g=a.className?"-"+a.className+b+d:"",h=document.getElementsByTagName("html")[0].classList,i=function(a){h.add(c+e+"-"+a),h.add(c+g+"-"+a)},j=function(a){h.remove(c+e+"-"+a),h.remove(c+g+"-"+a)};i("loading"),new f(a.familyName).load(a.testString).then(function(){i("ready"),j("loading")},function(){i("failed"),j("loading")})},e=0;e0&&t-1 in e}if(!e.jQuery){var r=function(e,t){return new r.fn.init(e,t)};r.isWindow=function(e){return null!=e&&e==e.window},r.type=function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e},r.isArray=Array.isArray||function(e){return"array"===r.type(e)},r.isPlainObject=function(e){var t;if(!e||"object"!==r.type(e)||e.nodeType||r.isWindow(e))return!1;try{if(e.constructor&&!o.call(e,"constructor")&&!o.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(a){return!1}for(t in e);return void 0===t||o.call(e,t)},r.each=function(e,r,a){var n,o=0,i=e.length,s=t(e);if(a){if(s)for(;i>o&&(n=r.apply(e[o],a),n!==!1);o++);else for(o in e)if(n=r.apply(e[o],a),n===!1)break}else if(s)for(;i>o&&(n=r.call(e[o],o,e[o]),n!==!1);o++);else for(o in e)if(n=r.call(e[o],o,e[o]),n===!1)break;return e},r.data=function(e,t,n){if(void 0===n){var o=e[r.expando],i=o&&a[o];if(void 0===t)return i;if(i&&t in i)return i[t]}else if(void 0!==t){var o=e[r.expando]||(e[r.expando]=++r.uuid);return a[o]=a[o]||{},a[o][t]=n,n}},r.removeData=function(e,t){var n=e[r.expando],o=n&&a[n];o&&r.each(t,function(e,t){delete o[t]})},r.extend=function(){var e,t,a,n,o,i,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[l]||{},l++),"object"!=typeof s&&"function"!==r.type(s)&&(s={}),l===u&&(s=this,l--);u>l;l++)if(null!=(o=arguments[l]))for(n in o)e=s[n],a=o[n],s!==a&&(c&&a&&(r.isPlainObject(a)||(t=r.isArray(a)))?(t?(t=!1,i=e&&r.isArray(e)?e:[]):i=e&&r.isPlainObject(e)?e:{},s[n]=r.extend(c,i,a)):void 0!==a&&(s[n]=a));return s},r.queue=function(e,a,n){function o(e,r){var a=r||[];return null!=e&&(t(Object(e))?!function(e,t){for(var r=+t.length,a=0,n=e.length;r>a;)e[n++]=t[a++];if(r!==r)for(;void 0!==t[a];)e[n++]=t[a++];return e.length=n,e}(a,"string"==typeof e?[e]:e):[].push.call(a,e)),a}if(e){a=(a||"fx")+"queue";var i=r.data(e,a);return n?(!i||r.isArray(n)?i=r.data(e,a,o(n)):i.push(n),i):i||[]}},r.dequeue=function(e,t){r.each(e.nodeType?[e]:e,function(e,a){t=t||"fx";var n=r.queue(a,t),o=n.shift();"inprogress"===o&&(o=n.shift()),o&&("fx"===t&&n.unshift("inprogress"),o.call(a,function(){r.dequeue(a,t)}))})},r.fn=r.prototype={init:function(e){if(e.nodeType)return this[0]=e,this;throw new Error("Not a DOM node.")},offset:function(){var t=this[0].getBoundingClientRect?this[0].getBoundingClientRect():{top:0,left:0};return{top:t.top+(e.pageYOffset||document.scrollTop||0)-(document.clientTop||0),left:t.left+(e.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0)}},position:function(){function e(){for(var e=this.offsetParent||document;e&&"html"===!e.nodeType.toLowerCase&&"static"===e.style.position;)e=e.offsetParent;return e||document}var t=this[0],e=e.apply(t),a=this.offset(),n=/^(?:body|html)$/i.test(e.nodeName)?{top:0,left:0}:r(e).offset();return a.top-=parseFloat(t.style.marginTop)||0,a.left-=parseFloat(t.style.marginLeft)||0,e.style&&(n.top+=parseFloat(e.style.borderTopWidth)||0,n.left+=parseFloat(e.style.borderLeftWidth)||0),{top:a.top-n.top,left:a.left-n.left}}};var a={};r.expando="velocity"+(new Date).getTime(),r.uuid=0;for(var n={},o=n.hasOwnProperty,i=n.toString,s="Boolean Number String Function Array Date RegExp Object Error".split(" "),l=0;ln;++n){var o=u(r,e,a);if(0===o)return r;var i=l(r,e,a)-t;r-=i/o}return r}function p(){for(var t=0;b>t;++t)w[t]=l(t*x,e,a)}function f(t,r,n){var o,i,s=0;do i=r+(n-r)/2,o=l(i,e,a)-t,o>0?n=i:r=i;while(Math.abs(o)>h&&++s=y?c(t,s):0==l?s:f(t,r,r+x)}function g(){V=!0,(e!=r||a!=n)&&p()}var m=4,y=.001,h=1e-7,v=10,b=11,x=1/(b-1),S="Float32Array"in t;if(4!==arguments.length)return!1;for(var P=0;4>P;++P)if("number"!=typeof arguments[P]||isNaN(arguments[P])||!isFinite(arguments[P]))return!1;e=Math.min(e,1),a=Math.min(a,1),e=Math.max(e,0),a=Math.max(a,0);var w=S?new Float32Array(b):new Array(b),V=!1,C=function(t){return V||g(),e===r&&a===n?t:0===t?0:1===t?1:l(d(t),r,n)};C.getControlPoints=function(){return[{x:e,y:r},{x:a,y:n}]};var T="generateBezier("+[e,r,a,n]+")";return C.toString=function(){return T},C}function u(e,t){var r=e;return m.isString(e)?b.Easings[e]||(r=!1):r=m.isArray(e)&&1===e.length?s.apply(null,e):m.isArray(e)&&2===e.length?x.apply(null,e.concat([t])):m.isArray(e)&&4===e.length?l.apply(null,e):!1,r===!1&&(r=b.Easings[b.defaults.easing]?b.defaults.easing:v),r}function c(e){if(e){var t=(new Date).getTime(),r=b.State.calls.length;r>1e4&&(b.State.calls=n(b.State.calls));for(var o=0;r>o;o++)if(b.State.calls[o]){var s=b.State.calls[o],l=s[0],u=s[2],d=s[3],g=!!d,y=null;d||(d=b.State.calls[o][3]=t-16);for(var h=Math.min((t-d)/u.duration,1),v=0,x=l.length;x>v;v++){var P=l[v],V=P.element;if(i(V)){var C=!1;if(u.display!==a&&null!==u.display&&"none"!==u.display){if("flex"===u.display){var T=["-webkit-box","-moz-box","-ms-flexbox","-webkit-flex"];f.each(T,function(e,t){S.setPropertyValue(V,"display",t)})}S.setPropertyValue(V,"display",u.display)}u.visibility!==a&&"hidden"!==u.visibility&&S.setPropertyValue(V,"visibility",u.visibility);for(var k in P)if("element"!==k){var A,F=P[k],j=m.isString(F.easing)?b.Easings[F.easing]:F.easing;if(1===h)A=F.endValue;else{var E=F.endValue-F.startValue;if(A=F.startValue+E*j(h,u,E),!g&&A===F.currentValue)continue}if(F.currentValue=A,"tween"===k)y=A;else{if(S.Hooks.registered[k]){var H=S.Hooks.getRoot(k),N=i(V).rootPropertyValueCache[H];N&&(F.rootPropertyValue=N)}var L=S.setPropertyValue(V,k,F.currentValue+(0===parseFloat(A)?"":F.unitType),F.rootPropertyValue,F.scrollData);S.Hooks.registered[k]&&(i(V).rootPropertyValueCache[H]=S.Normalizations.registered[H]?S.Normalizations.registered[H]("extract",null,L[1]):L[1]),"transform"===L[0]&&(C=!0)}}u.mobileHA&&i(V).transformCache.translate3d===a&&(i(V).transformCache.translate3d="(0px, 0px, 0px)",C=!0),C&&S.flushTransformCache(V)}}u.display!==a&&"none"!==u.display&&(b.State.calls[o][2].display=!1),u.visibility!==a&&"hidden"!==u.visibility&&(b.State.calls[o][2].visibility=!1),u.progress&&u.progress.call(s[1],s[1],h,Math.max(0,d+u.duration-t),d,y),1===h&&p(o)}}b.State.isTicking&&w(c)}function p(e,t){if(!b.State.calls[e])return!1;for(var r=b.State.calls[e][0],n=b.State.calls[e][1],o=b.State.calls[e][2],s=b.State.calls[e][4],l=!1,u=0,c=r.length;c>u;u++){var p=r[u].element;if(t||o.loop||("none"===o.display&&S.setPropertyValue(p,"display",o.display),"hidden"===o.visibility&&S.setPropertyValue(p,"visibility",o.visibility)),o.loop!==!0&&(f.queue(p)[1]===a||!/\.velocityQueueEntryFlag/i.test(f.queue(p)[1]))&&i(p)){i(p).isAnimating=!1,i(p).rootPropertyValueCache={};var d=!1;f.each(S.Lists.transforms3D,function(e,t){var r=/^scale/.test(t)?1:0,n=i(p).transformCache[t];i(p).transformCache[t]!==a&&new RegExp("^\\("+r+"[^.]").test(n)&&(d=!0,delete i(p).transformCache[t])}),o.mobileHA&&(d=!0,delete i(p).transformCache.translate3d),d&&S.flushTransformCache(p),S.Values.removeClass(p,"velocity-animating")}if(!t&&o.complete&&!o.loop&&u===c-1)try{o.complete.call(n,n)}catch(g){setTimeout(function(){throw g},1)}s&&o.loop!==!0&&s(n),i(p)&&o.loop===!0&&!t&&(f.each(i(p).tweensContainer,function(e,t){/^rotate/.test(e)&&360===parseFloat(t.endValue)&&(t.endValue=0,t.startValue=360),/^backgroundPosition/.test(e)&&100===parseFloat(t.endValue)&&"%"===t.unitType&&(t.endValue=0,t.startValue=100)}),b(p,"reverse",{loop:!0,delay:o.delay})),o.queue!==!1&&f.dequeue(p,o.queue)}b.State.calls[e]=!1;for(var m=0,y=b.State.calls.length;y>m;m++)if(b.State.calls[m]!==!1){l=!0;break}l===!1&&(b.State.isTicking=!1,delete b.State.calls,b.State.calls=[])}var f,d=function(){if(r.documentMode)return r.documentMode;for(var e=7;e>4;e--){var t=r.createElement("div");if(t.innerHTML="",t.getElementsByTagName("span").length)return t=null,e}return a}(),g=function(){var e=0;return t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||function(t){var r,a=(new Date).getTime();return r=Math.max(0,16-(a-e)),e=a+r,setTimeout(function(){t(a+r)},r)}}(),m={isString:function(e){return"string"==typeof e},isArray:Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},isFunction:function(e){return"[object Function]"===Object.prototype.toString.call(e)},isNode:function(e){return e&&e.nodeType},isNodeList:function(e){return"object"==typeof e&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(e))&&e.length!==a&&(0===e.length||"object"==typeof e[0]&&e[0].nodeType>0)},isWrapped:function(e){return e&&(e.jquery||t.Zepto&&t.Zepto.zepto.isZ(e))},isSVG:function(e){return t.SVGElement&&e instanceof t.SVGElement},isEmptyObject:function(e){for(var t in e)return!1;return!0}},y=!1;if(e.fn&&e.fn.jquery?(f=e,y=!0):f=t.Velocity.Utilities,8>=d&&!y)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(7>=d)return void(jQuery.fn.velocity=jQuery.fn.animate);var h=400,v="swing",b={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:t.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:r.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:f,Redirects:{},Easings:{},Promise:t.Promise,defaults:{queue:"",duration:h,easing:v,begin:a,complete:a,progress:a,display:a,visibility:a,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0},init:function(e){f.data(e,"velocity",{isSVG:m.isSVG(e),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:2,patch:2},debug:!1};t.pageYOffset!==a?(b.State.scrollAnchor=t,b.State.scrollPropertyLeft="pageXOffset",b.State.scrollPropertyTop="pageYOffset"):(b.State.scrollAnchor=r.documentElement||r.body.parentNode||r.body,b.State.scrollPropertyLeft="scrollLeft",b.State.scrollPropertyTop="scrollTop");var x=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,r,a){var n={x:t.x+a.dx*r,v:t.v+a.dv*r,tension:t.tension,friction:t.friction};return{dx:n.v,dv:e(n)}}function r(r,a){var n={dx:r.v,dv:e(r)},o=t(r,.5*a,n),i=t(r,.5*a,o),s=t(r,a,i),l=1/6*(n.dx+2*(o.dx+i.dx)+s.dx),u=1/6*(n.dv+2*(o.dv+i.dv)+s.dv);return r.x=r.x+l*a,r.v=r.v+u*a,r}return function a(e,t,n){var o,i,s,l={x:-1,v:0,tension:null,friction:null},u=[0],c=0,p=1e-4,f=.016;for(e=parseFloat(e)||500,t=parseFloat(t)||20,n=n||null,l.tension=e,l.friction=t,o=null!==n,o?(c=a(e,t),i=c/n*f):i=f;s=r(s||l,i),u.push(1+s.x),c+=16,Math.abs(s.x)>p&&Math.abs(s.v)>p;);return o?function(e){return u[e*(u.length-1)|0]}:c}}();b.Easings={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},spring:function(e){return 1-Math.cos(4.5*e*Math.PI)*Math.exp(6*-e)}},f.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(e,t){b.Easings[t[0]]=l.apply(null,t[1])});var S=b.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var e=0;e=d)switch(e){case"name":return"filter";case"extract":var a=r.toString().match(/alpha\(opacity=(.*)\)/i);return r=a?a[1]/100:1;case"inject":return t.style.zoom=1,parseFloat(r)>=1?"":"alpha(opacity="+parseInt(100*parseFloat(r),10)+")"}else switch(e){case"name":return"opacity";case"extract":return r;case"inject":return r}}},register:function(){9>=d||b.State.isGingerbread||(S.Lists.transformsBase=S.Lists.transformsBase.concat(S.Lists.transforms3D));for(var e=0;en&&(n=1),o=!/(\d)$/i.test(n);break;case"skew":o=!/(deg|\d)$/i.test(n);break;case"rotate":o=!/(deg|\d)$/i.test(n)}return o||(i(r).transformCache[t]="("+n+")"),i(r).transformCache[t]}}}();for(var e=0;e=d||3!==o.split(" ").length||(o+=" 1"),o;case"inject":return 8>=d?4===n.split(" ").length&&(n=n.split(/\s+/).slice(0,3).join(" ")):3===n.split(" ").length&&(n+=" 1"),(8>=d?"rgb":"rgba")+"("+n.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")"}}}()}},Names:{camelCase:function(e){return e.replace(/-(\w)/g,function(e,t){return t.toUpperCase()})},SVGAttribute:function(e){var t="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(d||b.State.isAndroid&&!b.State.isChrome)&&(t+="|transform"),new RegExp("^("+t+")$","i").test(e)},prefixCheck:function(e){if(b.State.prefixMatches[e])return[b.State.prefixMatches[e],!0];for(var t=["","Webkit","Moz","ms","O"],r=0,a=t.length;a>r;r++){var n;if(n=0===r?e:t[r]+e.replace(/^\w/,function(e){return e.toUpperCase()}),m.isString(b.State.prefixElement.style[n]))return b.State.prefixMatches[e]=n,[n,!0]}return[e,!1]}},Values:{hexToRgb:function(e){var t,r=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;return e=e.replace(r,function(e,t,r,a){return t+t+r+r+a+a}),t=a.exec(e),t?[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]:[0,0,0]},isCSSNullValue:function(e){return 0==e||/^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(e)},getUnitType:function(e){return/^(rotate|skew)/i.test(e)?"deg":/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(e)?"":"px"},getDisplayType:function(e){var t=e&&e.tagName.toString().toLowerCase();return/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(t)?"inline":/^(li)$/i.test(t)?"list-item":/^(tr)$/i.test(t)?"table-row":/^(table)$/i.test(t)?"table":/^(tbody)$/i.test(t)?"table-row-group":"block"},addClass:function(e,t){e.classList?e.classList.add(t):e.className+=(e.className.length?" ":"")+t},removeClass:function(e,t){e.classList?e.classList.remove(t):e.className=e.className.toString().replace(new RegExp("(^|\\s)"+t.split(" ").join("|")+"(\\s|$)","gi")," ")}},getPropertyValue:function(e,r,n,o){function s(e,r){function n(){u&&S.setPropertyValue(e,"display","none")}var l=0;if(8>=d)l=f.css(e,r);else{var u=!1;if(/^(width|height)$/.test(r)&&0===S.getPropertyValue(e,"display")&&(u=!0,S.setPropertyValue(e,"display",S.Values.getDisplayType(e))),!o){if("height"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var c=e.offsetHeight-(parseFloat(S.getPropertyValue(e,"borderTopWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderBottomWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingTop"))||0)-(parseFloat(S.getPropertyValue(e,"paddingBottom"))||0);return n(),c}if("width"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var p=e.offsetWidth-(parseFloat(S.getPropertyValue(e,"borderLeftWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderRightWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingLeft"))||0)-(parseFloat(S.getPropertyValue(e,"paddingRight"))||0);return n(),p}}var g;g=i(e)===a?t.getComputedStyle(e,null):i(e).computedStyle?i(e).computedStyle:i(e).computedStyle=t.getComputedStyle(e,null),"borderColor"===r&&(r="borderTopColor"),l=9===d&&"filter"===r?g.getPropertyValue(r):g[r],(""===l||null===l)&&(l=e.style[r]),n()}if("auto"===l&&/^(top|right|bottom|left)$/i.test(r)){var m=s(e,"position");("fixed"===m||"absolute"===m&&/top|left/i.test(r))&&(l=f(e).position()[r]+"px")}return l}var l;if(S.Hooks.registered[r]){var u=r,c=S.Hooks.getRoot(u);n===a&&(n=S.getPropertyValue(e,S.Names.prefixCheck(c)[0])),S.Normalizations.registered[c]&&(n=S.Normalizations.registered[c]("extract",e,n)),l=S.Hooks.extractValue(u,n)}else if(S.Normalizations.registered[r]){var p,g;p=S.Normalizations.registered[r]("name",e),"transform"!==p&&(g=s(e,S.Names.prefixCheck(p)[0]),S.Values.isCSSNullValue(g)&&S.Hooks.templates[r]&&(g=S.Hooks.templates[r][1])),l=S.Normalizations.registered[r]("extract",e,g)}if(!/^[\d-]/.test(l))if(i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r))if(/^(height|width)$/i.test(r))try{l=e.getBBox()[r]}catch(m){l=0}else l=e.getAttribute(r);else l=s(e,S.Names.prefixCheck(r)[0]);return S.Values.isCSSNullValue(l)&&(l=0),b.debug>=2&&console.log("Get "+r+": "+l),l},setPropertyValue:function(e,r,a,n,o){var s=r;if("scroll"===r)o.container?o.container["scroll"+o.direction]=a:"Left"===o.direction?t.scrollTo(a,o.alternateValue):t.scrollTo(o.alternateValue,a);else if(S.Normalizations.registered[r]&&"transform"===S.Normalizations.registered[r]("name",e))S.Normalizations.registered[r]("inject",e,a),s="transform",a=i(e).transformCache[r];else{if(S.Hooks.registered[r]){var l=r,u=S.Hooks.getRoot(r);n=n||S.getPropertyValue(e,u),a=S.Hooks.injectValue(l,a,n),r=u}if(S.Normalizations.registered[r]&&(a=S.Normalizations.registered[r]("inject",e,a),r=S.Normalizations.registered[r]("name",e)),s=S.Names.prefixCheck(r)[0],8>=d)try{e.style[s]=a}catch(c){b.debug&&console.log("Browser does not support ["+a+"] for ["+s+"]")}else i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r)?e.setAttribute(r,a):e.style[s]=a;b.debug>=2&&console.log("Set "+r+" ("+s+"): "+a)}return[s,a]},flushTransformCache:function(e){function t(t){return parseFloat(S.getPropertyValue(e,t))}var r="";if((d||b.State.isAndroid&&!b.State.isChrome)&&i(e).isSVG){var a={translate:[t("translateX"),t("translateY")],skewX:[t("skewX")],skewY:[t("skewY")],scale:1!==t("scale")?[t("scale"),t("scale")]:[t("scaleX"),t("scaleY")],rotate:[t("rotateZ"),0,0]};f.each(i(e).transformCache,function(e){/^translate/i.test(e)?e="translate":/^scale/i.test(e)?e="scale":/^rotate/i.test(e)&&(e="rotate"),a[e]&&(r+=e+"("+a[e].join(" ")+") ",delete a[e])})}else{var n,o;f.each(i(e).transformCache,function(t){return n=i(e).transformCache[t],"transformPerspective"===t?(o=n,!0):(9===d&&"rotateZ"===t&&(t="rotate"),void(r+=t+n+" "))}),o&&(r="perspective"+o+" "+r)}S.setPropertyValue(e,"transform",r)}};S.Hooks.register(),S.Normalizations.register(),b.hook=function(e,t,r){var n=a;return e=o(e),f.each(e,function(e,o){if(i(o)===a&&b.init(o),r===a)n===a&&(n=b.CSS.getPropertyValue(o,t));else{var s=b.CSS.setPropertyValue(o,t,r);"transform"===s[0]&&b.CSS.flushTransformCache(o),n=s}}),n};var P=function(){function e(){return s?k.promise||null:l}function n(){function e(e){function p(e,t){var r=a,n=a,i=a;return m.isArray(e)?(r=e[0],!m.isArray(e[1])&&/^[\d-]/.test(e[1])||m.isFunction(e[1])||S.RegEx.isHex.test(e[1])?i=e[1]:(m.isString(e[1])&&!S.RegEx.isHex.test(e[1])||m.isArray(e[1]))&&(n=t?e[1]:u(e[1],s.duration),e[2]!==a&&(i=e[2]))):r=e,t||(n=n||s.easing),m.isFunction(r)&&(r=r.call(o,V,w)),m.isFunction(i)&&(i=i.call(o,V,w)),[r||0,n,i]}function d(e,t){var r,a;return a=(t||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(e){return r=e,""}),r||(r=S.Values.getUnitType(e)),[a,r]}function h(){var e={myParent:o.parentNode||r.body,position:S.getPropertyValue(o,"position"),fontSize:S.getPropertyValue(o,"fontSize")},a=e.position===L.lastPosition&&e.myParent===L.lastParent,n=e.fontSize===L.lastFontSize;L.lastParent=e.myParent,L.lastPosition=e.position,L.lastFontSize=e.fontSize;var s=100,l={};if(n&&a)l.emToPx=L.lastEmToPx,l.percentToPxWidth=L.lastPercentToPxWidth,l.percentToPxHeight=L.lastPercentToPxHeight;else{var u=i(o).isSVG?r.createElementNS("http://www.w3.org/2000/svg","rect"):r.createElement("div");b.init(u),e.myParent.appendChild(u),f.each(["overflow","overflowX","overflowY"],function(e,t){b.CSS.setPropertyValue(u,t,"hidden")}),b.CSS.setPropertyValue(u,"position",e.position),b.CSS.setPropertyValue(u,"fontSize",e.fontSize),b.CSS.setPropertyValue(u,"boxSizing","content-box"),f.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(e,t){b.CSS.setPropertyValue(u,t,s+"%")}),b.CSS.setPropertyValue(u,"paddingLeft",s+"em"),l.percentToPxWidth=L.lastPercentToPxWidth=(parseFloat(S.getPropertyValue(u,"width",null,!0))||1)/s,l.percentToPxHeight=L.lastPercentToPxHeight=(parseFloat(S.getPropertyValue(u,"height",null,!0))||1)/s,l.emToPx=L.lastEmToPx=(parseFloat(S.getPropertyValue(u,"paddingLeft"))||1)/s,e.myParent.removeChild(u)}return null===L.remToPx&&(L.remToPx=parseFloat(S.getPropertyValue(r.body,"fontSize"))||16),null===L.vwToPx&&(L.vwToPx=parseFloat(t.innerWidth)/100,L.vhToPx=parseFloat(t.innerHeight)/100),l.remToPx=L.remToPx,l.vwToPx=L.vwToPx,l.vhToPx=L.vhToPx,b.debug>=1&&console.log("Unit ratios: "+JSON.stringify(l),o),l}if(s.begin&&0===V)try{s.begin.call(g,g)}catch(x){setTimeout(function(){throw x},1)}if("scroll"===A){var P,C,T,F=/^x$/i.test(s.axis)?"Left":"Top",j=parseFloat(s.offset)||0;s.container?m.isWrapped(s.container)||m.isNode(s.container)?(s.container=s.container[0]||s.container,P=s.container["scroll"+F],T=P+f(o).position()[F.toLowerCase()]+j):s.container=null:(P=b.State.scrollAnchor[b.State["scrollProperty"+F]],C=b.State.scrollAnchor[b.State["scrollProperty"+("Left"===F?"Top":"Left")]],T=f(o).offset()[F.toLowerCase()]+j),l={scroll:{rootPropertyValue:!1,startValue:P,currentValue:P,endValue:T,unitType:"",easing:s.easing,scrollData:{container:s.container,direction:F,alternateValue:C}},element:o},b.debug&&console.log("tweensContainer (scroll): ",l.scroll,o)}else if("reverse"===A){if(!i(o).tweensContainer)return void f.dequeue(o,s.queue);"none"===i(o).opts.display&&(i(o).opts.display="auto"),"hidden"===i(o).opts.visibility&&(i(o).opts.visibility="visible"),i(o).opts.loop=!1,i(o).opts.begin=null,i(o).opts.complete=null,v.easing||delete s.easing,v.duration||delete s.duration,s=f.extend({},i(o).opts,s);var E=f.extend(!0,{},i(o).tweensContainer);for(var H in E)if("element"!==H){var N=E[H].startValue;E[H].startValue=E[H].currentValue=E[H].endValue,E[H].endValue=N,m.isEmptyObject(v)||(E[H].easing=s.easing),b.debug&&console.log("reverse tweensContainer ("+H+"): "+JSON.stringify(E[H]),o)}l=E}else if("start"===A){var E;i(o).tweensContainer&&i(o).isAnimating===!0&&(E=i(o).tweensContainer),f.each(y,function(e,t){if(RegExp("^"+S.Lists.colors.join("$|^")+"$").test(e)){var r=p(t,!0),n=r[0],o=r[1],i=r[2];if(S.RegEx.isHex.test(n)){for(var s=["Red","Green","Blue"],l=S.Values.hexToRgb(n),u=i?S.Values.hexToRgb(i):a,c=0;cO;O++){var q={delay:j.delay,progress:j.progress};O===z-1&&(q.display=j.display,q.visibility=j.visibility,q.complete=j.complete),P(g,"reverse",q)}return e()}};b=f.extend(P,b),b.animate=P;var w=t.requestAnimationFrame||g;return b.State.isMobile||r.hidden===a||r.addEventListener("visibilitychange",function(){r.hidden?(w=function(e){return setTimeout(function(){e(!0)},16)},c()):w=t.requestAnimationFrame||g}),e.Velocity=b,e!==t&&(e.fn.velocity=P,e.fn.velocity.defaults=b.defaults),f.each(["Down","Up"],function(e,t){b.Redirects["slide"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u=l.begin,c=l.complete,p={height:"",marginTop:"",marginBottom:"",paddingTop:"",paddingBottom:""},d={};l.display===a&&(l.display="Down"===t?"inline"===b.CSS.Values.getDisplayType(e)?"inline-block":"block":"none"),l.begin=function(){u&&u.call(i,i);for(var r in p){d[r]=e.style[r];var a=b.CSS.getPropertyValue(e,r);p[r]="Down"===t?[a,0]:[0,a]}d.overflow=e.style.overflow,e.style.overflow="hidden"},l.complete=function(){for(var t in d)e.style[t]=d[t];c&&c.call(i,i),s&&s.resolver(i)},b(e,p,l)}}),f.each(["In","Out"],function(e,t){b.Redirects["fade"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u={opacity:"In"===t?1:0},c=l.complete;l.complete=n!==o-1?l.begin=null:function(){c&&c.call(i,i),s&&s.resolver(i)},l.display===a&&(l.display="In"===t?"auto":"none"),b(this,u,l)}}),b}(window.jQuery||window.Zepto||window,window,document)})); -;!function(a,b,c,d){"use strict";function k(a,b,c){return setTimeout(q(a,c),b)}function l(a,b,c){return Array.isArray(a)?(m(a,c[b],c),!0):!1}function m(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e-1}function x(a){return a.trim().split(/\s+/g)}function y(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;dc[b]}):d.sort()),d}function B(a,b){for(var c,f,g=b[0].toUpperCase()+b.slice(1),h=0;h1&&!c.firstMultiple?c.firstMultiple=gb(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=hb(d);b.timeStamp=j(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=lb(h,i),b.distance=kb(h,i),eb(c,b),b.offsetDirection=jb(b.deltaX,b.deltaY),b.scale=g?nb(g.pointers,d):1,b.rotation=g?mb(g.pointers,d):0,fb(c,b);var k=a.element;v(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function eb(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};(b.eventType===O||f.eventType===Q)&&(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function fb(a,b){var f,g,h,j,c=a.lastInterval||b,e=b.timeStamp-c.timeStamp;if(b.eventType!=R&&(e>N||c.velocity===d)){var k=c.deltaX-b.deltaX,l=c.deltaY-b.deltaY,m=ib(e,k,l);g=m.x,h=m.y,f=i(m.x)>i(m.y)?m.x:m.y,j=jb(k,l),a.lastInterval=b}else f=c.velocity,g=c.velocityX,h=c.velocityY,j=c.direction;b.velocity=f,b.velocityX=g,b.velocityY=h,b.direction=j}function gb(a){for(var b=[],c=0;ce;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:h(c/b),y:h(d/b)}}function ib(a,b,c){return{x:b/a||0,y:c/a||0}}function jb(a,b){return a===b?S:i(a)>=i(b)?a>0?T:U:b>0?V:W}function kb(a,b,c){c||(c=$);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function lb(a,b,c){c||(c=$);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function mb(a,b){return lb(b[1],b[0],_)-lb(a[1],a[0],_)}function nb(a,b){return kb(b[0],b[1],_)/kb(a[0],a[1],_)}function rb(){this.evEl=pb,this.evWin=qb,this.allow=!0,this.pressed=!1,ab.apply(this,arguments)}function wb(){this.evEl=ub,this.evWin=vb,ab.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function Ab(){this.evTarget=yb,this.evWin=zb,this.started=!1,ab.apply(this,arguments)}function Bb(a,b){var c=z(a.touches),d=z(a.changedTouches);return b&(Q|R)&&(c=A(c.concat(d),"identifier",!0)),[c,d]}function Eb(){this.evTarget=Db,this.targetIds={},ab.apply(this,arguments)}function Fb(a,b){var c=z(a.touches),d=this.targetIds;if(b&(O|P)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=z(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return v(a.target,i)}),b===O)for(e=0;eh&&(b.push(a),h=b.length-1):e&(Q|R)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var xb={touchstart:O,touchmove:P,touchend:Q,touchcancel:R},yb="touchstart",zb="touchstart touchmove touchend touchcancel";p(Ab,ab,{handler:function(a){var b=xb[a.type];if(b===O&&(this.started=!0),this.started){var c=Bb.call(this,a,b);b&(Q|R)&&0===c[0].length-c[1].length&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:J,srcEvent:a})}}});var Cb={touchstart:O,touchmove:P,touchend:Q,touchcancel:R},Db="touchstart touchmove touchend touchcancel";p(Eb,ab,{handler:function(a){var b=Cb[a.type],c=Fb.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:J,srcEvent:a})}}),p(Gb,ab,{handler:function(a,b,c){var d=c.pointerType==J,e=c.pointerType==L;if(d)this.mouse.allow=!1;else if(e&&!this.mouse.allow)return;b&(Q|R)&&(this.mouse.allow=!0),this.callback(a,b,c)},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var Hb=B(f.style,"touchAction"),Ib=Hb!==d,Jb="compute",Kb="auto",Lb="manipulation",Mb="none",Nb="pan-x",Ob="pan-y";Pb.prototype={set:function(a){a==Jb&&(a=this.compute()),Ib&&(this.manager.element.style[Hb]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return m(this.manager.recognizers,function(b){r(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),Qb(a.join(" "))},preventDefaults:function(a){if(!Ib){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return b.preventDefault(),void 0;var d=this.actions,e=w(d,Mb),f=w(d,Ob),g=w(d,Nb);return e||f&&c&X||g&&c&Y?this.preventSrc(b):void 0}},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var Rb=1,Sb=2,Tb=4,Ub=8,Vb=Ub,Wb=16,Xb=32;Yb.prototype={defaults:{},set:function(a){return n(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(l(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=_b(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return l(a,"dropRecognizeWith",this)?this:(a=_b(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(l(a,"requireFailure",this))return this;var b=this.requireFail;return a=_b(a,this),-1===y(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(l(a,"dropRequireFailure",this))return this;a=_b(a,this);var b=y(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function d(d){b.manager.emit(b.options.event+(d?Zb(c):""),a)}var b=this,c=this.state;Ub>c&&d(!0),d(),c>=Ub&&d(!0)},tryEmit:function(a){return this.canEmit()?this.emit(a):(this.state=Xb,void 0)},canEmit:function(){for(var a=0;af?T:U,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?S:0>g?V:W,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return ac.prototype.attrTest.call(this,a)&&(this.state&Sb||!(this.state&Sb)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=$b(a.direction);b&&this.manager.emit(this.options.event+b,a),this._super.emit.call(this,a)}}),p(cc,ac,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[Mb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&Sb)},emit:function(a){if(this._super.emit.call(this,a),1!==a.scale){var b=a.scale<1?"in":"out";this.manager.emit(this.options.event+b,a)}}}),p(dc,Yb,{defaults:{event:"press",pointers:1,time:500,threshold:5},getTouchAction:function(){return[Kb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distanceb.time;if(this._input=a,!d||!c||a.eventType&(Q|R)&&!e)this.reset();else if(a.eventType&O)this.reset(),this._timer=k(function(){this.state=Vb,this.tryEmit()},b.time,this);else if(a.eventType&Q)return Vb;return Xb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===Vb&&(a&&a.eventType&Q?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=j(),this.manager.emit(this.options.event,this._input)))}}),p(ec,ac,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[Mb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&Sb)}}),p(fc,ac,{defaults:{event:"swipe",threshold:10,velocity:.65,direction:X|Y,pointers:1},getTouchAction:function(){return bc.prototype.getTouchAction.call(this)},attrTest:function(a){var c,b=this.options.direction;return b&(X|Y)?c=a.velocity:b&X?c=a.velocityX:b&Y&&(c=a.velocityY),this._super.attrTest.call(this,a)&&b&a.direction&&a.distance>this.options.threshold&&i(c)>this.options.velocity&&a.eventType&Q},emit:function(a){var b=$b(a.direction);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),p(gc,Yb,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:2,posThreshold:10},getTouchAction:function(){return[Lb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance -1 + } + + function x(a) { + return a.trim().split(/\s+/g) + } + + function y(a, b, c) { + if (a.indexOf && !c) return a.indexOf(b); + for (var d = 0; d < a.length;) { + if (c && a[d][c] == b || !c && a[d] === b) return d; + d++ + } + return -1 + } + + function z(a) { + return Array.prototype.slice.call(a, 0) + } + + function A(a, b, c) { + for (var d = [], e = [], f = 0; f < a.length;) { + var g = b ? a[f][b] : a[f]; + y(e, g) < 0 && d.push(a[f]), e[f] = g, f++ + } + return c && (d = b ? d.sort(function (a, c) { + return a[b] > c[b] + }) : d.sort()), d + } + + function B(a, b) { + for (var c, f, g = b[0].toUpperCase() + b.slice(1), h = 0; h < e.length;) { + if (c = e[h], f = c ? c + g : b, f in a) return f; + h++ + } + return d + } + + function D() { + return C++ + } + + function E(a) { + var b = a.ownerDocument; + return b.defaultView || b.parentWindow + } + + function ab(a, b) { + var c = this; + this.manager = a, this.callback = b, this.element = a.element, this.target = a.options.inputTarget, this.domHandler = function (b) { + r(a.options.enable, [a]) && c.handler(b) + }, this.init() + } + + function bb(a) { + var b, c = a.options.inputClass; + return b = c ? c : H ? wb : I ? Eb : G ? Gb : rb, new b(a, cb) + } + + function cb(a, b, c) { + var d = c.pointers.length, e = c.changedPointers.length, f = b & O && 0 === d - e, + g = b & (Q | R) && 0 === d - e; + c.isFirst = !!f, c.isFinal = !!g, f && (a.session = {}), c.eventType = b, db(a, c), a.emit("hammer.input", c), a.recognize(c), a.session.prevInput = c + } + + function db(a, b) { + var c = a.session, d = b.pointers, e = d.length; + c.firstInput || (c.firstInput = gb(b)), e > 1 && !c.firstMultiple ? c.firstMultiple = gb(b) : 1 === e && (c.firstMultiple = !1); + var f = c.firstInput, g = c.firstMultiple, h = g ? g.center : f.center, i = b.center = hb(d); + b.timeStamp = j(), b.deltaTime = b.timeStamp - f.timeStamp, b.angle = lb(h, i), b.distance = kb(h, i), eb(c, b), b.offsetDirection = jb(b.deltaX, b.deltaY), b.scale = g ? nb(g.pointers, d) : 1, b.rotation = g ? mb(g.pointers, d) : 0, fb(c, b); + var k = a.element; + v(b.srcEvent.target, k) && (k = b.srcEvent.target), b.target = k + } + + function eb(a, b) { + var c = b.center, d = a.offsetDelta || {}, e = a.prevDelta || {}, f = a.prevInput || {}; + (b.eventType === O || f.eventType === Q) && (e = a.prevDelta = { + x: f.deltaX || 0, + y: f.deltaY || 0 + }, d = a.offsetDelta = {x: c.x, y: c.y}), b.deltaX = e.x + (c.x - d.x), b.deltaY = e.y + (c.y - d.y) + } + + function fb(a, b) { + var f, g, h, j, c = a.lastInterval || b, e = b.timeStamp - c.timeStamp; + if (b.eventType != R && (e > N || c.velocity === d)) { + var k = c.deltaX - b.deltaX, l = c.deltaY - b.deltaY, m = ib(e, k, l); + g = m.x, h = m.y, f = i(m.x) > i(m.y) ? m.x : m.y, j = jb(k, l), a.lastInterval = b + } else f = c.velocity, g = c.velocityX, h = c.velocityY, j = c.direction; + b.velocity = f, b.velocityX = g, b.velocityY = h, b.direction = j + } + + function gb(a) { + for (var b = [], c = 0; c < a.pointers.length;) b[c] = { + clientX: h(a.pointers[c].clientX), + clientY: h(a.pointers[c].clientY) + }, c++; + return {timeStamp: j(), pointers: b, center: hb(b), deltaX: a.deltaX, deltaY: a.deltaY} + } + + function hb(a) { + var b = a.length; + if (1 === b) return {x: h(a[0].clientX), y: h(a[0].clientY)}; + for (var c = 0, d = 0, e = 0; b > e;) c += a[e].clientX, d += a[e].clientY, e++; + return {x: h(c / b), y: h(d / b)} + } + + function ib(a, b, c) { + return {x: b / a || 0, y: c / a || 0} + } + + function jb(a, b) { + return a === b ? S : i(a) >= i(b) ? a > 0 ? T : U : b > 0 ? V : W + } + + function kb(a, b, c) { + c || (c = $); + var d = b[c[0]] - a[c[0]], e = b[c[1]] - a[c[1]]; + return Math.sqrt(d * d + e * e) + } + + function lb(a, b, c) { + c || (c = $); + var d = b[c[0]] - a[c[0]], e = b[c[1]] - a[c[1]]; + return 180 * Math.atan2(e, d) / Math.PI + } + + function mb(a, b) { + return lb(b[1], b[0], _) - lb(a[1], a[0], _) + } + + function nb(a, b) { + return kb(b[0], b[1], _) / kb(a[0], a[1], _) + } + + function rb() { + this.evEl = pb, this.evWin = qb, this.allow = !0, this.pressed = !1, ab.apply(this, arguments) + } + + function wb() { + this.evEl = ub, this.evWin = vb, ab.apply(this, arguments), this.store = this.manager.session.pointerEvents = [] + } + + function Ab() { + this.evTarget = yb, this.evWin = zb, this.started = !1, ab.apply(this, arguments) + } + + function Bb(a, b) { + var c = z(a.touches), d = z(a.changedTouches); + return b & (Q | R) && (c = A(c.concat(d), "identifier", !0)), [c, d] + } + + function Eb() { + this.evTarget = Db, this.targetIds = {}, ab.apply(this, arguments) + } + + function Fb(a, b) { + var c = z(a.touches), d = this.targetIds; + if (b & (O | P) && 1 === c.length) return d[c[0].identifier] = !0, [c, c]; + var e, f, g = z(a.changedTouches), h = [], i = this.target; + if (f = c.filter(function (a) { + return v(a.target, i) + }), b === O) for (e = 0; e < f.length;) d[f[e].identifier] = !0, e++; + for (e = 0; e < g.length;) d[g[e].identifier] && h.push(g[e]), b & (Q | R) && delete d[g[e].identifier], e++; + return h.length ? [A(f.concat(h), "identifier", !0), h] : void 0 + } + + function Gb() { + ab.apply(this, arguments); + var a = q(this.handler, this); + this.touch = new Eb(this.manager, a), this.mouse = new rb(this.manager, a) + } + + function Pb(a, b) { + this.manager = a, this.set(b) + } + + function Qb(a) { + if (w(a, Mb)) return Mb; + var b = w(a, Nb), c = w(a, Ob); + return b && c ? Nb + " " + Ob : b || c ? b ? Nb : Ob : w(a, Lb) ? Lb : Kb + } + + function Yb(a) { + this.id = D(), this.manager = null, this.options = o(a || {}, this.defaults), this.options.enable = s(this.options.enable, !0), this.state = Rb, this.simultaneous = {}, this.requireFail = [] + } + + function Zb(a) { + return a & Wb ? "cancel" : a & Ub ? "end" : a & Tb ? "move" : a & Sb ? "start" : "" + } + + function $b(a) { + return a == W ? "down" : a == V ? "up" : a == T ? "left" : a == U ? "right" : "" + } + + function _b(a, b) { + var c = b.manager; + return c ? c.get(a) : a + } + + function ac() { + Yb.apply(this, arguments) + } + + function bc() { + ac.apply(this, arguments), this.pX = null, this.pY = null + } + + function cc() { + ac.apply(this, arguments) + } + + function dc() { + Yb.apply(this, arguments), this._timer = null, this._input = null + } + + function ec() { + ac.apply(this, arguments) + } + + function fc() { + ac.apply(this, arguments) + } + + function gc() { + Yb.apply(this, arguments), this.pTime = !1, this.pCenter = !1, this._timer = null, this._input = null, this.count = 0 + } + + function hc(a, b) { + return b = b || {}, b.recognizers = s(b.recognizers, hc.defaults.preset), new kc(a, b) + } + + function kc(a, b) { + b = b || {}, this.options = o(b, hc.defaults), this.options.inputTarget = this.options.inputTarget || a, this.handlers = {}, this.session = {}, this.recognizers = [], this.element = a, this.input = bb(this), this.touchAction = new Pb(this, this.options.touchAction), lc(this, !0), m(b.recognizers, function (a) { + var b = this.add(new a[0](a[1])); + a[2] && b.recognizeWith(a[2]), a[3] && b.requireFailure(a[3]) + }, this) + } + + function lc(a, b) { + var c = a.element; + m(a.options.cssProps, function (a, d) { + c.style[B(c.style, d)] = b ? a : "" + }) + } + + function mc(a, c) { + var d = b.createEvent("Event"); + d.initEvent(a, !0, !0), d.gesture = c, c.target.dispatchEvent(d) + } + + var e = ["", "webkit", "moz", "MS", "ms", "o"], f = b.createElement("div"), g = "function", h = Math.round, + i = Math.abs, j = Date.now, C = 1, F = /mobile|tablet|ip(ad|hone|od)|android/i, G = "ontouchstart" in a, + H = B(a, "PointerEvent") !== d, I = G && F.test(navigator.userAgent), J = "touch", K = "pen", L = "mouse", + M = "kinect", N = 25, O = 1, P = 2, Q = 4, R = 8, S = 1, T = 2, U = 4, V = 8, W = 16, X = T | U, Y = V | W, + Z = X | Y, $ = ["x", "y"], _ = ["clientX", "clientY"]; + ab.prototype = { + handler: function () { + }, init: function () { + this.evEl && t(this.element, this.evEl, this.domHandler), this.evTarget && t(this.target, this.evTarget, this.domHandler), this.evWin && t(E(this.element), this.evWin, this.domHandler) + }, destroy: function () { + this.evEl && u(this.element, this.evEl, this.domHandler), this.evTarget && u(this.target, this.evTarget, this.domHandler), this.evWin && u(E(this.element), this.evWin, this.domHandler) + } + }; + var ob = {mousedown: O, mousemove: P, mouseup: Q}, pb = "mousedown", qb = "mousemove mouseup"; + p(rb, ab, { + handler: function (a) { + var b = ob[a.type]; + b & O && 0 === a.button && (this.pressed = !0), b & P && 1 !== a.which && (b = Q), this.pressed && this.allow && (b & Q && (this.pressed = !1), this.callback(this.manager, b, { + pointers: [a], + changedPointers: [a], + pointerType: L, + srcEvent: a + })) + } + }); + var sb = {pointerdown: O, pointermove: P, pointerup: Q, pointercancel: R, pointerout: R}, + tb = {2: J, 3: K, 4: L, 5: M}, ub = "pointerdown", vb = "pointermove pointerup pointercancel"; + a.MSPointerEvent && (ub = "MSPointerDown", vb = "MSPointerMove MSPointerUp MSPointerCancel"), p(wb, ab, { + handler: function (a) { + var b = this.store, c = !1, d = a.type.toLowerCase().replace("ms", ""), e = sb[d], + f = tb[a.pointerType] || a.pointerType, g = f == J, h = y(b, a.pointerId, "pointerId"); + e & O && (0 === a.button || g) ? 0 > h && (b.push(a), h = b.length - 1) : e & (Q | R) && (c = !0), 0 > h || (b[h] = a, this.callback(this.manager, e, { + pointers: b, + changedPointers: [a], + pointerType: f, + srcEvent: a + }), c && b.splice(h, 1)) + } + }); + var xb = {touchstart: O, touchmove: P, touchend: Q, touchcancel: R}, yb = "touchstart", + zb = "touchstart touchmove touchend touchcancel"; + p(Ab, ab, { + handler: function (a) { + var b = xb[a.type]; + if (b === O && (this.started = !0), this.started) { + var c = Bb.call(this, a, b); + b & (Q | R) && 0 === c[0].length - c[1].length && (this.started = !1), this.callback(this.manager, b, { + pointers: c[0], + changedPointers: c[1], + pointerType: J, + srcEvent: a + }) + } + } + }); + var Cb = {touchstart: O, touchmove: P, touchend: Q, touchcancel: R}, + Db = "touchstart touchmove touchend touchcancel"; + p(Eb, ab, { + handler: function (a) { + var b = Cb[a.type], c = Fb.call(this, a, b); + c && this.callback(this.manager, b, {pointers: c[0], changedPointers: c[1], pointerType: J, srcEvent: a}) + } + }), p(Gb, ab, { + handler: function (a, b, c) { + var d = c.pointerType == J, e = c.pointerType == L; + if (d) this.mouse.allow = !1; else if (e && !this.mouse.allow) return; + b & (Q | R) && (this.mouse.allow = !0), this.callback(a, b, c) + }, destroy: function () { + this.touch.destroy(), this.mouse.destroy() + } + }); + var Hb = B(f.style, "touchAction"), Ib = Hb !== d, Jb = "compute", Kb = "auto", Lb = "manipulation", Mb = "none", + Nb = "pan-x", Ob = "pan-y"; + Pb.prototype = { + set: function (a) { + a == Jb && (a = this.compute()), Ib && (this.manager.element.style[Hb] = a), this.actions = a.toLowerCase().trim() + }, update: function () { + this.set(this.manager.options.touchAction) + }, compute: function () { + var a = []; + return m(this.manager.recognizers, function (b) { + r(b.options.enable, [b]) && (a = a.concat(b.getTouchAction())) + }), Qb(a.join(" ")) + }, preventDefaults: function (a) { + if (!Ib) { + var b = a.srcEvent, c = a.offsetDirection; + if (this.manager.session.prevented) return b.preventDefault(), void 0; + var d = this.actions, e = w(d, Mb), f = w(d, Ob), g = w(d, Nb); + return e || f && c & X || g && c & Y ? this.preventSrc(b) : void 0 + } + }, preventSrc: function (a) { + this.manager.session.prevented = !0, a.preventDefault() + } + }; + var Rb = 1, Sb = 2, Tb = 4, Ub = 8, Vb = Ub, Wb = 16, Xb = 32; + Yb.prototype = { + defaults: {}, set: function (a) { + return n(this.options, a), this.manager && this.manager.touchAction.update(), this + }, recognizeWith: function (a) { + if (l(a, "recognizeWith", this)) return this; + var b = this.simultaneous; + return a = _b(a, this), b[a.id] || (b[a.id] = a, a.recognizeWith(this)), this + }, dropRecognizeWith: function (a) { + return l(a, "dropRecognizeWith", this) ? this : (a = _b(a, this), delete this.simultaneous[a.id], this) + }, requireFailure: function (a) { + if (l(a, "requireFailure", this)) return this; + var b = this.requireFail; + return a = _b(a, this), -1 === y(b, a) && (b.push(a), a.requireFailure(this)), this + }, dropRequireFailure: function (a) { + if (l(a, "dropRequireFailure", this)) return this; + a = _b(a, this); + var b = y(this.requireFail, a); + return b > -1 && this.requireFail.splice(b, 1), this + }, hasRequireFailures: function () { + return this.requireFail.length > 0 + }, canRecognizeWith: function (a) { + return !!this.simultaneous[a.id] + }, emit: function (a) { + function d(d) { + b.manager.emit(b.options.event + (d ? Zb(c) : ""), a) + } + + var b = this, c = this.state; + Ub > c && d(!0), d(), c >= Ub && d(!0) + }, tryEmit: function (a) { + return this.canEmit() ? this.emit(a) : (this.state = Xb, void 0) + }, canEmit: function () { + for (var a = 0; a < this.requireFail.length;) { + if (!(this.requireFail[a].state & (Xb | Rb))) return !1; + a++ + } + return !0 + }, recognize: function (a) { + var b = n({}, a); + return r(this.options.enable, [this, b]) ? (this.state & (Vb | Wb | Xb) && (this.state = Rb), this.state = this.process(b), this.state & (Sb | Tb | Ub | Wb) && this.tryEmit(b), void 0) : (this.reset(), this.state = Xb, void 0) + }, process: function () { + }, getTouchAction: function () { + }, reset: function () { + } + }, p(ac, Yb, { + defaults: {pointers: 1}, attrTest: function (a) { + var b = this.options.pointers; + return 0 === b || a.pointers.length === b + }, process: function (a) { + var b = this.state, c = a.eventType, d = b & (Sb | Tb), e = this.attrTest(a); + return d && (c & R || !e) ? b | Wb : d || e ? c & Q ? b | Ub : b & Sb ? b | Tb : Sb : Xb + } + }), p(bc, ac, { + defaults: {event: "pan", threshold: 10, pointers: 1, direction: Z}, getTouchAction: function () { + var a = this.options.direction, b = []; + return a & X && b.push(Ob), a & Y && b.push(Nb), b + }, directionTest: function (a) { + var b = this.options, c = !0, d = a.distance, e = a.direction, f = a.deltaX, g = a.deltaY; + return e & b.direction || (b.direction & X ? (e = 0 === f ? S : 0 > f ? T : U, c = f != this.pX, d = Math.abs(a.deltaX)) : (e = 0 === g ? S : 0 > g ? V : W, c = g != this.pY, d = Math.abs(a.deltaY))), a.direction = e, c && d > b.threshold && e & b.direction + }, attrTest: function (a) { + return ac.prototype.attrTest.call(this, a) && (this.state & Sb || !(this.state & Sb) && this.directionTest(a)) + }, emit: function (a) { + this.pX = a.deltaX, this.pY = a.deltaY; + var b = $b(a.direction); + b && this.manager.emit(this.options.event + b, a), this._super.emit.call(this, a) + } + }), p(cc, ac, { + defaults: {event: "pinch", threshold: 0, pointers: 2}, getTouchAction: function () { + return [Mb] + }, attrTest: function (a) { + return this._super.attrTest.call(this, a) && (Math.abs(a.scale - 1) > this.options.threshold || this.state & Sb) + }, emit: function (a) { + if (this._super.emit.call(this, a), 1 !== a.scale) { + var b = a.scale < 1 ? "in" : "out"; + this.manager.emit(this.options.event + b, a) + } + } + }), p(dc, Yb, { + defaults: {event: "press", pointers: 1, time: 500, threshold: 5}, getTouchAction: function () { + return [Kb] + }, process: function (a) { + var b = this.options, c = a.pointers.length === b.pointers, d = a.distance < b.threshold, + e = a.deltaTime > b.time; + if (this._input = a, !d || !c || a.eventType & (Q | R) && !e) this.reset(); else if (a.eventType & O) this.reset(), this._timer = k(function () { + this.state = Vb, this.tryEmit() + }, b.time, this); else if (a.eventType & Q) return Vb; + return Xb + }, reset: function () { + clearTimeout(this._timer) + }, emit: function (a) { + this.state === Vb && (a && a.eventType & Q ? this.manager.emit(this.options.event + "up", a) : (this._input.timeStamp = j(), this.manager.emit(this.options.event, this._input))) + } + }), p(ec, ac, { + defaults: {event: "rotate", threshold: 0, pointers: 2}, getTouchAction: function () { + return [Mb] + }, attrTest: function (a) { + return this._super.attrTest.call(this, a) && (Math.abs(a.rotation) > this.options.threshold || this.state & Sb) + } + }), p(fc, ac, { + defaults: {event: "swipe", threshold: 10, velocity: .65, direction: X | Y, pointers: 1}, + getTouchAction: function () { + return bc.prototype.getTouchAction.call(this) + }, + attrTest: function (a) { + var c, b = this.options.direction; + return b & (X | Y) ? c = a.velocity : b & X ? c = a.velocityX : b & Y && (c = a.velocityY), this._super.attrTest.call(this, a) && b & a.direction && a.distance > this.options.threshold && i(c) > this.options.velocity && a.eventType & Q + }, + emit: function (a) { + var b = $b(a.direction); + b && this.manager.emit(this.options.event + b, a), this.manager.emit(this.options.event, a) + } + }), p(gc, Yb, { + defaults: { + event: "tap", + pointers: 1, + taps: 1, + interval: 300, + time: 250, + threshold: 2, + posThreshold: 10 + }, getTouchAction: function () { + return [Lb] + }, process: function (a) { + var b = this.options, c = a.pointers.length === b.pointers, d = a.distance < b.threshold, + e = a.deltaTime < b.time; + if (this.reset(), a.eventType & O && 0 === this.count) return this.failTimeout(); + if (d && e && c) { + if (a.eventType != Q) return this.failTimeout(); + var f = this.pTime ? a.timeStamp - this.pTime < b.interval : !0, + g = !this.pCenter || kb(this.pCenter, a.center) < b.posThreshold; + this.pTime = a.timeStamp, this.pCenter = a.center, g && f ? this.count += 1 : this.count = 1, this._input = a; + var h = this.count % b.taps; + if (0 === h) return this.hasRequireFailures() ? (this._timer = k(function () { + this.state = Vb, this.tryEmit() + }, b.interval, this), Sb) : Vb + } + return Xb + }, failTimeout: function () { + return this._timer = k(function () { + this.state = Xb + }, this.options.interval, this), Xb + }, reset: function () { + clearTimeout(this._timer) + }, emit: function () { + this.state == Vb && (this._input.tapCount = this.count, this.manager.emit(this.options.event, this._input)) + } + }), hc.VERSION = "2.0.4", hc.defaults = { + domEvents: !1, + touchAction: Jb, + enable: !0, + inputTarget: null, + inputClass: null, + preset: [[ec, {enable: !1}], [cc, {enable: !1}, ["rotate"]], [fc, {direction: X}], [bc, {direction: X}, ["swipe"]], [gc], [gc, { + event: "doubletap", + taps: 2 + }, ["tap"]], [dc]], + cssProps: { + userSelect: "default", + touchSelect: "none", + touchCallout: "none", + contentZooming: "none", + userDrag: "none", + tapHighlightColor: "rgba(0,0,0,0)" + } + }; + var ic = 1, jc = 2; + kc.prototype = { + set: function (a) { + return n(this.options, a), a.touchAction && this.touchAction.update(), a.inputTarget && (this.input.destroy(), this.input.target = a.inputTarget, this.input.init()), this + }, stop: function (a) { + this.session.stopped = a ? jc : ic + }, recognize: function (a) { + var b = this.session; + if (!b.stopped) { + this.touchAction.preventDefaults(a); + var c, d = this.recognizers, e = b.curRecognizer; + (!e || e && e.state & Vb) && (e = b.curRecognizer = null); + for (var f = 0; f < d.length;) c = d[f], b.stopped === jc || e && c != e && !c.canRecognizeWith(e) ? c.reset() : c.recognize(a), !e && c.state & (Sb | Tb | Ub) && (e = b.curRecognizer = c), f++ + } + }, get: function (a) { + if (a instanceof Yb) return a; + for (var b = this.recognizers, c = 0; c < b.length; c++) if (b[c].options.event == a) return b[c]; + return null + }, add: function (a) { + if (l(a, "add", this)) return this; + var b = this.get(a.options.event); + return b && this.remove(b), this.recognizers.push(a), a.manager = this, this.touchAction.update(), a + }, remove: function (a) { + if (l(a, "remove", this)) return this; + var b = this.recognizers; + return a = this.get(a), b.splice(y(b, a), 1), this.touchAction.update(), this + }, on: function (a, b) { + var c = this.handlers; + return m(x(a), function (a) { + c[a] = c[a] || [], c[a].push(b) + }), this + }, off: function (a, b) { + var c = this.handlers; + return m(x(a), function (a) { + b ? c[a].splice(y(c[a], b), 1) : delete c[a] + }), this + }, emit: function (a, b) { + this.options.domEvents && mc(a, b); + var c = this.handlers[a] && this.handlers[a].slice(); + if (c && c.length) { + b.type = a, b.preventDefault = function () { + b.srcEvent.preventDefault() + }; + for (var d = 0; d < c.length;) c[d](b), d++ + } + }, destroy: function () { + this.element && lc(this, !1), this.handlers = {}, this.session = {}, this.input.destroy(), this.element = null + } + }, n(hc, { + INPUT_START: O, + INPUT_MOVE: P, + INPUT_END: Q, + INPUT_CANCEL: R, + STATE_POSSIBLE: Rb, + STATE_BEGAN: Sb, + STATE_CHANGED: Tb, + STATE_ENDED: Ub, + STATE_RECOGNIZED: Vb, + STATE_CANCELLED: Wb, + STATE_FAILED: Xb, + DIRECTION_NONE: S, + DIRECTION_LEFT: T, + DIRECTION_RIGHT: U, + DIRECTION_UP: V, + DIRECTION_DOWN: W, + DIRECTION_HORIZONTAL: X, + DIRECTION_VERTICAL: Y, + DIRECTION_ALL: Z, + Manager: kc, + Input: ab, + TouchAction: Pb, + TouchInput: Eb, + MouseInput: rb, + PointerEventInput: wb, + TouchMouseInput: Gb, + SingleTouchInput: Ab, + Recognizer: Yb, + AttrRecognizer: ac, + Tap: gc, + Pan: bc, + Swipe: fc, + Pinch: cc, + Rotate: ec, + Press: dc, + on: t, + off: u, + each: m, + merge: o, + extend: n, + inherit: p, + bindFn: q, + prefixed: B + }), typeof define == g && define.amd ? define(function () { + return hc + }) : "undefined" != typeof module && module.exports ? module.exports = hc : a[c] = hc +}(window, document, "Hammer"); +(function (factory) { if (typeof define === 'function' && define.amd) { define(['jquery', 'hammerjs'], factory); } else if (typeof exports === 'object') { @@ -265,7 +936,7 @@ m.isFunction(t)&&t(null,!0)}),f.queue(a,m.isString(v)?v:"",[])),"stop"===y?(i(a) }; })(Hammer.Manager.prototype.emit); })); -;// Required for Meteor package, the use of window prevents export by Meteor +// Required for Meteor package, the use of window prevents export by Meteor (function(window){ if(window.Package){ Materialize = {}; @@ -310,8 +981,8 @@ if ($) { } else { Vel = Velocity; } -;(function ($) { - $.fn.collapsible = function(options) { +(function ($) { + $.fn.collapsible = function (options) { var defaults = { accordion: undefined }; @@ -446,9 +1117,10 @@ if ($) { $(document).ready(function(){ $('.collapsible').collapsible(); }); -}( jQuery ));;(function ($) { +}(jQuery)); +(function ($) { - // Add posibility to scroll to selected option + // Add posibility to scroll to selected option // usefull for select for example $.fn.scrollTo = function(elem) { $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top); @@ -711,7 +1383,7 @@ if ($) { $('.dropdown-button').dropdown(); }); }( jQuery )); -;(function($) { +(function ($) { var _stack = 0, _lastID = 0, _generateID = function() { @@ -903,9 +1575,8 @@ if ($) { } }); })(jQuery); -;(function ($) { - - $.fn.materialbox = function () { +(function ($) { + $.fn.materialbox = function () { return this.each(function() { @@ -1172,8 +1843,7 @@ $(document).ready(function(){ }); }( jQuery )); -;(function ($) { - +(function ($) { $.fn.parallax = function () { var window_width = $(window).width(); // Parallax Scripts @@ -1229,9 +1899,9 @@ $(document).ready(function(){ }); }; -}( jQuery ));;(function ($) { - - var methods = { +}(jQuery)); +(function ($) { + var methods = { init : function(options) { var defaults = { onShow: null @@ -1377,7 +2047,7 @@ $(document).ready(function(){ $('ul.tabs').tabs(); }); }( jQuery )); -;(function ($) { +(function ($) { $.fn.tooltip = function (options) { var timeout = null, margin = 5; @@ -1607,7 +2277,7 @@ $(document).ready(function(){ $('.tooltipped').tooltip(); }); }( jQuery )); -;/*! +/*! * Waves v0.6.4 * http://fian.my.id/Waves * @@ -1616,7 +2286,7 @@ $(document).ready(function(){ * https://github.com/fians/Waves/blob/master/LICENSE */ -;(function(window) { +(function (window) { 'use strict'; var Waves = Waves || {}; @@ -1945,7 +2615,7 @@ $(document).ready(function(){ }, false); })(window); -;Materialize.toast = function (message, displayLength, className, completeCallback) { +Materialize.toast = function (message, displayLength, className, completeCallback) { className = className || ""; var container = document.getElementById('toast-container'); @@ -2081,9 +2751,8 @@ $(document).ready(function(){ return toast; } }; -;(function ($) { - - var methods = { +(function ($) { + var methods = { init : function(options) { var defaults = { menuWidth: 300, @@ -2433,7 +3102,7 @@ $(document).ready(function(){ } }; // Plugin end }( jQuery )); -;/** +/** * Extend jquery with a scrollspy plugin. * This watches the window scroll and fires events when elements are scrolled into viewport. * @@ -2458,7 +3127,7 @@ $(document).ready(function(){ right : 0, bottom : 0, left : 0, - } + }; /** * Find elements that are within the boundary @@ -2591,9 +3260,9 @@ $(document).ready(function(){ } return result; }; - }; + } - /** + /** * Enables ScrollSpy using a selector * @param {jQuery|string} selector The elements collection, or a selector * @param {Object=} options Optional. @@ -2716,8 +3385,8 @@ $(document).ready(function(){ }; })(jQuery); -;(function ($) { - $(document).ready(function() { +(function ($) { + $(document).ready(function () { // Function to update labels of text fields Materialize.updateTextFields = function() { @@ -2822,7 +3491,7 @@ $(document).ready(function(){ $(this).removeClass('tabbed'); }); - return; + } }); @@ -3397,9 +4066,8 @@ $(document).ready(function(){ }; }( jQuery )); -;(function ($) { - - var methods = { +(function ($) { + var methods = { init : function(options) { var defaults = { @@ -3718,8 +4386,8 @@ $(document).ready(function(){ } }; // Plugin end }( jQuery )); -;(function ($) { - $(document).ready(function() { +(function ($) { + $(document).ready(function () { $(document).on('click.card', '.card', function (e) { if ($(this).find('> .card-reveal').length) { @@ -3743,8 +4411,9 @@ $(document).ready(function(){ }); }); -}( jQuery ));;(function ($) { - var chipsHandleEvents = false; +}(jQuery)); +(function ($) { + var chipsHandleEvents = false; var materialChipsDefaults = { data: [], placeholder: '', @@ -3907,7 +4576,7 @@ $(document).ready(function(){ if ((8 === e.keyCode || 37 === e.keyCode) && '' === $target.val() && chipsLength) { self.selectChip(chipsIndex, chipsLength - 1, $chips); $target.blur(); - return; + } }); @@ -4009,8 +4678,9 @@ $(document).ready(function(){ chipsHandleEvents = true; } }; -}( jQuery ));;(function ($) { - $.fn.pushpin = function (options) { +}(jQuery)); +(function ($) { + $.fn.pushpin = function (options) { // Defaults var defaults = { top: 0, @@ -4079,8 +4749,9 @@ $(document).ready(function(){ }); }; -}( jQuery ));;(function ($) { - $(document).ready(function() { +}(jQuery)); +(function ($) { + $(document).ready(function () { // jQuery reverse $.fn.reverse = [].reverse; @@ -4170,8 +4841,8 @@ $(document).ready(function(){ }( jQuery )); -;(function ($) { - // Image transition function +(function ($) { + // Image transition function Materialize.fadeInImage = function(selectorOrEl) { var element; if (typeof(selectorOrEl) === 'string') { @@ -4339,9 +5010,9 @@ $(document).ready(function(){ // }); }); }( jQuery )); -;(function($) { +(function ($) { - // Input: Array of JSON objects {selector, offset, callback} + // Input: Array of JSON objects {selector, offset, callback} Materialize.scrollFire = function(options) { @@ -4387,7 +5058,7 @@ $(document).ready(function(){ }; })(jQuery); -;/*! +/*! * pickadate.js v3.5.0, 2014/04/13 * By Amsul, http://amsul.ca * Hosted on http://amsul.github.io/pickadate.js @@ -4398,20 +5069,20 @@ $(document).ready(function(){ // AMD. if ( typeof define == 'function' && define.amd ) - define( 'picker', ['jquery'], factory ) + define('picker', ['jquery'], factory); // Node.js/browserify. else if ( typeof exports == 'object' ) - module.exports = factory( require('jquery') ) + module.exports = factory(require('jquery')); // Browser globals. else this.Picker = factory( jQuery ) }(function( $ ) { -var $window = $( window ) -var $document = $( document ) -var $html = $( document.documentElement ) + var $window = $(window); + var $document = $(document); + var $html = $(document.documentElement); /** @@ -4420,7 +5091,7 @@ var $html = $( document.documentElement ) function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // If there’s no element, return the picker constructor. - if ( !ELEMENT ) return PickerConstructor + if (!ELEMENT) return PickerConstructor; var @@ -4465,33 +5136,33 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { start: function() { // If it’s already started, do nothing. - if ( STATE && STATE.start ) return P + if (STATE && STATE.start) return P; // Update the picker states. - STATE.methods = {} - STATE.start = true - STATE.open = false - STATE.type = ELEMENT.type + STATE.methods = {}; + STATE.start = true; + STATE.open = false; + STATE.type = ELEMENT.type; // Confirm focus state, convert into text input to remove UA stylings, // and set as readonly to prevent keyboard popup. - ELEMENT.autofocus = ELEMENT == getActiveElement() - ELEMENT.readOnly = !SETTINGS.editable - ELEMENT.id = ELEMENT.id || STATE.id + ELEMENT.autofocus = ELEMENT == getActiveElement(); + ELEMENT.readOnly = !SETTINGS.editable; + ELEMENT.id = ELEMENT.id || STATE.id; if ( ELEMENT.type != 'text' ) { ELEMENT.type = 'text' } // Create a new picker component with the settings. - P.component = new COMPONENT(P, SETTINGS) + P.component = new COMPONENT(P, SETTINGS); // Create the picker root with a holder and then prepare it. - P.$root = $( PickerConstructor._.node('div', createWrappedComponent(), CLASSES.picker, 'id="' + ELEMENT.id + '_root" tabindex="0"') ) - prepareElementRoot() + P.$root = $(PickerConstructor._.node('div', createWrappedComponent(), CLASSES.picker, 'id="' + ELEMENT.id + '_root" tabindex="0"')); + prepareElementRoot(); // If there’s a format for the hidden input element, create the element. @@ -4501,12 +5172,12 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // Prepare the input element. - prepareElement() + prepareElement(); // Insert the root as specified in the settings. - if ( SETTINGS.container ) $( SETTINGS.container ).append( P.$root ) - else $ELEMENT.after( P.$root ) + if (SETTINGS.container) $(SETTINGS.container).append(P.$root); + else $ELEMENT.after(P.$root); // Bind the default component and settings events. @@ -4524,11 +5195,11 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { open: SETTINGS.onOpen, close: SETTINGS.onClose, set: SETTINGS.onSet - }) + }); // Once we’re all set, check the theme in use. - IS_DEFAULT_THEME = isUsingDefaultTheme( P.$root.children()[ 0 ] ) + IS_DEFAULT_THEME = isUsingDefaultTheme(P.$root.children()[0]); // If the element has autofocus, open the picker. @@ -4548,8 +5219,8 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { render: function( entireComponent ) { // Insert a new component holder in the root or box. - if ( entireComponent ) P.$root.html( createWrappedComponent() ) - else P.$root.find( '.' + CLASSES.box ).html( P.component.nodes( STATE.open ) ) + if (entireComponent) P.$root.html(createWrappedComponent()); + else P.$root.find('.' + CLASSES.box).html(P.component.nodes(STATE.open)); // Trigger the queued “render” events. return P.trigger( 'render' ) @@ -4562,10 +5233,10 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { stop: function() { // If it’s already stopped, do nothing. - if ( !STATE.start ) return P + if (!STATE.start) return P; // Then close the picker. - P.close() + P.close(); // Remove the hidden field. if ( P._hidden ) { @@ -4573,25 +5244,25 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { } // Remove the root. - P.$root.remove() + P.$root.remove(); // Remove the input class, remove the stored data, and unbind // the events (after a tick for IE - see `P.close`). - $ELEMENT.removeClass( CLASSES.input ).removeData( NAME ) + $ELEMENT.removeClass(CLASSES.input).removeData(NAME); setTimeout( function() { $ELEMENT.off( '.' + STATE.id ) - }, 0) + }, 0); // Restore the element state - ELEMENT.type = STATE.type - ELEMENT.readOnly = false + ELEMENT.type = STATE.type; + ELEMENT.readOnly = false; // Trigger the queued “stop” events. - P.trigger( 'stop' ) + P.trigger('stop'); // Reset the picker states. - STATE.methods = {} - STATE.start = false + STATE.methods = {}; + STATE.start = false; return P }, //stop @@ -4603,11 +5274,11 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { open: function( dontGiveFocus ) { // If it’s already open, do nothing. - if ( STATE.open ) return P + if (STATE.open) return P; // Add the “active” class. - $ELEMENT.addClass( CLASSES.active ) - aria( ELEMENT, 'expanded', true ) + $ELEMENT.addClass(CLASSES.active); + aria(ELEMENT, 'expanded', true); // * A Firefox bug, when `html` has `overflow:hidden`, results in // killing transitions :(. So add the “opened” state on the next tick. @@ -4615,16 +5286,16 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { setTimeout( function() { // Add the “opened” class to the picker root. - P.$root.addClass( CLASSES.opened ) + P.$root.addClass(CLASSES.opened); aria( P.$root[0], 'hidden', false ) - }, 0 ) + }, 0); // If we have to give focus, bind the element and doc events. if ( dontGiveFocus !== false ) { // Set it as open. - STATE.open = true + STATE.open = true; // Prevent the page from scrolling. if ( IS_DEFAULT_THEME ) { @@ -4635,12 +5306,12 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // Pass focus to the root element’s jQuery object. // * Workaround for iOS8 to bring the picker’s root into view. - P.$root.eq(0).focus() + P.$root.eq(0).focus(); // Bind the document events. $document.on( 'click.' + STATE.id + ' focusin.' + STATE.id, function( event ) { - var target = event.target + var target = event.target; // If the target of the event is not the element, close the picker picker. // * Don’t worry about clicks or focusins on the root because those don’t bubble up. @@ -4666,7 +5337,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { keycodeToMove = P.component.key[ keycode ], // Grab the target. - target = event.target + target = event.target; // On escape, close the picker and give focus. @@ -4679,7 +5350,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { else if ( target == P.$root[0] && ( keycodeToMove || keycode == 13 ) ) { // Prevent the default action to stop page movement. - event.preventDefault() + event.preventDefault(); // Trigger the key movement action. if ( keycodeToMove ) { @@ -4696,7 +5367,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // If the target is within the root and “enter” is pressed, // prevent the default action and trigger a click on the target instead. else if ( $.contains( P.$root[0], target ) && keycode == 13 ) { - event.preventDefault() + event.preventDefault(); target.click() } }) @@ -4717,15 +5388,15 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // ....ah yes! It would’ve been incomplete without a crazy workaround for IE :| // The focus is triggered *after* the close has completed - causing it // to open again. So unbind and rebind the event at the next tick. - P.$root.off( 'focus.toOpen' ).eq(0).focus() + P.$root.off('focus.toOpen').eq(0).focus(); setTimeout( function() { P.$root.on( 'focus.toOpen', handleFocusToOpenEvent ) }, 0 ) } // Remove the “active” class. - $ELEMENT.removeClass( CLASSES.active ) - aria( ELEMENT, 'expanded', false ) + $ELEMENT.removeClass(CLASSES.active); + aria(ELEMENT, 'expanded', false); // * A Firefox bug, when `html` has `overflow:hidden`, results in // killing transitions :(. So remove the “opened” state on the next tick. @@ -4733,16 +5404,16 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { setTimeout( function() { // Remove the “opened” and “focused” class from the picker root. - P.$root.removeClass( CLASSES.opened + ' ' + CLASSES.focused ) + P.$root.removeClass(CLASSES.opened + ' ' + CLASSES.focused); aria( P.$root[0], 'hidden', true ) - }, 0 ) + }, 0); // If it’s already closed, do nothing more. - if ( !STATE.open ) return P + if (!STATE.open) return P; // Set it as closed. - STATE.open = false + STATE.open = false; // Allow the page to scroll. if ( IS_DEFAULT_THEME ) { @@ -4752,7 +5423,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { } // Unbind the document events. - $document.off( '.' + STATE.id ) + $document.off('.' + STATE.id); // Trigger the queued “close” events. return P.trigger( 'close' ) @@ -4774,10 +5445,10 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { var thingItem, thingValue, thingIsObject = $.isPlainObject( thing ), - thingObject = thingIsObject ? thing : {} + thingObject = thingIsObject ? thing : {}; // Make sure we have usable options. - options = thingIsObject && $.isPlainObject( value ) ? value : options || {} + options = thingIsObject && $.isPlainObject(value) ? value : options || {}; if ( thing ) { @@ -4790,11 +5461,11 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { for ( thingItem in thingObject ) { // Grab the value of the thing. - thingValue = thingObject[ thingItem ] + thingValue = thingObject[thingItem]; // First, if the item exists and there’s a value, set it. if ( thingItem in P.component.item ) { - if ( thingValue === undefined ) thingValue = null + if (thingValue === undefined) thingValue = null; P.component.set( thingItem, thingValue, options ) } @@ -4821,7 +5492,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { get: function( thing, format ) { // Make sure there’s something to get. - thing = thing || 'value' + thing = thing || 'value'; // If a picker state exists, return that. if ( STATE[ thing ] != null ) { @@ -4844,7 +5515,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // Check if a component item exists, return that. if ( thing in P.component.item ) { if ( typeof format == 'string' ) { - var thingValue = P.component.get( thing ) + var thingValue = P.component.get(thing); return thingValue ? PickerConstructor._.trigger( P.component.formats.toString, @@ -4865,7 +5536,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { var thingName, thingMethod, thingIsObject = $.isPlainObject( thing ), - thingObject = thingIsObject ? thing : {} + thingObject = thingIsObject ? thing : {}; if ( thing ) { @@ -4878,7 +5549,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { for ( thingName in thingObject ) { // Grab the method of the thing. - thingMethod = thingObject[ thingName ] + thingMethod = thingObject[thingName]; // If it was an internal binding, prefix it. if ( internal ) { @@ -4886,7 +5557,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { } // Make sure the thing methods collection exists. - STATE.methods[ thingName ] = STATE.methods[ thingName ] || [] + STATE.methods[thingName] = STATE.methods[thingName] || []; // Add the method to the relative method collection. STATE.methods[ thingName ].push( thingMethod ) @@ -4905,7 +5576,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { var i, thingName, names = arguments; for ( i = 0, namesCount = names.length; i < namesCount; i += 1 ) { - thingName = names[i] + thingName = names[i]; if ( thingName in STATE.methods ) { delete STATE.methods[thingName] } @@ -4919,18 +5590,18 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { */ trigger: function( name, data ) { var _trigger = function( name ) { - var methodList = STATE.methods[ name ] + var methodList = STATE.methods[name]; if ( methodList ) { methodList.map( function( method ) { PickerConstructor._.trigger( method, P, [ data ] ) }) } - } - _trigger( '_' + name ) - _trigger( name ) + }; + _trigger('_' + name); + _trigger(name); return P } //trigger - } //PickerInstance.prototype + }; //PickerInstance.prototype /** @@ -4992,7 +5663,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { val( $ELEMENT.data('value') ? P.get('select', SETTINGS.format) : ELEMENT.value - ) + ); // Only bind keydown events if the element isn’t editable. @@ -5002,7 +5673,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // On focus/click, focus onto the root to open it up. on( 'focus.' + STATE.id + ' click.' + STATE.id, function( event ) { - event.preventDefault() + event.preventDefault(); P.$root.eq(0).focus() }). @@ -5036,7 +5707,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // When something within the root is focused, stop from bubbling // to the doc and remove the “focused” state from the root. focusin: function( event ) { - P.$root.removeClass( CLASSES.focused ) + P.$root.removeClass(CLASSES.focused); event.stopPropagation() }, @@ -5044,12 +5715,12 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // from bubbling to the doc. 'mousedown click': function( event ) { - var target = event.target + var target = event.target; // Make sure the target isn’t the root holder so it can bubble up. if ( target != P.$root.children()[ 0 ] ) { - event.stopPropagation() + event.stopPropagation(); // * For mousedown events, cancel the default action in order to // prevent cases where focus is shifted onto external elements @@ -5057,7 +5728,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // Also, for Firefox, don’t prevent action on the `option` element. if ( event.type == 'mousedown' && !$( target ).is( 'input, select, textarea, button, option' )) { - event.preventDefault() + event.preventDefault(); // Re-focus onto the root so that users can click away // from elements focused within the picker. @@ -5089,8 +5760,8 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // * For IE, non-focusable elements can be active elements as well // (http://stackoverflow.com/a/2684561). - activeElement = getActiveElement() - activeElement = activeElement && ( activeElement.type || activeElement.href ) + activeElement = getActiveElement(); + activeElement = activeElement && (activeElement.type || activeElement.href); // If it’s disabled or nothing inside is actively focused, re-focus the element. if ( targetDisabled || activeElement && !$.contains( P.$root[0], activeElement ) ) { @@ -5116,7 +5787,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { P.close( true ) } - }) //P.$root + }); //P.$root aria( P.$root[0], 'hidden', true ) } @@ -5127,17 +5798,17 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { */ function prepareElementHidden() { - var name + var name; if ( SETTINGS.hiddenName === true ) { - name = ELEMENT.name + name = ELEMENT.name; ELEMENT.name = '' } else { name = [ typeof SETTINGS.hiddenPrefix == 'string' ? SETTINGS.hiddenPrefix : '', typeof SETTINGS.hiddenSuffix == 'string' ? SETTINGS.hiddenSuffix : '_submit' - ] + ]; name = name[0] + ELEMENT.name + name[1] } @@ -5155,7 +5826,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { '' ) + '>' - )[0] + )[0]; $ELEMENT. @@ -5164,11 +5835,11 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { P._hidden.value = ELEMENT.value ? P.get('select', SETTINGS.formatSubmit) : '' - }) + }); // Insert the hidden input as specified in the settings. - if ( SETTINGS.container ) $( SETTINGS.container ).append( P._hidden ) + if (SETTINGS.container) $(SETTINGS.container).append(P._hidden); else $ELEMENT.after( P._hidden ) } @@ -5179,11 +5850,11 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { var keycode = event.keyCode, // Check if one of the delete keys was pressed. - isKeycodeDelete = /^(8|46)$/.test(keycode) + isKeycodeDelete = /^(8|46)$/.test(keycode); // For some reason IE clears the input value on “escape”. if ( keycode == 27 ) { - P.close() + P.close(); return false } @@ -5191,8 +5862,8 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { if ( keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode] ) { // Prevent it from moving the page and bubbling to doc. - event.preventDefault() - event.stopPropagation() + event.preventDefault(); + event.stopPropagation(); // If `delete` was pressed, clear the values and close the picker. // Otherwise open the picker. @@ -5206,7 +5877,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { function handleFocusToOpenEvent( event ) { // Stop the event from propagating to the doc. - event.stopPropagation() + event.stopPropagation(); // If it’s a focus event, add the “focused” class to the root. if ( event.type == 'focus' ) { @@ -5228,7 +5899,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { * The default classes and prefix to use for the HTML classes. */ PickerConstructor.klasses = function( prefix ) { - prefix = prefix || 'picker' + prefix = prefix || 'picker'; return { picker: prefix, @@ -5246,7 +5917,7 @@ PickerConstructor.klasses = function( prefix ) { box: prefix + '__box' } -} //PickerConstructor.klasses +}; //PickerConstructor.klasses @@ -5256,7 +5927,7 @@ PickerConstructor.klasses = function( prefix ) { function isUsingDefaultTheme( element ) { var theme, - prop = 'position' + prop = 'position'; // For IE. if ( element.currentStyle ) { @@ -5283,23 +5954,22 @@ function getScrollbarWidth() { return 0 } - var $outer = $( '

    ' ). - appendTo( 'body' ) + var $outer = $( '
    ' ).appendTo('body'); // Get the width without scrollbars. - var widthWithoutScroll = $outer[0].offsetWidth + var widthWithoutScroll = $outer[0].offsetWidth; // Force adding scrollbars. - $outer.css( 'overflow', 'scroll' ) + $outer.css('overflow', 'scroll'); // Add the inner div. - var $inner = $( '
    ' ).appendTo( $outer ) + var $inner = $('
    ').appendTo($outer); // Get the width with scrollbars. - var widthWithScroll = $inner[0].offsetWidth + var widthWithScroll = $inner[0].offsetWidth; // Remove the divs. - $outer.remove() + $outer.remove(); // Return the difference between the widths. return widthWithoutScroll - widthWithScroll @@ -5334,14 +6004,14 @@ PickerConstructor._ = { nodesList = '', // The counter starts from the `min` - counter = PickerConstructor._.trigger( groupObject.min, groupObject ) + counter = PickerConstructor._.trigger(groupObject.min, groupObject); // Loop from the `min` to `max`, incrementing by `i` for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) { // Trigger the `item` function within scope of the object - loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] ) + loopObjectScope = PickerConstructor._.trigger(groupObject.item, groupObject, [counter]); // Splice the subgroup and create nodes out of the sub nodes nodesList += PickerConstructor._.node( @@ -5363,16 +6033,16 @@ PickerConstructor._ = { node: function( wrapper, item, klass, attribute ) { // If the item is false-y, just return an empty string - if ( !item ) return '' + if (!item) return ''; // If the item is an array, do a join - item = $.isArray( item ) ? item.join( '' ) : item + item = $.isArray(item) ? item.join('') : item; // Check for the class - klass = klass ? ' class="' + klass + '"' : '' + klass = klass ? ' class="' + klass + '"' : ''; // Check for any attributes - attribute = attribute ? ' ' + attribute : '' + attribute = attribute ? ' ' + attribute : ''; // Return the wrapped item return '<' + wrapper + klass + attribute + '>' + item + '' @@ -5423,7 +6093,7 @@ PickerConstructor._ = { * Create ARIA attribute strings. */ ariaAttr: ariaAttr -} //PickerConstructor._ +}; //PickerConstructor._ @@ -5436,7 +6106,7 @@ PickerConstructor.extend = function( name, Component ) { $.fn[ name ] = function( options, action ) { // Grab the component data. - var componentData = this.data( name ) + var componentData = this.data(name); // If the picker is requested, return the data object. if ( options == 'picker' ) { @@ -5452,16 +6122,16 @@ PickerConstructor.extend = function( name, Component ) { // doesn’t exist, create a new picker using `this` element // and merging the defaults and options with a deep copy. return this.each( function() { - var $this = $( this ) + var $this = $(this); if ( !$this.data( name ) ) { new PickerConstructor( this, name, Component, options ) } }) - } + }; // Set the defaults. $.fn[ name ].defaults = Component.defaults -} //PickerConstructor.extend +}; //PickerConstructor.extend @@ -5485,10 +6155,10 @@ function ariaAttr(attribute, data) { if ( !$.isPlainObject(attribute) ) { attribute = { attribute: data } } - data = '' + data = ''; for ( var key in attribute ) { var attr = (key == 'role' ? '' : 'aria-') + key, - attrVal = attribute[key] + attrVal = attribute[key]; data += attrVal == null ? '' : attr + '="' + attribute[key] + '"' } return data @@ -5510,7 +6180,7 @@ return PickerConstructor })); -;/*! +/*! * Date picker for pickadate.js v3.5.0 * http://amsul.github.io/pickadate.js/date.htm */ @@ -5519,11 +6189,11 @@ return PickerConstructor // AMD. if ( typeof define == 'function' && define.amd ) - define( ['picker', 'jquery'], factory ) + define(['picker', 'jquery'], factory); // Node.js/browserify. else if ( typeof exports == 'object' ) - module.exports = factory( require('./picker.js'), require('jquery') ) + module.exports = factory(require('./picker.js'), require('jquery')); // Browser globals. else factory( Picker, jQuery ) @@ -5536,7 +6206,7 @@ return PickerConstructor */ var DAYS_IN_WEEK = 7, WEEKS_IN_CALENDAR = 6, - _ = Picker._ + _ = Picker._; @@ -5560,10 +6230,10 @@ function DatePicker( picker, settings ) { // For normal browsers. getComputedStyle( picker.$root[0] ).direction == 'rtl' - } + }; - calendar.settings = settings - calendar.$node = picker.$node + calendar.settings = settings; + calendar.$node = picker.$node; // The queue of methods that will be used to build item objects. calendar.queue = { @@ -5575,21 +6245,20 @@ function DatePicker( picker, settings ) { view: 'parse create validate viewset', disable: 'deactivate', enable: 'activate' - } + }; // The component's item object. - calendar.item = {} + calendar.item = {}; - calendar.item.clear = null - calendar.item.disable = ( settings.disable || [] ).slice( 0 ) + calendar.item.clear = null; + calendar.item.disable = (settings.disable || []).slice(0); calendar.item.enable = -(function( collectionDisabled ) { return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1 - })( calendar.item.disable ) + })(calendar.item.disable); calendar. set( 'min', settings.min ). - set( 'max', settings.max ). - set( 'now' ) + set( 'max', settings.max ).set('now'); // When there’s a value, set the `select`, which in turn // also sets the `highlight` and `view`. @@ -5613,37 +6282,37 @@ function DatePicker( picker, settings ) { 37: function() { return isRTL() ? 1 : -1 }, // Left go: function( timeChange ) { var highlightedObject = calendar.item.highlight, - targetDate = new Date( highlightedObject.year, highlightedObject.month, highlightedObject.date + timeChange ) + targetDate = new Date(highlightedObject.year, highlightedObject.month, highlightedObject.date + timeChange); calendar.set( 'highlight', targetDate, { interval: timeChange } - ) + ); this.render() } - } + }; // Bind some picker events. picker. on( 'render', function() { picker.$root.find( '.' + settings.klass.selectMonth ).on( 'change', function() { - var value = this.value + var value = this.value; if ( value ) { - picker.set( 'highlight', [ picker.get( 'view' ).year, value, picker.get( 'highlight' ).date ] ) + picker.set('highlight', [picker.get('view').year, value, picker.get('highlight').date]); picker.$root.find( '.' + settings.klass.selectMonth ).trigger( 'focus' ) } - }) + }); picker.$root.find( '.' + settings.klass.selectYear ).on( 'change', function() { - var value = this.value + var value = this.value; if ( value ) { - picker.set( 'highlight', [ value, picker.get( 'view' ).month, picker.get( 'highlight' ).date ] ) + picker.set('highlight', [value, picker.get('view').month, picker.get('highlight').date]); picker.$root.find( '.' + settings.klass.selectYear ).trigger( 'focus' ) } }) }, 1 ). on( 'open', function() { - var includeToday = '' + var includeToday = ''; if ( calendar.disabled( calendar.get('now') ) ) { includeToday = ':not(.' + settings.klass.buttonToday + ')' } @@ -5662,12 +6331,12 @@ function DatePicker( picker, settings ) { DatePicker.prototype.set = function( type, value, options ) { var calendar = this, - calendarItem = calendar.item + calendarItem = calendar.item; // If the value is `null` just set it immediately. if ( value === null ) { - if ( type == 'clear' ) type = 'select' - calendarItem[ type ] = value + if (type == 'clear') type = 'select'; + calendarItem[type] = value; return calendar } @@ -5676,9 +6345,9 @@ DatePicker.prototype.set = function( type, value, options ) { // * In the case of `enable`, keep the queue but set `disable` instead. // And in the case of `flip`, keep the queue but set `enable` instead. calendarItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = calendar.queue[ type ].split( ' ' ).map( function( method ) { - value = calendar[ method ]( type, value, options ) + value = calendar[method](type, value, options); return value - }).pop() + }).pop(); // Check if we need to cascade through more updates. if ( type == 'select' ) { @@ -5697,7 +6366,7 @@ DatePicker.prototype.set = function( type, value, options ) { } return calendar -} //DatePicker.prototype.set +}; //DatePicker.prototype.set /** @@ -5705,7 +6374,7 @@ DatePicker.prototype.set = function( type, value, options ) { */ DatePicker.prototype.get = function( type ) { return this.item[ type ] -} //DatePicker.prototype.get +}; //DatePicker.prototype.get /** @@ -5714,10 +6383,10 @@ DatePicker.prototype.get = function( type ) { DatePicker.prototype.create = function( type, value, options ) { var isInfiniteValue, - calendar = this + calendar = this; // If there’s no value, use the type as the value. - value = value === undefined ? type : value + value = value === undefined ? type : value; // If it’s infinity, update the value. @@ -5733,7 +6402,7 @@ DatePicker.prototype.create = function( type, value, options ) { // If it’s an array, convert it into a date and make sure // that it’s a valid date – otherwise default to today. else if ( $.isArray( value ) ) { - value = new Date( value[ 0 ], value[ 1 ], value[ 2 ] ) + value = new Date(value[0], value[1], value[2]); value = _.isDate( value ) ? value : calendar.create().obj } @@ -5756,7 +6425,7 @@ DatePicker.prototype.create = function( type, value, options ) { obj: isInfiniteValue || value, pick: isInfiniteValue || value.getTime() } -} //DatePicker.prototype.create +}; //DatePicker.prototype.create /** @@ -5771,7 +6440,7 @@ DatePicker.prototype.createRange = function( from, to ) { return calendar.create( date ) } return date - } + }; // Create objects if possible. if ( !_.isInteger( from ) ) { @@ -5793,16 +6462,16 @@ DatePicker.prototype.createRange = function( from, to ) { from: createDate( from ), to: createDate( to ) } -} //DatePicker.prototype.createRange +}; //DatePicker.prototype.createRange /** * Check if a date unit falls within a date range object. */ DatePicker.prototype.withinRange = function( range, dateUnit ) { - range = this.createRange(range.from, range.to) + range = this.createRange(range.from, range.to); return dateUnit.pick >= range.from.pick && dateUnit.pick <= range.to.pick -} +}; /** @@ -5810,27 +6479,27 @@ DatePicker.prototype.withinRange = function( range, dateUnit ) { */ DatePicker.prototype.overlapRanges = function( one, two ) { - var calendar = this + var calendar = this; // Convert the ranges into comparable dates. - one = calendar.createRange( one.from, one.to ) - two = calendar.createRange( two.from, two.to ) + one = calendar.createRange(one.from, one.to); + two = calendar.createRange(two.from, two.to); return calendar.withinRange( one, two.from ) || calendar.withinRange( one, two.to ) || calendar.withinRange( two, one.from ) || calendar.withinRange( two, one.to ) -} +}; /** * Get the date today. */ DatePicker.prototype.now = function( type, value, options ) { - value = new Date() + value = new Date(); if ( options && options.rel ) { value.setDate( value.getDate() + options.rel ) } return this.normalize( value, options ) -} +}; /** @@ -5844,34 +6513,35 @@ DatePicker.prototype.navigate = function( type, value, options ) { targetDate, isTargetArray = $.isArray( value ), isTargetObject = $.isPlainObject( value ), - viewsetObject = this.item.view/*, - safety = 100*/ + viewsetObject = this.item.view; + /*, + safety = 100*/ if ( isTargetArray || isTargetObject ) { if ( isTargetObject ) { - targetYear = value.year - targetMonth = value.month + targetYear = value.year; + targetMonth = value.month; targetDate = value.date } else { - targetYear = +value[0] - targetMonth = +value[1] + targetYear = +value[0]; + targetMonth = +value[1]; targetDate = +value[2] } // If we’re navigating months but the view is in a different // month, navigate to the view’s year and month. if ( options && options.nav && viewsetObject && viewsetObject.month !== targetMonth ) { - targetYear = viewsetObject.year + targetYear = viewsetObject.year; targetMonth = viewsetObject.month } // Figure out the expected target year and month. - targetDateObject = new Date( targetYear, targetMonth + ( options && options.nav ? options.nav : 0 ), 1 ) - targetYear = targetDateObject.getFullYear() - targetMonth = targetDateObject.getMonth() + targetDateObject = new Date(targetYear, targetMonth + (options && options.nav ? options.nav : 0), 1); + targetYear = targetDateObject.getFullYear(); + targetMonth = targetDateObject.getMonth(); // If the month we’re going to doesn’t have enough days, // keep decreasing the date until we reach the month’s last date. @@ -5887,16 +6557,16 @@ DatePicker.prototype.navigate = function( type, value, options ) { } return value -} //DatePicker.prototype.navigate +}; //DatePicker.prototype.navigate /** * Normalize a date by setting the hours to midnight. */ DatePicker.prototype.normalize = function( value/*, options*/ ) { - value.setHours( 0, 0, 0, 0 ) + value.setHours(0, 0, 0, 0); return value -} +}; /** @@ -5904,7 +6574,7 @@ DatePicker.prototype.normalize = function( value/*, options*/ ) { */ DatePicker.prototype.measure = function( type, value/*, options*/ ) { - var calendar = this + var calendar = this; // If it’s anything false-y, remove the limits. if ( !value ) { @@ -5922,7 +6592,7 @@ DatePicker.prototype.measure = function( type, value/*, options*/ ) { } return value -} ///DatePicker.prototype.measure +}; ///DatePicker.prototype.measure /** @@ -5930,7 +6600,7 @@ DatePicker.prototype.measure = function( type, value/*, options*/ ) { */ DatePicker.prototype.viewset = function( type, dateObject/*, options*/ ) { return this.create([ dateObject.year, dateObject.month, 1 ]) -} +}; /** @@ -5964,16 +6634,17 @@ DatePicker.prototype.validate = function( type, dateObject, options ) { // If there’s a date, check where it is relative to the target. if ( $.isArray( value ) ) { - var dateTime = calendar.create( value ).pick - if ( dateTime < dateObject.pick ) hasEnabledBeforeTarget = true + var dateTime = calendar.create(value).pick; + if (dateTime < dateObject.pick) hasEnabledBeforeTarget = true; else if ( dateTime > dateObject.pick ) hasEnabledAfterTarget = true } // Return only integers for enabled weekdays. return _.isInteger( value ) - }).length/*, + }).length; + /*, - safety = 100*/ + safety = 100*/ @@ -6012,15 +6683,15 @@ DatePicker.prototype.validate = function( type, dateObject, options ) { // If we’ve looped into the next/prev month with a large interval, return to the original date and flatten the interval. if ( Math.abs( interval ) > 1 && ( dateObject.month < originalDateObject.month || dateObject.month > originalDateObject.month ) ) { - dateObject = originalDateObject + dateObject = originalDateObject; interval = interval > 0 ? 1 : -1 } // If we’ve reached the min/max limit, reverse the direction, flatten the interval and set it to the limit. if ( dateObject.pick <= minLimitObject.pick ) { - reachedMin = true - interval = 1 + reachedMin = true; + interval = 1; dateObject = calendar.create([ minLimitObject.year, minLimitObject.month, @@ -6028,8 +6699,8 @@ DatePicker.prototype.validate = function( type, dateObject, options ) { ]) } else if ( dateObject.pick >= maxLimitObject.pick ) { - reachedMax = true - interval = -1 + reachedMax = true; + interval = -1; dateObject = calendar.create([ maxLimitObject.year, maxLimitObject.month, @@ -6053,7 +6724,7 @@ DatePicker.prototype.validate = function( type, dateObject, options ) { // Return the date object settled on. return dateObject -} //DatePicker.prototype.validate +}; //DatePicker.prototype.validate /** @@ -6081,13 +6752,13 @@ DatePicker.prototype.disabled = function( dateToVerify ) { if ( $.isPlainObject( dateToDisable ) ) { return calendar.withinRange( dateToDisable, dateToVerify ) } - }) + }); // If this date matches a disabled date, confirm it’s not inverted. isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( dateToDisable ) { return $.isArray( dateToDisable ) && dateToDisable[3] == 'inverted' || $.isPlainObject( dateToDisable ) && dateToDisable.inverted - }).length + }).length; // Check the calendar “enabled” flag and respectively flip the // disabled state. Then also check if it’s beyond the min/max limits. @@ -6095,7 +6766,7 @@ DatePicker.prototype.disabled = function( dateToVerify ) { dateToVerify.pick < calendar.item.min.pick || dateToVerify.pick > calendar.item.max.pick -} //DatePicker.prototype.disabled +}; //DatePicker.prototype.disabled /** @@ -6104,7 +6775,7 @@ DatePicker.prototype.disabled = function( dateToVerify ) { DatePicker.prototype.parse = function( type, value, options ) { var calendar = this, - parsingObject = {} + parsingObject = {}; // If it’s already parsed, we’re good. if ( !value || typeof value != 'string' ) { @@ -6113,7 +6784,7 @@ DatePicker.prototype.parse = function( type, value, options ) { // We need a `.format` to parse the value with. if ( !( options && options.format ) ) { - options = options || {} + options = options || {}; options.format = calendar.settings.format } @@ -6126,7 +6797,7 @@ DatePicker.prototype.parse = function( type, value, options ) { // The format length is from the formatting label function or the // label length without the escaping exclamation (!) mark. - formatLength = formattingLabel ? _.trigger( formattingLabel, calendar, [ value, parsingObject ] ) : label.replace( /^!/, '' ).length + formatLength = formattingLabel ? _.trigger(formattingLabel, calendar, [value, parsingObject]) : label.replace(/^!/, '').length; // If there's a format label, split the value up to the format length. // Then add it to the parsing object with appropriate label. @@ -6136,7 +6807,7 @@ DatePicker.prototype.parse = function( type, value, options ) { // Update the value as the substring from format length to end. value = value.substr( formatLength ) - }) + }); // Compensate for month 0index. return [ @@ -6144,7 +6815,7 @@ DatePicker.prototype.parse = function( type, value, options ) { +( parsingObject.mm || parsingObject.m ) - 1, parsingObject.dd || parsingObject.d ] -} //DatePicker.prototype.parse +}; //DatePicker.prototype.parse /** @@ -6156,7 +6827,7 @@ DatePicker.prototype.formats = (function() { function getWordLengthFromCollection( string, collection, dateObject ) { // Grab the first word from the string. - var word = string.match( /\w+/ )[ 0 ] + var word = string.match(/\w+/)[0]; // If there's no month index, add it to the date object if ( !dateObject.mm && !dateObject.m ) { @@ -6212,7 +6883,7 @@ DatePicker.prototype.formats = (function() { }, mmm: function( string, dateObject ) { - var collection = this.settings.monthsShort + var collection = this.settings.monthsShort; // If there's a string, get length of the relevant month from the short // months collection. Otherwise return the selected month from that collection. @@ -6220,7 +6891,7 @@ DatePicker.prototype.formats = (function() { }, mmmm: function( string, dateObject ) { - var collection = this.settings.monthsFull + var collection = this.settings.monthsFull; // If there's a string, get length of the relevant month from the full // months collection. Otherwise return the selected month from that collection. @@ -6244,13 +6915,13 @@ DatePicker.prototype.formats = (function() { // Format an object into a string using the formatting options. toString: function ( formatString, itemObject ) { - var calendar = this + var calendar = this; return calendar.formats.toArray( formatString ).map( function( label ) { return _.trigger( calendar.formats[ label ], calendar, [ 0, itemObject ] ) || label.replace( /^!/, '' ) }).join( '' ) } } -})() //DatePicker.prototype.formats +})(); //DatePicker.prototype.formats @@ -6260,7 +6931,7 @@ DatePicker.prototype.formats = (function() { */ DatePicker.prototype.isDateExact = function( one, two ) { - var calendar = this + var calendar = this; // When we’re working with weekdays, do a direct comparison. if ( @@ -6284,7 +6955,7 @@ DatePicker.prototype.isDateExact = function( one, two ) { } return false -} +}; /** @@ -6293,15 +6964,15 @@ DatePicker.prototype.isDateExact = function( one, two ) { DatePicker.prototype.isDateOverlap = function( one, two ) { var calendar = this, - firstDay = calendar.settings.firstDay ? 1 : 0 + firstDay = calendar.settings.firstDay ? 1 : 0; // When we’re working with a weekday index, compare the days. if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) { - one = one % 7 + firstDay + one = one % 7 + firstDay; return one === calendar.create( two ).day + 1 } if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) { - two = two % 7 + firstDay + two = two % 7 + firstDay; return two === calendar.create( one ).day + 1 } @@ -6311,16 +6982,16 @@ DatePicker.prototype.isDateOverlap = function( one, two ) { } return false -} +}; /** * Flip the “enabled” state. */ DatePicker.prototype.flipEnable = function(val) { - var itemObject = this.item + var itemObject = this.item; itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1) -} +}; /** @@ -6329,7 +7000,7 @@ DatePicker.prototype.flipEnable = function(val) { DatePicker.prototype.deactivate = function( type, datesToDisable ) { var calendar = this, - disabledItems = calendar.item.disable.slice(0) + disabledItems = calendar.item.disable.slice(0); // If we’re flipping, that’s all we need to do. @@ -6338,12 +7009,12 @@ DatePicker.prototype.deactivate = function( type, datesToDisable ) { } else if ( datesToDisable === false ) { - calendar.flipEnable(1) + calendar.flipEnable(1); disabledItems = [] } else if ( datesToDisable === true ) { - calendar.flipEnable(-1) + calendar.flipEnable(-1); disabledItems = [] } @@ -6352,13 +7023,13 @@ DatePicker.prototype.deactivate = function( type, datesToDisable ) { datesToDisable.map(function( unitToDisable ) { - var matchFound + var matchFound; // When we have disabled items, check for matches. // If something is matched, immediately break out. for ( var index = 0; index < disabledItems.length; index += 1 ) { if ( calendar.isDateExact( unitToDisable, disabledItems[index] ) ) { - matchFound = true + matchFound = true; break } } @@ -6379,7 +7050,7 @@ DatePicker.prototype.deactivate = function( type, datesToDisable ) { // Return the updated collection. return disabledItems -} //DatePicker.prototype.deactivate +}; //DatePicker.prototype.deactivate /** @@ -6389,7 +7060,7 @@ DatePicker.prototype.activate = function( type, datesToEnable ) { var calendar = this, disabledItems = calendar.item.disable, - disabledItemsCount = disabledItems.length + disabledItemsCount = disabledItems.length; // If we’re flipping, that’s all we need to do. if ( datesToEnable == 'flip' ) { @@ -6397,12 +7068,12 @@ DatePicker.prototype.activate = function( type, datesToEnable ) { } else if ( datesToEnable === true ) { - calendar.flipEnable(1) + calendar.flipEnable(1); disabledItems = [] } else if ( datesToEnable === false ) { - calendar.flipEnable(-1) + calendar.flipEnable(-1); disabledItems = [] } @@ -6414,28 +7085,28 @@ DatePicker.prototype.activate = function( type, datesToEnable ) { var matchFound, disabledUnit, index, - isExactRange + isExactRange; // Go through the disabled items and try to find a match. for ( index = 0; index < disabledItemsCount; index += 1 ) { - disabledUnit = disabledItems[index] + disabledUnit = disabledItems[index]; // When an exact match is found, remove it from the collection. if ( calendar.isDateExact( disabledUnit, unitToEnable ) ) { - matchFound = disabledItems[index] = null - isExactRange = true + matchFound = disabledItems[index] = null; + isExactRange = true; break } // When an overlapped match is found, add the “inverted” state to it. else if ( calendar.isDateOverlap( disabledUnit, unitToEnable ) ) { if ( $.isPlainObject( unitToEnable ) ) { - unitToEnable.inverted = true + unitToEnable.inverted = true; matchFound = unitToEnable } else if ( $.isArray( unitToEnable ) ) { - matchFound = unitToEnable + matchFound = unitToEnable; if ( !matchFound[3] ) matchFound.push( 'inverted' ) } else if ( _.isDate( unitToEnable ) ) { @@ -6448,7 +7119,7 @@ DatePicker.prototype.activate = function( type, datesToEnable ) { // If a match was found, remove a previous duplicate entry. if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) { if ( calendar.isDateExact( disabledItems[index], unitToEnable ) ) { - disabledItems[index] = null + disabledItems[index] = null; break } } @@ -6457,7 +7128,7 @@ DatePicker.prototype.activate = function( type, datesToEnable ) { // make sure there are no “inverted” dates because of it. if ( isExactRange ) for ( index = 0; index < disabledItemsCount; index += 1 ) { if ( calendar.isDateOverlap( disabledItems[index], unitToEnable ) ) { - disabledItems[index] = null + disabledItems[index] = null; break } } @@ -6471,7 +7142,7 @@ DatePicker.prototype.activate = function( type, datesToEnable ) { // Return the updated collection. return disabledItems.filter(function( val ) { return val != null }) -} //DatePicker.prototype.activate +}; //DatePicker.prototype.activate /** @@ -6498,7 +7169,7 @@ DatePicker.prototype.nodes = function( isOpen ) { // If the first day should be Monday, move Sunday to the end. if ( settings.firstDay ) { - collection.push( collection.shift() ) + collection.push(collection.shift()); fullCollection.push( fullCollection.shift() ) } @@ -6555,7 +7226,7 @@ DatePicker.prototype.nodes = function( isOpen ) { //Materialize modified createMonthLabel = function(override) { - var monthsCollection = settings.showMonthsShort ? settings.monthsShort : settings.monthsFull + var monthsCollection = settings.showMonthsShort ? settings.monthsShort : settings.monthsFull; // Materialize modified if (override == "short_months") { @@ -6617,7 +7288,7 @@ DatePicker.prototype.nodes = function( isOpen ) { // If years selector is set to a literal "true", set it to 5. Otherwise // divide in half to get half before and half after focused year. - numberYears = settings.selectYears === true ? 5 : ~~( settings.selectYears / 2 ) + numberYears = settings.selectYears === true ? 5 : ~~(settings.selectYears / 2); // If there are years to select, add a dropdown menu. if ( numberYears ) { @@ -6626,12 +7297,12 @@ DatePicker.prototype.nodes = function( isOpen ) { minYear = minLimitObject.year, maxYear = maxLimitObject.year, lowestYear = focusedYear - numberYears, - highestYear = focusedYear + numberYears + highestYear = focusedYear + numberYears; // If the min year is greater than the lowest year, increase the highest year // by the difference and set the lowest year to the min year. if ( minYear > lowestYear ) { - highestYear += minYear - lowestYear + highestYear += minYear - lowestYear; lowestYear = minYear } @@ -6641,9 +7312,9 @@ DatePicker.prototype.nodes = function( isOpen ) { if ( maxYear < highestYear ) { var availableYears = lowestYear - minYear, - neededYears = highestYear - maxYear + neededYears = highestYear - maxYear; - lowestYear -= availableYears > neededYears ? neededYears : availableYears + lowestYear -= availableYears > neededYears ? neededYears : availableYears; highestYear = maxYear } @@ -6674,19 +7345,19 @@ DatePicker.prototype.nodes = function( isOpen ) { // Materialize modified if (override == "raw") - return _.node( 'div', focusedYear ) + return _.node('div', focusedYear); // Otherwise just return the year focused return _.node( 'div', focusedYear, settings.klass.year ) - } //createYearLabel + }; //createYearLabel // Materialize modified createDayLabel = function() { if (selectedObject != null) - return _.node( 'div', selectedObject.date) + return _.node('div', selectedObject.date); else return _.node( 'div', nowObject.date) - } + }; createWeekdayLabel = function() { var display_day; @@ -6694,9 +7365,9 @@ DatePicker.prototype.nodes = function( isOpen ) { display_day = selectedObject.day; else display_day = nowObject.day; - var weekday = settings.weekdaysFull[ display_day ] + var weekday = settings.weekdaysFull[display_day]; return weekday - } + }; // Create and return the entire calendar. @@ -6747,7 +7418,7 @@ return _.node( item: function( rowCounter ) { // If Monday is the first day and the month starts on Sunday, shift the date back a week. - var shiftDateBy = settings.firstDay && calendar.create([ viewsetObject.year, viewsetObject.month, 1 ]).day === 0 ? -7 : 0 + var shiftDateBy = settings.firstDay && calendar.create([viewsetObject.year, viewsetObject.month, 1]).day === 0 ? -7 : 0; return [ _.group({ @@ -6760,12 +7431,12 @@ return _.node( item: function( targetDate ) { // Convert the time date from a relative date to a target date. - targetDate = calendar.create([ viewsetObject.year, viewsetObject.month, targetDate + ( settings.firstDay ? 1 : 0 ) ]) + targetDate = calendar.create([viewsetObject.year, viewsetObject.month, targetDate + (settings.firstDay ? 1 : 0)]); var isSelected = selectedObject && selectedObject.pick == targetDate.pick, isHighlighted = highlightedObject && highlightedObject.pick == targetDate.pick, isDisabled = disabledCollection && calendar.disabled( targetDate ) || targetDate.pick < minLimitObject.pick || targetDate.pick > maxLimitObject.pick, - formattedDate = _.trigger( calendar.formats.toString, calendar, [ settings.format, targetDate ] ) + formattedDate = _.trigger(calendar.formats.toString, calendar, [settings.format, targetDate]); return [ _.node( @@ -6774,7 +7445,7 @@ return _.node( (function( klasses ) { // Add the `infocus` or `outfocus` classes based on month in view. - klasses.push( viewsetObject.month == targetDate.month ? settings.klass.infocus : settings.klass.outfocus ) + klasses.push(viewsetObject.month == targetDate.month ? settings.klass.infocus : settings.klass.outfocus); // Add the `today` class if needed. if ( nowObject.pick == targetDate.pick ) { @@ -6843,7 +7514,7 @@ return _.node( _.ariaAttr({ controls: calendar.$node[0].id }) ), settings.klass.footer ) //endreturn -} //DatePicker.prototype.nodes +}; //DatePicker.prototype.nodes @@ -6925,7 +7596,7 @@ DatePicker.defaults = (function( prefix ) { buttonClose: prefix + 'button--close' } } -})( Picker.klasses().picker + '__' ) +})(Picker.klasses().picker + '__'); @@ -6940,9 +7611,8 @@ Picker.extend( 'pickadate', DatePicker ) })); -;(function ($) { - - $.fn.characterCounter = function(){ +(function ($) { + $.fn.characterCounter = function () { return this.each(function(){ var $input = $(this); var $counterElement = $input.parent().find('span[class="character-counter"]'); @@ -7012,14 +7682,13 @@ Picker.extend( 'pickadate', DatePicker ) }); }( jQuery )); -;(function ($) { - - var methods = { +(function ($) { + var methods = { init : function(options) { var defaults = { time_constant: 200, // ms - dist: -100, // zoom scale TODO: make this more intuitive as an option + dist: -100, // zoom scale shift: 0, // spacing for center image padding: 0, // Padding between non center items full_width: false, // Change to full width styles diff --git a/Plan/src/main/resources/web/plugins/momentjs/moment.js b/Plan/src/main/resources/web/plugins/momentjs/moment.js index 714b4c441..a375a9527 100644 --- a/Plan/src/main/resources/web/plugins/momentjs/moment.js +++ b/Plan/src/main/resources/web/plugins/momentjs/moment.js @@ -873,7 +873,6 @@ this._shortMonthsParse = []; } - // TODO: add sorting // Sorting makes sure if one month (or abbr) is a prefix of another // see sorting in computeMonthsParse for (i = 0; i < 12; i++) { @@ -913,7 +912,6 @@ value = toInt(value); } else { value = mom.localeData().monthsParse(value); - // TODO: Another silent failure? if (typeof value !== 'number') { return mom; } @@ -1756,7 +1754,6 @@ function loadLocale(name) { var oldLocale = null; - // TODO: Find a better way to register and load all the locales in Node if (!locales[name] && (typeof module !== 'undefined') && module && module.exports) { try { @@ -2120,10 +2117,6 @@ dow = 1; doy = 4; - // TODO: We need to take the current isoWeekYear, but that depends on - // how we interpret now (local, utc, fixed offset). So create - // a now version of current config (take local/utc/offset flags, and - // create now). weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year); week = defaults(w.W, 1); weekday = defaults(w.E, 1); @@ -2170,7 +2163,6 @@ // date from string and format string function configFromStringAndFormat(config) { - // TODO: Move this to another part of the creation flow to prevent circular deps if (config._f === utils_hooks__hooks.ISO_8601) { configFromISO(config); return; @@ -2462,7 +2454,6 @@ return res; } - // TODO: Use [].sort instead? function min () { var args = [].slice.call(arguments, 0); @@ -2842,7 +2833,6 @@ } } - // TODO: remove 'name' arg after deprecation is removed function createAdder(direction, name) { return function (val, period) { var dur, tmp; @@ -3924,7 +3914,6 @@ } } - // TODO: Use this.as('ms')? function duration_as__valueOf () { return ( this._milliseconds + diff --git a/Plan/src/main/resources/web/server.html b/Plan/src/main/resources/web/server.html index eaba8be23..313e6aac4 100644 --- a/Plan/src/main/resources/web/server.html +++ b/Plan/src/main/resources/web/server.html @@ -31,6 +31,9 @@ + + + @@ -281,7 +284,7 @@ person
    -
    UNIQUE PLAYERS / 24h
    +
    UNIQUE / 24h
    ${playersDay}
    @@ -292,7 +295,7 @@ person_add
    -
    NEW PLAYERS / 24h
    +
    NEW / 24h
    ${playersNewDay}
    @@ -636,9 +639,7 @@ -
    - ${accordionSessions} -
    + ${accordionSessions} @@ -682,16 +683,16 @@
    -
    +
    -
    +
    -
    +
    -
    +
    @@ -877,7 +878,9 @@

    Command Usage

    -

    Used Commands: ${commandCount} Unique: ${commandUniqueCount}

    +

    Used + Commands: ${commandCount} + Unique: ${commandUniqueCount}

    @@ -907,9 +910,6 @@ - - - @@ -933,7 +933,7 @@ - + @@ -943,7 +943,7 @@ - + @@ -955,101 +955,190 @@ @@ -1077,18 +1166,18 @@ openFunc(slideIndex)(); // Chart draw scripts - activityPie('activityPie', activitySeries); - activityStackChart('activityStackGraph', activityCategories, activityStackSeries); - worldPie('worldPie', worldSeries, gmSeries); - playersChart('playerChartDay', playersOnlineSeries, 3); - playersChart('playerChartMonth', playersOnlineSeries, 2); - performanceChart('performanceGraph', playersOnlineSeries, tpsSeries, cpuSeries, ramSeries, entitySeries, chunkSeries); - tpsChart('tpsGraph', tpsSeries, playersOnlineSeries); - resourceChart('resourceGraph', cpuSeries, ramSeries, playersOnlineSeries); - worldChart('worldGraph', entitySeries, chunkSeries, playersOnlineSeries); - worldMap('worldMap', '${worldMapColLow}', '${worldMapColHigh}', mapSeries); - punchCard('punchCard', punchcardSeries); - healthGauge('healthGauge', [${healthIndex}]); + activityPie('activityPie', series.activityPie); + stackChart('activityStackGraph', series.activityStackCategories, series.activityStack, 'Players'); + worldPie('worldPie', series.worldPie, series.worldPieDrillDown); + playersChart('playerChartDay', series.playersOnline, 3); + playersChart('playerChartMonth', series.playersOnline, 2); + performanceChart('performanceGraph', series.playersOnline, series.tps, series.cpu, series.ram, series.entities, series.chunks); + tpsChart('tpsGraph', series.tps, series.playersOnline); + resourceChart('resourceGraph', series.cpu_alt, series.ram_alt, series.playersOnline); + worldChart('worldGraph', series.entities_alt, series.chunks_alt, series.playersOnline); + worldMap('worldMap', v.colors.geolocationsLow, v.colors.geolocationsHigh, series.geolocations); + punchCard('punchCard', series.punchCard); + healthGauge('healthGauge', [v.data.healthIndex]); ${sessionTabGraphViewFunctions} /**/ diff --git a/Plan/test/main/java/com/djrapitops/plan/data/PlayerKillTest.java b/Plan/src/test/java/com/djrapitops/plan/data/PlayerKillTest.java similarity index 96% rename from Plan/test/main/java/com/djrapitops/plan/data/PlayerKillTest.java rename to Plan/src/test/java/com/djrapitops/plan/data/PlayerKillTest.java index 881746830..387584594 100644 --- a/Plan/test/main/java/com/djrapitops/plan/data/PlayerKillTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/data/PlayerKillTest.java @@ -7,7 +7,7 @@ package com.djrapitops.plan.data; import com.djrapitops.plan.data.container.PlayerKill; import org.junit.Test; -import test.utilities.RandomData; +import utilities.RandomData; import java.util.UUID; diff --git a/Plan/test/main/java/com/djrapitops/plan/data/PlayerProfileTest.java b/Plan/src/test/java/com/djrapitops/plan/data/PlayerProfileTest.java similarity index 83% rename from Plan/test/main/java/com/djrapitops/plan/data/PlayerProfileTest.java rename to Plan/src/test/java/com/djrapitops/plan/data/PlayerProfileTest.java index 9ebcd87f7..0827fd968 100644 --- a/Plan/test/main/java/com/djrapitops/plan/data/PlayerProfileTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/data/PlayerProfileTest.java @@ -1,16 +1,16 @@ package com.djrapitops.plan.data; import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.settings.Settings; +import com.djrapitops.plan.system.settings.Settings; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.api.TimeAmount; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.TestInit; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.mocks.SystemMockUtil; import java.util.ArrayList; import java.util.List; @@ -18,18 +18,15 @@ import java.util.List; import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertTrue; -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) +@RunWith(MockitoJUnitRunner.Silent.class) public class PlayerProfileTest { - @Before - public void setUp() throws Exception { - TestInit.init(); + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @BeforeClass + public static void setUpClass() throws Exception { + SystemMockUtil.setUp(temporaryFolder.getRoot()).enableConfigSystem(); } @Test @@ -53,7 +50,7 @@ public class PlayerProfileTest { } p.setSessions(null, sessions); - assertEquals(5.0, p.getActivityIndex(date)); + assertEquals(5.0, p.getActivityIndex(date).getValue()); } @Test @@ -77,7 +74,7 @@ public class PlayerProfileTest { } p.setSessions(null, sessions); - assertEquals(5.0, p.getActivityIndex(date)); + assertEquals(5.0, p.getActivityIndex(date).getValue()); } @Test @@ -101,7 +98,7 @@ public class PlayerProfileTest { } p.setSessions(null, sessions); - assertTrue(2.0 <= p.getActivityIndex(date)); + assertTrue(2.0 <= p.getActivityIndex(date).getValue()); } @Test(timeout = 500) diff --git a/Plan/test/main/java/com/djrapitops/plan/data/additional/importer/ImportBuilderTest.java b/Plan/src/test/java/com/djrapitops/plan/data/additional/importer/ImportBuilderTest.java similarity index 96% rename from Plan/test/main/java/com/djrapitops/plan/data/additional/importer/ImportBuilderTest.java rename to Plan/src/test/java/com/djrapitops/plan/data/additional/importer/ImportBuilderTest.java index 42e728f0b..9bfb8f7e9 100644 --- a/Plan/test/main/java/com/djrapitops/plan/data/additional/importer/ImportBuilderTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/data/additional/importer/ImportBuilderTest.java @@ -7,11 +7,11 @@ package com.djrapitops.plan.data.additional.importer; import com.djrapitops.plan.data.container.PlayerKill; import com.djrapitops.plan.data.container.TPS; import com.djrapitops.plan.data.time.GMTimes; -import com.djrapitops.plan.systems.processing.importing.ServerImportData; -import com.djrapitops.plan.systems.processing.importing.UserImportData; +import com.djrapitops.plan.system.processing.importing.ServerImportData; +import com.djrapitops.plan.system.processing.importing.UserImportData; import com.google.common.collect.ImmutableMap; import org.junit.Test; -import test.utilities.RandomData; +import utilities.RandomData; import java.util.Arrays; import java.util.Collections; diff --git a/Plan/test/main/java/com/djrapitops/plan/data/cache/GeolocationCacheTest.java b/Plan/src/test/java/com/djrapitops/plan/data/cache/GeolocationCacheTest.java similarity index 71% rename from Plan/test/main/java/com/djrapitops/plan/data/cache/GeolocationCacheTest.java rename to Plan/src/test/java/com/djrapitops/plan/data/cache/GeolocationCacheTest.java index 0f1a3dc6d..9e7771bad 100644 --- a/Plan/test/main/java/com/djrapitops/plan/data/cache/GeolocationCacheTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/data/cache/GeolocationCacheTest.java @@ -1,13 +1,15 @@ package com.djrapitops.plan.data.cache; -import com.djrapitops.plan.systems.cache.GeolocationCache; -import org.bukkit.plugin.java.JavaPlugin; +import com.djrapitops.plan.system.cache.CacheSystem; +import com.djrapitops.plan.system.cache.GeolocationCache; import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.TestInit; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.mocks.SystemMockUtil; import java.util.HashMap; import java.util.Map; @@ -17,16 +19,24 @@ import static junit.framework.TestCase.*; /** * @author Fuzzlemann */ -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) +@RunWith(MockitoJUnitRunner.Silent.class) public class GeolocationCacheTest { private final Map ipsToCountries = new HashMap<>(); + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @BeforeClass + public static void setUpClass() throws Exception { + SystemMockUtil.setUp(temporaryFolder.getRoot()) + .enableConfigSystem() + .enableCacheSystem(); + } + @Before - public void setUp() throws Exception { - TestInit.init(); - GeolocationCache.clearCache(); + public void setUp() { + CacheSystem.getInstance().getGeolocationCache().clearCache(); ipsToCountries.put("8.8.8.8", "United States"); ipsToCountries.put("8.8.4.4", "United States"); diff --git a/Plan/src/test/java/com/djrapitops/plan/data/cache/ResponseCacheTest.java b/Plan/src/test/java/com/djrapitops/plan/data/cache/ResponseCacheTest.java new file mode 100644 index 000000000..d33b9e0bc --- /dev/null +++ b/Plan/src/test/java/com/djrapitops/plan/data/cache/ResponseCacheTest.java @@ -0,0 +1,41 @@ +package com.djrapitops.plan.data.cache; + +import com.djrapitops.plan.system.webserver.response.Response; +import com.djrapitops.plan.system.webserver.response.cache.ResponseCache; +import org.junit.Test; +import utilities.RandomData; + +import static junit.framework.TestCase.*; + +/** + * @author Fuzzlemann + */ +public class ResponseCacheTest { + private final String IDENTIFIER = RandomData.randomString(10); + private final String RESPONSE_STRING = RandomData.randomString(10); + private final Response RESPONSE = new Response() { + @Override + public String getResponse() { + return RESPONSE_STRING; + } + }; + + @Test + public void testCache() { + assertFalse(ResponseCache.isCached(IDENTIFIER)); + + Response response = ResponseCache.loadResponse(IDENTIFIER, () -> RESPONSE); + assertTrue(ResponseCache.isCached(IDENTIFIER)); + + assertEquals(RESPONSE, response); + } + + @Test + public void testClearCache() { + ResponseCache.cacheResponse(IDENTIFIER, () -> RESPONSE); + assertTrue(ResponseCache.isCached(IDENTIFIER)); + + ResponseCache.clearCache(); + assertFalse(ResponseCache.isCached(IDENTIFIER)); + } +} diff --git a/Plan/test/main/java/com/djrapitops/plan/data/time/GMTimesTest.java b/Plan/src/test/java/com/djrapitops/plan/data/time/GMTimesTest.java similarity index 100% rename from Plan/test/main/java/com/djrapitops/plan/data/time/GMTimesTest.java rename to Plan/src/test/java/com/djrapitops/plan/data/time/GMTimesTest.java diff --git a/Plan/test/main/java/com/djrapitops/plan/data/time/WorldTimesTest.java b/Plan/src/test/java/com/djrapitops/plan/data/time/WorldTimesTest.java similarity index 99% rename from Plan/test/main/java/com/djrapitops/plan/data/time/WorldTimesTest.java rename to Plan/src/test/java/com/djrapitops/plan/data/time/WorldTimesTest.java index b193bf6e8..72c0dad0e 100644 --- a/Plan/test/main/java/com/djrapitops/plan/data/time/WorldTimesTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/data/time/WorldTimesTest.java @@ -2,7 +2,7 @@ package com.djrapitops.plan.data.time; import com.google.common.collect.ImmutableMap; import org.junit.Test; -import test.utilities.RandomData; +import utilities.RandomData; import java.util.ArrayList; import java.util.List; diff --git a/Plan/src/test/java/com/djrapitops/plan/system/BukkitSystemTest.java b/Plan/src/test/java/com/djrapitops/plan/system/BukkitSystemTest.java new file mode 100644 index 000000000..14ae63ef5 --- /dev/null +++ b/Plan/src/test/java/com/djrapitops/plan/system/BukkitSystemTest.java @@ -0,0 +1,61 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.system.settings.Settings; +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.Teardown; +import utilities.mocks.BukkitMockUtil; + +/** + * Test for BukkitSystem. + * + * @author Rsl1122 + */ +@RunWith(MockitoJUnitRunner.Silent.class) +public class BukkitSystemTest { + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + private static Plan planMock; + private BukkitSystem bukkitSystem; + + @BeforeClass + public static void setUpClass() throws Exception { + BukkitMockUtil mockUtil = BukkitMockUtil.setUp() + .withDataFolder(temporaryFolder.getRoot()) + .withLogging() + .withPluginDescription() + .withResourceFetchingFromJar() + .withServer(); + planMock = mockUtil.getPlanMock(); + } + + @Before + public void setUp() { + Teardown.resetSettingsTempValues(); + } + + @After + public void tearDown() { + if (bukkitSystem != null) { + bukkitSystem.disable(); + } + Teardown.resetSettingsTempValues(); + } + + @Test + public void testEnable() throws EnableException { + Settings.WEBSERVER_PORT.setTemporaryValue(9000); + + bukkitSystem = new BukkitSystem(planMock); + bukkitSystem.enable(); + } +} \ No newline at end of file diff --git a/Plan/src/test/java/com/djrapitops/plan/system/BungeeBukkitConnectionTest.java b/Plan/src/test/java/com/djrapitops/plan/system/BungeeBukkitConnectionTest.java new file mode 100644 index 000000000..069be97b2 --- /dev/null +++ b/Plan/src/test/java/com/djrapitops/plan/system/BungeeBukkitConnectionTest.java @@ -0,0 +1,121 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.PlanBungee; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.api.exceptions.connection.WebException; +import com.djrapitops.plan.system.database.BukkitDBSystem; +import com.djrapitops.plan.system.info.request.GenerateInspectPageRequest; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.settings.Settings; +import org.junit.*; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.Teardown; +import utilities.TestConstants; +import utilities.mocks.BukkitMockUtil; +import utilities.mocks.BungeeMockUtil; + +import java.util.UUID; + +/** + * @author Rsl1122 + */ +@RunWith(MockitoJUnitRunner.Silent.class) +public class BungeeBukkitConnectionTest { + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + private static Plan bukkitMock; + private static PlanBungee bungeeMock; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private BukkitSystem bukkitSystem; + private BungeeSystem bungeeSystem; + + private UUID bukkitUUID; + private UUID bungeeUUID; + + @BeforeClass + public static void setUpClass() throws Exception { + BukkitMockUtil bukkitMockUtil = BukkitMockUtil.setUp() + .withDataFolder(temporaryFolder.getRoot()) + .withLogging() + .withPluginDescription() + .withResourceFetchingFromJar() + .withServer(); + bukkitMock = bukkitMockUtil.getPlanMock(); + + BungeeMockUtil bungeeMockUtil = BungeeMockUtil.setUp() + .withDataFolder(temporaryFolder.getRoot()) + .withLogging() + .withPluginDescription() + .withResourceFetchingFromJar() + .withProxy(); + bungeeMock = bungeeMockUtil.getPlanMock(); + } + + @Before + public void setUp() { + Teardown.resetSettingsTempValues(); + Settings.DEBUG.setTemporaryValue("console"); + Settings.DEV_MODE.setTemporaryValue(true); + } + + @After + public void tearDown() { + System.out.println("------------------------------"); + System.out.println("Disable"); + System.out.println("------------------------------"); + if (bukkitSystem != null) { + bukkitSystem.disable(); + } + if (bungeeSystem != null) { + bungeeSystem.disable(); + } + Teardown.resetSettingsTempValues(); + } + + public void enable() throws EnableException { + Settings.WEBSERVER_PORT.setTemporaryValue(9000); + + bukkitSystem = new BukkitSystem(bukkitMock); + bukkitSystem.enable(); + + bukkitUUID = ServerInfo.getServerUUID(); + + bungeeSystem = new BungeeSystem(bungeeMock); + + Settings.WEBSERVER_PORT.setTemporaryValue(9250); + Settings.BUNGEE_IP.setTemporaryValue("localhost"); + Settings.DB_TYPE.setTemporaryValue("sqlite"); + bungeeSystem.setDatabaseSystem(new BukkitDBSystem()); + + bungeeSystem.enable(); + + bungeeUUID = ServerInfo.getServerUUID(); + + System.out.println("------------------------------"); + System.out.println("Enable Complete"); + System.out.println("Bukkit: " + bukkitUUID); + System.out.println("Bungee: " + bungeeUUID); + System.out.println("------------------------------"); + } + + @Test + @Ignore("Causes next BungeeSystem test to fail") + public void testRequest() throws EnableException, WebException { + enable(); + + System.out.println("Sending request"); + bungeeSystem.getInfoSystem().getConnectionSystem().sendWideInfoRequest(new GenerateInspectPageRequest(TestConstants.PLAYER_ONE_UUID)); + } +} \ No newline at end of file diff --git a/Plan/src/test/java/com/djrapitops/plan/system/BungeeSystemTest.java b/Plan/src/test/java/com/djrapitops/plan/system/BungeeSystemTest.java new file mode 100644 index 000000000..384802906 --- /dev/null +++ b/Plan/src/test/java/com/djrapitops/plan/system/BungeeSystemTest.java @@ -0,0 +1,93 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system; + +import com.djrapitops.plan.PlanBungee; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.system.database.BukkitDBSystem; +import com.djrapitops.plan.system.settings.Settings; +import org.junit.*; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.Teardown; +import utilities.mocks.BungeeMockUtil; + +/** + * Test for BukkitSystem. + * + * @author Rsl1122 + */ +@RunWith(MockitoJUnitRunner.Silent.class) +public class BungeeSystemTest { + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + private static PlanBungee planMock; + @Rule + public ExpectedException thrown = ExpectedException.none(); + private BungeeSystem bungeeSystem; + + @BeforeClass + public static void setUpClass() throws Exception { + BungeeMockUtil mockUtil = BungeeMockUtil.setUp() + .withDataFolder(temporaryFolder.getRoot()) + .withLogging() + .withPluginDescription() + .withResourceFetchingFromJar() + .withProxy(); + planMock = mockUtil.getPlanMock(); + } + + + @Before + public void setUp() { + Teardown.resetSettingsTempValues(); + } + + @After + public void tearDown() { + if (bungeeSystem != null) { + bungeeSystem.disable(); + } + Teardown.resetSettingsTempValues(); + } + + @Test + public void testEnable() throws EnableException { + bungeeSystem = new BungeeSystem(planMock); + + Settings.WEBSERVER_PORT.setTemporaryValue(9000); + Settings.BUNGEE_IP.setTemporaryValue("8.8.8.8"); + Settings.DB_TYPE.setTemporaryValue("sqlite"); + bungeeSystem.setDatabaseSystem(new BukkitDBSystem()); + + bungeeSystem.enable(); + } + + @Test + public void testEnableDefaultIP() throws EnableException { + thrown.expect(EnableException.class); + thrown.expectMessage("IP setting still 0.0.0.0 - Configure AlternativeIP/IP that connects to the Proxy server."); + + bungeeSystem = new BungeeSystem(planMock); + + Settings.WEBSERVER_PORT.setTemporaryValue(9000); + Settings.DB_TYPE.setTemporaryValue("sqlite"); + bungeeSystem.setDatabaseSystem(new BukkitDBSystem()); + + bungeeSystem.enable(); + } + + @Test + public void testEnableNoMySQL() throws EnableException { + thrown.expect(EnableException.class); + thrown.expectMessage("Database failed to initialize"); + + bungeeSystem = new BungeeSystem(planMock); + bungeeSystem.enable(); + } +} \ No newline at end of file diff --git a/Plan/test/main/java/com/djrapitops/plan/systems/cache/SessionCacheTest.java b/Plan/src/test/java/com/djrapitops/plan/system/cache/SessionCacheTest.java similarity index 52% rename from Plan/test/main/java/com/djrapitops/plan/systems/cache/SessionCacheTest.java rename to Plan/src/test/java/com/djrapitops/plan/system/cache/SessionCacheTest.java index 9b8d890b3..b80c95144 100644 --- a/Plan/test/main/java/com/djrapitops/plan/systems/cache/SessionCacheTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/system/cache/SessionCacheTest.java @@ -1,15 +1,13 @@ -package com.djrapitops.plan.systems.cache; +package com.djrapitops.plan.system.cache; import com.djrapitops.plan.data.container.Session; -import org.bukkit.plugin.java.JavaPlugin; import org.junit.Before; -import org.junit.Ignore; +import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.MockUtils; -import test.utilities.TestInit; +import org.junit.rules.TemporaryFolder; +import utilities.TestConstants; +import utilities.mocks.SystemMockUtil; import java.util.Optional; import java.util.UUID; @@ -17,27 +15,31 @@ import java.util.UUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) public class SessionCacheTest { - private final UUID uuid = MockUtils.getPlayerUUID(); + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); private SessionCache sessionCache; private Session session; + private final UUID uuid = TestConstants.PLAYER_ONE_UUID; + + @BeforeClass + public static void setUpClass() throws Exception { + SystemMockUtil.setUp(temporaryFolder.getRoot()) + .enableProcessingQueue(); + } @Before - public void setUp() throws Exception { - TestInit t = TestInit.init(); + public void setUp() { sessionCache = new SessionCache(null); session = new Session(12345L, "World1", "SURVIVAL"); sessionCache.cacheSession(uuid, session); } @Test - @Ignore("Ignored, Requires more mocks") public void testAtomity() { SessionCache reloaded = new SessionCache(null); - Optional cachedSession = reloaded.getCachedSession(uuid); + Optional cachedSession = SessionCache.getCachedSession(uuid); assertTrue(cachedSession.isPresent()); assertEquals(session, cachedSession.get()); } diff --git a/Plan/src/test/java/com/djrapitops/plan/system/database/databases/MySQLTest.java b/Plan/src/test/java/com/djrapitops/plan/system/database/databases/MySQLTest.java new file mode 100644 index 000000000..d4b17c932 --- /dev/null +++ b/Plan/src/test/java/com/djrapitops/plan/system/database/databases/MySQLTest.java @@ -0,0 +1,29 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.system.database.databases; + +import com.djrapitops.plan.system.database.databases.sql.MySQLDB; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Tests MySQLDB. + * + * @author Rsl1122 + */ +public class MySQLTest { + + @Test + public void testMySQLGetConfigName() { + assertEquals("mysql", new MySQLDB().getConfigName()); + } + + @Test + public void testMySQLGetName() { + assertEquals("MySQL", new MySQLDB().getName()); + } + +} \ No newline at end of file diff --git a/Plan/test/main/java/com/djrapitops/plan/database/DatabaseTest.java b/Plan/src/test/java/com/djrapitops/plan/system/database/databases/SQLiteTest.java similarity index 60% rename from Plan/test/main/java/com/djrapitops/plan/database/DatabaseTest.java rename to Plan/src/test/java/com/djrapitops/plan/system/database/databases/SQLiteTest.java index e98c3dd16..54ac0a354 100644 --- a/Plan/test/main/java/com/djrapitops/plan/database/DatabaseTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/system/database/databases/SQLiteTest.java @@ -3,121 +3,110 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.djrapitops.plan.database; +package com.djrapitops.plan.system.database.databases; import com.djrapitops.plan.Plan; -import com.djrapitops.plan.api.exceptions.DatabaseInitException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.api.exceptions.database.DBInitException; +import com.djrapitops.plan.data.Actions; import com.djrapitops.plan.data.WebUser; import com.djrapitops.plan.data.container.*; import com.djrapitops.plan.data.time.GMTimes; import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.database.databases.MySQLDB; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.databases.SQLiteDB; -import com.djrapitops.plan.database.tables.*; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.info.server.ServerInfo; -import com.djrapitops.plan.systems.processing.player.RegisterProcessor; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.SQLiteDB; +import com.djrapitops.plan.system.database.databases.sql.tables.*; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.processing.processors.player.RegisterProcessor; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.utilities.Base64Util; import com.djrapitops.plan.utilities.ManageUtils; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plan.utilities.analysis.MathUtils; -import com.djrapitops.plan.utilities.file.FileUtil; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import com.djrapitops.plugin.StaticHolder; +import com.djrapitops.plugin.api.utility.log.Log; +import org.junit.*; +import org.junit.rules.TemporaryFolder; import org.junit.rules.Timeout; import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.MockUtils; -import test.utilities.RandomData; -import test.utilities.TestInit; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.RandomData; +import utilities.Teardown; +import utilities.TestConstants; +import utilities.TestErrorManager; +import utilities.mocks.SystemMockUtil; -import java.io.File; -import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import java.sql.SQLException; import java.util.*; import static org.junit.Assert.*; -import static org.powermock.api.mockito.PowerMockito.when; /** * @author Rsl1122 */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({JavaPlugin.class}) -public class DatabaseTest { +@RunWith(MockitoJUnitRunner.Silent.class) +public class SQLiteTest { - private final UUID uuid = MockUtils.getPlayerUUID(); private final List worlds = Arrays.asList("TestWorld", "TestWorld2"); - private final UUID uuid2 = MockUtils.getPlayer2UUID(); - private Plan plan; - private Database db; - private Database backup; - private int rows; - + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + private static SQLDB db; + private final UUID playerUUID = TestConstants.PLAYER_ONE_UUID; + private final UUID player2UUID = TestConstants.PLAYER_TWO_UUID; @Rule - public Timeout globalTimeout = Timeout.seconds(7); // 5 seconds max per method tested + public Timeout globalTimeout = Timeout.seconds(5); + @BeforeClass + public static void setUpClass() throws Exception { + System.out.println("--- Test Class Setup ---"); + db = new SQLiteDB(); + SystemMockUtil.setUp(temporaryFolder.getRoot()) + .enableConfigSystem() + .enableDatabaseSystem(db) + .enableServerInfoSystem(); + StaticHolder.saveInstance(SQLDB.class, Plan.class); + StaticHolder.saveInstance(SQLiteTest.class, Plan.class); - @Before - public void setUp() throws Exception { - TestInit t = TestInit.init(); - plan = t.getPlanMock(); + Log.setErrorManager(new TestErrorManager()); + Log.setDebugMode("console"); + Settings.DEV_MODE.setTemporaryValue(true); - db = new SQLiteDB("debug" + MiscUtils.getTime()); db.init(); - - when(plan.getDB()).thenReturn(db); - DataCache dataCache = new DataCache(plan) { - @Override - public void markFirstSession(UUID uuid) { - } - }; - when(plan.getDataCache()).thenReturn(dataCache); - - db.getServerTable().saveCurrentServerInfo(new ServerInfo(-1, TestInit.getServerUUID(), "ServerName", "", 20)); - - File f = new File(plan.getDataFolder(), "Errors.txt"); - rows = FileUtil.lines(f).size(); + System.out.println("--- Class Setup Complete ---\n"); } - @After - public void tearDown() throws IOException, SQLException { - db.close(); - if (backup != null) { - backup.close(); + @AfterClass + public static void tearDownClass() { + if (db != null) { + db.close(); } + Teardown.resetSettingsTempValues(); + } - File f = new File(plan.getDataFolder(), "Errors.txt"); - - List lines = FileUtil.lines(f); - int rowsAgain = lines.size(); - if (rowsAgain > 0) { - for (String line : lines) { - System.out.println(line); - } - } - - assertTrue("Errors were caught.", rows == rowsAgain); + @Before + public void setUp() throws DBException, SQLException { + assertEquals(db, Database.getActive()); + System.out.println("\n-- Clearing Test Database --"); + db.remove().everything(); + ServerTable serverTable = db.getServerTable(); + serverTable.saveCurrentServerInfo(new Server(-1, TestConstants.SERVER_UUID, "ServerName", "", 20)); + assertEquals(ServerInfo.getServerUUID(), TestConstants.SERVER_UUID); + System.out.println("-- Clear Complete --\n"); } @Test - public void testInit() throws DatabaseInitException { + public void testInit() throws DBInitException { db.init(); } @Test public void testNoExceptionWhenCommitEmpty() throws Exception { - db.init(); - - db.commit(((SQLDB) db).getConnection()); - db.commit(((SQLDB) db).getConnection()); - db.commit(((SQLDB) db).getConnection()); + db.commit(db.getConnection()); + db.commit(db.getConnection()); + db.commit(db.getConnection()); } @Test @@ -130,18 +119,8 @@ public class DatabaseTest { assertEquals("SQLite", db.getName()); } - @Test - public void testMySQLGetConfigName() { - assertEquals("mysql", new MySQLDB().getConfigName()); - } - - @Test - public void testMySQLGetName() { - assertEquals("MySQL", new MySQLDB().getName()); - } - @Test(timeout = 3000) - public void testSaveCommandUse() throws SQLException, DatabaseInitException { + public void testSaveCommandUse() throws SQLException, DBInitException { CommandUseTable commandUseTable = db.getCommandUseTable(); Map expected = new HashMap<>(); @@ -170,7 +149,7 @@ public class DatabaseTest { commitTest(); - Map commandUse = db.getCommandUse(); + Map commandUse = db.getCommandUseTable().getCommandUse(); assertEquals(expected, commandUse); for (int i = 0; i < 3; i++) { @@ -184,7 +163,7 @@ public class DatabaseTest { expected.put("test", 3); expected.put("tp", 6); - commandUse = db.getCommandUse(); + commandUse = db.getCommandUseTable().getCommandUse(); assertEquals(expected, commandUse); } @@ -245,16 +224,16 @@ public class DatabaseTest { saveUserOne(db); } - private void saveUserOne(Database database) throws SQLException { - database.getUsersTable().registerUser(uuid, 123456789L, "Test"); + private void saveUserOne(SQLDB database) throws SQLException { + database.getUsersTable().registerUser(playerUUID, 123456789L, "Test"); } private void saveUserTwo() throws SQLException { saveUserTwo(db); } - private void saveUserTwo(Database database) throws SQLException { - database.getUsersTable().registerUser(uuid2, 123456789L, "Test"); + private void saveUserTwo(SQLDB database) throws SQLException { + database.getUsersTable().registerUser(player2UUID, 123456789L, "Test"); } @Test @@ -265,58 +244,57 @@ public class DatabaseTest { Action save = new Action(234567890L, Actions.FIRST_SESSION, "Additional Info"); Action expected = new Action(234567890L, Actions.FIRST_SESSION, "Additional Info", 1); - actionsTable.insertAction(uuid, save); + actionsTable.insertAction(playerUUID, save); - List actions = actionsTable.getActions(uuid); + List actions = actionsTable.getActions(playerUUID); assertEquals(expected, actions.get(0)); } @Test - public void testIPTable() throws SQLException, DatabaseInitException { + public void testIPTable() throws SQLException, DBInitException { saveUserOne(); - IPsTable ipsTable = db.getIpsTable(); + GeoInfoTable geoInfoTable = db.getGeoInfoTable(); String expectedIP = "1.2.3.4"; String expectedGeoLoc = "TestLocation"; long time = MiscUtils.getTime(); GeoInfo expected = new GeoInfo(expectedIP, expectedGeoLoc, time); - ipsTable.saveGeoInfo(uuid, expected); - ipsTable.saveGeoInfo(uuid, expected); + geoInfoTable.saveGeoInfo(playerUUID, expected); + geoInfoTable.saveGeoInfo(playerUUID, expected); commitTest(); - List getInfo = ipsTable.getGeoInfo(uuid); + List getInfo = geoInfoTable.getGeoInfo(playerUUID); assertEquals(1, getInfo.size()); GeoInfo actual = getInfo.get(0); assertEquals(expected, actual); assertEquals(time, actual.getLastUsed()); - - Optional result = ipsTable.getGeolocation(expectedIP); + Optional result = geoInfoTable.getGeolocation(expectedIP); assertTrue(result.isPresent()); assertEquals(expectedGeoLoc, result.get()); } @Test - public void testNicknamesTable() throws SQLException, DatabaseInitException { + public void testNicknamesTable() throws SQLException, DBInitException { saveUserOne(); NicknamesTable nickTable = db.getNicknamesTable(); String expected = "TestNickname"; - nickTable.saveUserName(uuid, expected); - nickTable.saveUserName(uuid, expected); + nickTable.saveUserName(playerUUID, expected); + nickTable.saveUserName(playerUUID, expected); commitTest(); - List nicknames = nickTable.getNicknames(uuid); + List nicknames = nickTable.getNicknames(playerUUID); assertEquals(1, nicknames.size()); assertEquals(expected, nicknames.get(0)); - Map> allNicknames = nickTable.getAllNicknames(uuid); - assertEquals(nicknames, allNicknames.get(Plan.getServerUUID())); + Map> allNicknames = nickTable.getAllNicknames(playerUUID); + assertEquals(nicknames, allNicknames.get(ServerInfo.getServerUUID())); } @Test - public void testSecurityTable() throws SQLException, DatabaseInitException { + public void testSecurityTable() throws SQLException, DBInitException { SecurityTable securityTable = db.getSecurityTable(); WebUser expected = new WebUser("Test", "RandomGarbageBlah", 0); securityTable.addNewUser(expected); @@ -339,7 +317,7 @@ public class DatabaseTest { } @Test - public void testWorldTable() throws SQLException, DatabaseInitException { + public void testWorldTable() throws SQLException, DBInitException { WorldTable worldTable = db.getWorldTable(); List worlds = Arrays.asList("Test", "Test2", "Test3"); worldTable.saveWorlds(worlds); @@ -354,7 +332,7 @@ public class DatabaseTest { saveTwoWorlds(db); } - private void saveTwoWorlds(Database database) throws SQLException { + private void saveTwoWorlds(SQLDB database) throws SQLException { database.getWorldTable().saveWorlds(worlds); } @@ -373,13 +351,13 @@ public class DatabaseTest { private List createKills() { List kills = new ArrayList<>(); - kills.add(new PlayerKill(uuid2, "Iron Sword", 4321L)); - kills.add(new PlayerKill(uuid2, "Gold Sword", 5321L)); + kills.add(new PlayerKill(TestConstants.PLAYER_TWO_UUID, "Iron Sword", 4321L)); + kills.add(new PlayerKill(TestConstants.PLAYER_TWO_UUID, "Gold Sword", 5321L)); return kills; } @Test - public void testSessionPlaytimeSaving() throws SQLException, DatabaseInitException { + public void testSessionPlaytimeSaving() throws SQLException, DBInitException { saveTwoWorlds(); saveUserOne(); saveUserTwo(); @@ -393,23 +371,24 @@ public class DatabaseTest { assertEquals(expectedLength, session.getWorldTimes().getTotal()); SessionsTable sessionsTable = db.getSessionsTable(); - sessionsTable.saveSession(uuid, session); + sessionsTable.saveSession(playerUUID, session); commitTest(); - assertEquals(expectedLength, sessionsTable.getPlaytime(uuid)); - assertEquals(0L, sessionsTable.getPlaytime(uuid, 30000L)); + assertEquals(expectedLength, sessionsTable.getPlaytime(playerUUID)); + assertEquals(0L, sessionsTable.getPlaytime(playerUUID, 30000L)); - long playtimeOfServer = sessionsTable.getPlaytimeOfServer(TestInit.getServerUUID()); + UUID serverUUID = TestConstants.SERVER_UUID; + long playtimeOfServer = sessionsTable.getPlaytimeOfServer(serverUUID); assertEquals(expectedLength, playtimeOfServer); - assertEquals(0L, sessionsTable.getPlaytimeOfServer(TestInit.getServerUUID(), 30000L)); + assertEquals(0L, sessionsTable.getPlaytimeOfServer(serverUUID, 30000L)); - assertEquals(1, sessionsTable.getSessionCount(uuid)); - assertEquals(0, sessionsTable.getSessionCount(uuid, 30000L)); + assertEquals(1, sessionsTable.getSessionCount(playerUUID)); + assertEquals(0, sessionsTable.getSessionCount(playerUUID, 30000L)); } @Test - public void testSessionSaving() throws SQLException, DatabaseInitException { + public void testSessionSaving() throws SQLException, DBInitException { saveUserOne(); saveUserTwo(); @@ -419,11 +398,11 @@ public class DatabaseTest { session.setPlayerKills(createKills()); SessionsTable sessionsTable = db.getSessionsTable(); - sessionsTable.saveSession(uuid, session); + sessionsTable.saveSession(playerUUID, session); commitTest(); - Map> sessions = sessionsTable.getSessions(uuid); + Map> sessions = sessionsTable.getSessions(playerUUID); for (Map.Entry> entry : sessions.entrySet()) { UUID key = entry.getKey(); @@ -435,7 +414,7 @@ public class DatabaseTest { System.out.println(" " + entry.getValue()); } - List savedSessions = sessions.get(Plan.getServerUUID()); + List savedSessions = sessions.get(ServerInfo.getServerUUID()); assertNotNull(savedSessions); assertEquals(1, savedSessions.size()); @@ -444,52 +423,52 @@ public class DatabaseTest { assertEquals(session, savedSessions.get(0)); Map lastSeen = sessionsTable.getLastSeenForAllPlayers(); - assertTrue(lastSeen.containsKey(uuid)); - assertFalse(lastSeen.containsKey(uuid2)); - assertEquals(22345L, (long) lastSeen.get(uuid)); + assertTrue(lastSeen.containsKey(playerUUID)); + assertFalse(lastSeen.containsKey(TestConstants.PLAYER_TWO_UUID)); + assertEquals(22345L, (long) lastSeen.get(playerUUID)); } @Test - public void testUserInfoTableRegisterUnRegistered() throws SQLException, DatabaseInitException { + public void testUserInfoTableRegisterUnRegistered() throws SQLException, DBInitException { UserInfoTable userInfoTable = db.getUserInfoTable(); - assertFalse(userInfoTable.isRegistered(uuid)); + assertFalse(userInfoTable.isRegistered(playerUUID)); UsersTable usersTable = db.getUsersTable(); - assertFalse(usersTable.isRegistered(uuid)); + assertFalse(usersTable.isRegistered(playerUUID)); - userInfoTable.registerUserInfo(uuid, 123456789L); + userInfoTable.registerUserInfo(playerUUID, 123456789L); commitTest(); - assertTrue(usersTable.isRegistered(uuid)); - assertTrue(userInfoTable.isRegistered(uuid)); + assertTrue(usersTable.isRegistered(playerUUID)); + assertTrue(userInfoTable.isRegistered(playerUUID)); - UserInfo userInfo = userInfoTable.getUserInfo(uuid); - assertEquals(uuid, userInfo.getUuid()); + UserInfo userInfo = userInfoTable.getUserInfo(playerUUID); + assertEquals(playerUUID, userInfo.getUuid()); assertEquals(123456789L, (long) usersTable.getRegisterDates().get(0)); assertEquals(123456789L, userInfo.getRegistered()); - assertEquals(1, userInfoTable.getServerUserCount(Plan.getServerUUID())); + assertEquals(1, userInfoTable.getServerUserCount(ServerInfo.getServerUUID())); assertEquals("Waiting for Update..", userInfo.getName()); assertFalse(userInfo.isBanned()); assertFalse(userInfo.isOpped()); } @Test - public void testUserInfoTableRegisterRegistered() throws SQLException, DatabaseInitException { + public void testUserInfoTableRegisterRegistered() throws SQLException, DBInitException { saveUserOne(); UsersTable usersTable = db.getUsersTable(); - assertTrue(usersTable.isRegistered(uuid)); + assertTrue(usersTable.isRegistered(playerUUID)); UserInfoTable userInfoTable = db.getUserInfoTable(); - assertFalse(userInfoTable.isRegistered(uuid)); + assertFalse(userInfoTable.isRegistered(playerUUID)); - userInfoTable.registerUserInfo(uuid, 223456789L); + userInfoTable.registerUserInfo(playerUUID, 223456789L); commitTest(); - assertTrue(usersTable.isRegistered(uuid)); - assertTrue(userInfoTable.isRegistered(uuid)); + assertTrue(usersTable.isRegistered(playerUUID)); + assertTrue(userInfoTable.isRegistered(playerUUID)); - UserInfo userInfo = userInfoTable.getUserInfo(uuid); - assertEquals(uuid, userInfo.getUuid()); + UserInfo userInfo = userInfoTable.getUserInfo(playerUUID); + assertEquals(playerUUID, userInfo.getUuid()); assertEquals(123456789L, (long) usersTable.getRegisterDates().get(0)); assertEquals(223456789L, userInfo.getRegistered()); assertEquals("Test", userInfo.getName()); @@ -500,79 +479,82 @@ public class DatabaseTest { } @Test - public void testUserInfoTableUpdateBannedOpped() throws SQLException, DatabaseInitException { + public void testUserInfoTableUpdateBannedOpped() throws SQLException, DBInitException { UserInfoTable userInfoTable = db.getUserInfoTable(); - userInfoTable.registerUserInfo(uuid, 223456789L); - assertTrue(userInfoTable.isRegistered(uuid)); + userInfoTable.registerUserInfo(playerUUID, 223456789L); + assertTrue(userInfoTable.isRegistered(playerUUID)); - userInfoTable.updateOpAndBanStatus(uuid, true, true); + userInfoTable.updateOpStatus(playerUUID, true); + userInfoTable.updateBanStatus(playerUUID, true); commitTest(); - UserInfo userInfo = userInfoTable.getUserInfo(uuid); + UserInfo userInfo = userInfoTable.getUserInfo(playerUUID); assertTrue(userInfo.isBanned()); assertTrue(userInfo.isOpped()); - userInfoTable.updateOpAndBanStatus(uuid, false, true); + userInfoTable.updateOpStatus(playerUUID, false); + userInfoTable.updateBanStatus(playerUUID, true); commitTest(); - userInfo = userInfoTable.getUserInfo(uuid); + userInfo = userInfoTable.getUserInfo(playerUUID); assertTrue(userInfo.isBanned()); assertFalse(userInfo.isOpped()); - userInfoTable.updateOpAndBanStatus(uuid, false, false); + userInfoTable.updateOpStatus(playerUUID, true); + userInfoTable.updateBanStatus(playerUUID, false); commitTest(); - userInfo = userInfoTable.getUserInfo(uuid); + userInfo = userInfoTable.getUserInfo(playerUUID); assertFalse(userInfo.isBanned()); - assertFalse(userInfo.isOpped()); + assertTrue(userInfo.isOpped()); } @Test - public void testUsersTableUpdateName() throws SQLException, DatabaseInitException { + public void testUsersTableUpdateName() throws SQLException, DBInitException { saveUserOne(); UsersTable usersTable = db.getUsersTable(); - assertEquals(uuid, usersTable.getUuidOf("Test")); - usersTable.updateName(uuid, "NewName"); + assertEquals(playerUUID, usersTable.getUuidOf("Test")); + usersTable.updateName(playerUUID, "NewName"); commitTest(); assertNull(usersTable.getUuidOf("Test")); - assertEquals("NewName", usersTable.getPlayerName(uuid)); - assertEquals(uuid, usersTable.getUuidOf("NewName")); + assertEquals("NewName", usersTable.getPlayerName(playerUUID)); + assertEquals(playerUUID, usersTable.getUuidOf("NewName")); } @Test - public void testUsersTableKickSaving() throws SQLException, DatabaseInitException { + public void testUsersTableKickSaving() throws SQLException, DBInitException { saveUserOne(); UsersTable usersTable = db.getUsersTable(); - assertEquals(0, usersTable.getTimesKicked(uuid)); + assertEquals(0, usersTable.getTimesKicked(playerUUID)); int random = new Random().nextInt(20); for (int i = 0; i < random + 1; i++) { - usersTable.kicked(uuid); + usersTable.kicked(playerUUID); } commitTest(); - assertEquals(random + 1, usersTable.getTimesKicked(uuid)); + assertEquals(random + 1, usersTable.getTimesKicked(playerUUID)); } @Test - public void testRemovalSingleUser() throws SQLException { + public void testRemovalSingleUser() throws SQLException, DBException { saveUserTwo(); UserInfoTable userInfoTable = db.getUserInfoTable(); UsersTable usersTable = db.getUsersTable(); SessionsTable sessionsTable = db.getSessionsTable(); NicknamesTable nicknamesTable = db.getNicknamesTable(); - IPsTable ipsTable = db.getIpsTable(); + GeoInfoTable geoInfoTable = db.getGeoInfoTable(); ActionsTable actionsTable = db.getActionsTable(); - userInfoTable.registerUserInfo(uuid, 223456789L); + userInfoTable.registerUserInfo(playerUUID, 223456789L); saveTwoWorlds(); Session session = new Session(12345L, "", ""); @@ -580,60 +562,60 @@ public class DatabaseTest { session.setWorldTimes(createWorldTimes()); session.setPlayerKills(createKills()); - sessionsTable.saveSession(uuid, session); - nicknamesTable.saveUserName(uuid, "TestNick"); - ipsTable.saveGeoInfo(uuid, new GeoInfo("1.2.3.4", "TestLoc", 223456789L)); - actionsTable.insertAction(uuid, new Action(1324L, Actions.FIRST_SESSION, "Add")); + sessionsTable.saveSession(playerUUID, session); + nicknamesTable.saveUserName(playerUUID, "TestNick"); + geoInfoTable.saveGeoInfo(playerUUID, new GeoInfo("1.2.3.4", "TestLoc", 223456789L)); + actionsTable.insertAction(playerUUID, new Action(1324L, Actions.FIRST_SESSION, "Add")); - assertTrue(usersTable.isRegistered(uuid)); + assertTrue(usersTable.isRegistered(playerUUID)); - db.removeAccount(uuid); + db.remove().player(playerUUID); - assertFalse(usersTable.isRegistered(uuid)); - assertFalse(userInfoTable.isRegistered(uuid)); - assertTrue(nicknamesTable.getNicknames(uuid).isEmpty()); - assertTrue(ipsTable.getGeoInfo(uuid).isEmpty()); - assertTrue(sessionsTable.getSessions(uuid).isEmpty()); - assertTrue(actionsTable.getActions(uuid).isEmpty()); + assertFalse(usersTable.isRegistered(playerUUID)); + assertFalse(userInfoTable.isRegistered(playerUUID)); + assertTrue(nicknamesTable.getNicknames(playerUUID).isEmpty()); + assertTrue(geoInfoTable.getGeoInfo(playerUUID).isEmpty()); + assertTrue(sessionsTable.getSessions(playerUUID).isEmpty()); + assertTrue(actionsTable.getActions(playerUUID).isEmpty()); } @Test - public void testRemovalEverything() throws SQLException { + public void testRemovalEverything() throws SQLException, DBException { UserInfoTable userInfoTable = db.getUserInfoTable(); UsersTable usersTable = db.getUsersTable(); SessionsTable sessionsTable = db.getSessionsTable(); NicknamesTable nicknamesTable = db.getNicknamesTable(); - IPsTable ipsTable = db.getIpsTable(); + GeoInfoTable geoInfoTable = db.getGeoInfoTable(); ActionsTable actionsTable = db.getActionsTable(); TPSTable tpsTable = db.getTpsTable(); SecurityTable securityTable = db.getSecurityTable(); saveAllData(db); - db.removeAllData(); + db.remove().everything(); - assertFalse(usersTable.isRegistered(uuid)); - assertFalse(usersTable.isRegistered(uuid2)); - assertFalse(userInfoTable.isRegistered(uuid)); + assertFalse(usersTable.isRegistered(playerUUID)); + assertFalse(usersTable.isRegistered(TestConstants.PLAYER_TWO_UUID)); + assertFalse(userInfoTable.isRegistered(playerUUID)); - assertTrue(nicknamesTable.getNicknames(uuid).isEmpty()); - assertTrue(ipsTable.getGeoInfo(uuid).isEmpty()); - assertTrue(sessionsTable.getSessions(uuid).isEmpty()); - assertTrue(actionsTable.getActions(uuid).isEmpty()); - assertTrue(db.getCommandUse().isEmpty()); + assertTrue(nicknamesTable.getNicknames(playerUUID).isEmpty()); + assertTrue(geoInfoTable.getGeoInfo(playerUUID).isEmpty()); + assertTrue(sessionsTable.getSessions(playerUUID).isEmpty()); + assertTrue(actionsTable.getActions(playerUUID).isEmpty()); + assertTrue(db.getCommandUseTable().getCommandUse().isEmpty()); assertTrue(db.getWorldTable().getWorlds().isEmpty()); assertTrue(tpsTable.getTPSData().isEmpty()); assertTrue(db.getServerTable().getBukkitServers().isEmpty()); assertTrue(securityTable.getUsers().isEmpty()); } - private void saveAllData(Database database) throws SQLException { + private void saveAllData(SQLDB database) throws SQLException { System.out.println("Saving all possible data to the Database.."); UserInfoTable userInfoTable = database.getUserInfoTable(); UsersTable usersTable = database.getUsersTable(); SessionsTable sessionsTable = database.getSessionsTable(); NicknamesTable nicknamesTable = database.getNicknamesTable(); - IPsTable ipsTable = database.getIpsTable(); + GeoInfoTable geoInfoTable = database.getGeoInfoTable(); ActionsTable actionsTable = database.getActionsTable(); TPSTable tpsTable = database.getTpsTable(); SecurityTable securityTable = database.getSecurityTable(); @@ -641,7 +623,7 @@ public class DatabaseTest { saveUserOne(database); saveUserTwo(database); - userInfoTable.registerUserInfo(uuid, 223456789L); + userInfoTable.registerUserInfo(playerUUID, 223456789L); saveTwoWorlds(database); Session session = new Session(12345L, "", ""); @@ -649,12 +631,12 @@ public class DatabaseTest { session.setWorldTimes(createWorldTimes()); session.setPlayerKills(createKills()); - sessionsTable.saveSession(uuid, session); - nicknamesTable.saveUserName(uuid, "TestNick"); - ipsTable.saveGeoInfo(uuid, new GeoInfo("1.2.3.4", "TestLoc", 223456789L)); - actionsTable.insertAction(uuid, new Action(1324L, Actions.FIRST_SESSION, "Add")); + sessionsTable.saveSession(playerUUID, session); + nicknamesTable.saveUserName(playerUUID, "TestNick"); + geoInfoTable.saveGeoInfo(playerUUID, new GeoInfo("1.2.3.4", "TestLoc", 223456789L)); + actionsTable.insertAction(playerUUID, new Action(1324L, Actions.FIRST_SESSION, "Add")); - assertTrue(usersTable.isRegistered(uuid)); + assertTrue(usersTable.isRegistered(playerUUID)); CommandUseTable commandUseTable = database.getCommandUseTable(); commandUseTable.commandUsed("plan"); @@ -685,14 +667,14 @@ public class DatabaseTest { } @Test - public void testServerTableBungeeSave() throws SQLException, DatabaseInitException { + public void testServerTableBungeeSave() throws SQLException, DBInitException { ServerTable serverTable = db.getServerTable(); - Optional bungeeInfo = serverTable.getBungeeInfo(); + Optional bungeeInfo = serverTable.getBungeeInfo(); assertFalse(bungeeInfo.isPresent()); UUID bungeeUUID = UUID.randomUUID(); - ServerInfo bungeeCord = new ServerInfo(-1, bungeeUUID, "BungeeCord", "Random:1234", 20); + Server bungeeCord = new Server(-1, bungeeUUID, "BungeeCord", "Random:1234", 20); serverTable.saveCurrentServerInfo(bungeeCord); commitTest(); @@ -709,11 +691,11 @@ public class DatabaseTest { } @Test - public void testServerTableBungee() throws SQLException, DatabaseInitException { + public void testServerTableBungee() throws SQLException, DBInitException { testServerTableBungeeSave(); ServerTable serverTable = db.getServerTable(); - List bukkitServers = serverTable.getBukkitServers(); + Map bukkitServers = serverTable.getBukkitServers(); assertEquals(1, bukkitServers.size()); } @@ -723,13 +705,13 @@ public class DatabaseTest { assertTrue(lastSeen.isEmpty()); } - private void commitTest() throws DatabaseInitException, SQLException { + private void commitTest() throws DBInitException { db.close(); db.init(); } @Test - public void testSessionTableGetInfoOfServer() throws SQLException, DatabaseInitException { + public void testSessionTableGetInfoOfServer() throws SQLException, DBInitException { saveUserOne(); saveUserTwo(); @@ -739,7 +721,7 @@ public class DatabaseTest { session.setPlayerKills(createKills()); SessionsTable sessionsTable = db.getSessionsTable(); - sessionsTable.saveSession(uuid, session); + sessionsTable.saveSession(playerUUID, session); commitTest(); @@ -748,7 +730,7 @@ public class DatabaseTest { session.setPlayerKills(new ArrayList<>()); session.setWorldTimes(new WorldTimes(new HashMap<>())); - List sSessions = sessions.get(uuid); + List sSessions = sessions.get(playerUUID); assertFalse(sessions.isEmpty()); assertNotNull(sSessions); assertFalse(sSessions.isEmpty()); @@ -756,18 +738,18 @@ public class DatabaseTest { } @Test - public void testKillTableGetKillsOfServer() throws SQLException, DatabaseInitException { + public void testKillTableGetKillsOfServer() throws SQLException, DBInitException { saveUserOne(); saveUserTwo(); KillsTable killsTable = db.getKillsTable(); List expected = createKills(); - killsTable.savePlayerKills(uuid, 1, expected); + killsTable.savePlayerKills(playerUUID, 1, expected); commitTest(); Map> playerKills = killsTable.getPlayerKills(); - List kills = playerKills.get(uuid); + List kills = playerKills.get(playerUUID); assertFalse(playerKills.isEmpty()); assertNotNull(kills); assertFalse(kills.isEmpty()); @@ -775,9 +757,11 @@ public class DatabaseTest { } @Test - public void testBackupAndRestore() throws SQLException, DatabaseInitException { + public void testBackupAndRestore() throws SQLException, DBInitException { + System.out.println("- Creating Backup Database -"); SQLiteDB backup = new SQLiteDB("debug-backup" + MiscUtils.getTime()); backup.init(); + System.out.println("- Backup Database Created -"); saveAllData(db); @@ -787,20 +771,20 @@ public class DatabaseTest { UsersTable usersTable = backup.getUsersTable(); SessionsTable sessionsTable = backup.getSessionsTable(); NicknamesTable nicknamesTable = backup.getNicknamesTable(); - IPsTable ipsTable = backup.getIpsTable(); + GeoInfoTable ipsTable = backup.getGeoInfoTable(); ActionsTable actionsTable = backup.getActionsTable(); TPSTable tpsTable = backup.getTpsTable(); SecurityTable securityTable = backup.getSecurityTable(); - assertTrue(usersTable.isRegistered(uuid)); - assertTrue(usersTable.isRegistered(uuid2)); - assertTrue(userInfoTable.isRegistered(uuid)); + assertTrue(usersTable.isRegistered(playerUUID)); + assertTrue(usersTable.isRegistered(TestConstants.PLAYER_TWO_UUID)); + assertTrue(userInfoTable.isRegistered(playerUUID)); - assertFalse(nicknamesTable.getNicknames(uuid).isEmpty()); - assertFalse(ipsTable.getGeoInfo(uuid).isEmpty()); - assertFalse(sessionsTable.getSessions(uuid).isEmpty()); - assertFalse(actionsTable.getActions(uuid).isEmpty()); - assertFalse(backup.getCommandUse().isEmpty()); + assertFalse(nicknamesTable.getNicknames(playerUUID).isEmpty()); + assertFalse(ipsTable.getGeoInfo(playerUUID).isEmpty()); + assertFalse(sessionsTable.getSessions(playerUUID).isEmpty()); + assertFalse(actionsTable.getActions(playerUUID).isEmpty()); + assertFalse(backup.getCommandUseTable().getCommandUse().isEmpty()); assertFalse(backup.getWorldTable().getWorlds().isEmpty()); assertFalse(tpsTable.getTPSData().isEmpty()); assertFalse(backup.getServerTable().getBukkitServers().isEmpty()); @@ -812,12 +796,12 @@ public class DatabaseTest { saveUserOne(); WorldTimes worldTimes = createWorldTimes(); WorldTimesTable worldTimesTable = db.getWorldTimesTable(); - worldTimesTable.saveWorldTimes(uuid, 1, worldTimes); + worldTimesTable.saveWorldTimes(playerUUID, 1, worldTimes); Session session = new Session(1, 12345L, 23456L, 0, 0); Map sessions = new HashMap<>(); sessions.put(1, session); - worldTimesTable.addWorldTimesToSessions(uuid, sessions); + worldTimesTable.addWorldTimesToSessions(playerUUID, sessions); assertEquals(worldTimes, session.getWorldTimes()); } @@ -835,8 +819,8 @@ public class DatabaseTest { Map> sessionMap = new HashMap<>(); List sessions = new ArrayList<>(); sessions.add(session); - sessionMap.put(uuid, sessions); - map.put(Plan.getServerUUID(), sessionMap); + sessionMap.put(playerUUID, sessions); + map.put(ServerInfo.getServerUUID(), sessionMap); worldTimesTable.saveWorldTimes(map); @@ -858,30 +842,58 @@ public class DatabaseTest { Map> sessionMap = new HashMap<>(); List sessions = new ArrayList<>(); sessions.add(session); - sessionMap.put(uuid, sessions); - UUID serverUUID = Plan.getServerUUID(); + sessionMap.put(playerUUID, sessions); + UUID serverUUID = ServerInfo.getServerUUID(); map.put(serverUUID, sessionMap); sessionsTable.insertSessions(map, true); Map>> allSessions = sessionsTable.getAllSessions(true); - assertEquals(worldTimes, allSessions.get(serverUUID).get(uuid).get(0).getWorldTimes()); + assertEquals(worldTimes, allSessions.get(serverUUID).get(playerUUID).get(0).getWorldTimes()); } @Test public void testRegisterProcessorRegisterException() throws SQLException { - assertFalse(db.getUsersTable().isRegistered(uuid)); - assertFalse(db.getUserInfoTable().isRegistered(uuid)); + assertFalse(db.getUsersTable().isRegistered(playerUUID)); + assertFalse(db.getUserInfoTable().isRegistered(playerUUID)); + System.out.println("\n- Running RegisterProcessors -"); + List processors = new ArrayList<>(); for (int i = 0; i < 200; i++) { - new RegisterProcessor(uuid, 500L, 1000L, "name", 4).process(); + processors.add(new RegisterProcessor(playerUUID, 500L, 1000L, "name", 4)); } - assertTrue(db.getUsersTable().isRegistered(uuid)); - assertTrue(db.getUserInfoTable().isRegistered(uuid)); + for (RegisterProcessor processor : processors) { + processor.process(); + } + System.out.println("- RegisterProcessors Run -\n"); + assertTrue(db.getUsersTable().isRegistered(playerUUID)); + assertTrue(db.getUserInfoTable().isRegistered(playerUUID)); + } + + @Test + public void testRegister() throws DBException { + assertFalse(db.check().isPlayerRegistered(playerUUID)); + assertFalse(db.check().isPlayerRegisteredOnThisServer(playerUUID)); + db.save().registerNewUser(playerUUID, 1000L, "name"); + db.save().registerNewUserOnThisServer(playerUUID, 500L); + assertTrue(db.check().isPlayerRegistered(playerUUID)); + assertTrue(db.check().isPlayerRegisteredOnThisServer(playerUUID)); } @Test public void testWorldTableGetWorldNamesNoException() throws SQLException { Set worldNames = db.getWorldTable().getWorldNames(); } + + @Test + public void testSettingTransfer() throws SQLException { + String testString = RandomData.randomString(100); + + TransferTable transferTable = db.getTransferTable(); + transferTable.storeConfigSettings(Base64Util.encode(testString)); + Optional configSettings = transferTable.getConfigSettings(); + + assertTrue(configSettings.isPresent()); + assertEquals(testString, Base64Util.decode(configSettings.get())); + } } diff --git a/Plan/test/main/java/com/djrapitops/plan/database/tables/ActionsTest.java b/Plan/src/test/java/com/djrapitops/plan/system/database/databases/sql/tables/ActionsTest.java similarity index 71% rename from Plan/test/main/java/com/djrapitops/plan/database/tables/ActionsTest.java rename to Plan/src/test/java/com/djrapitops/plan/system/database/databases/sql/tables/ActionsTest.java index 27e28d8e6..52596db01 100644 --- a/Plan/test/main/java/com/djrapitops/plan/database/tables/ActionsTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/system/database/databases/sql/tables/ActionsTest.java @@ -1,5 +1,6 @@ -package com.djrapitops.plan.database.tables; +package com.djrapitops.plan.system.database.databases.sql.tables; +import com.djrapitops.plan.data.Actions; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/Plan/src/test/java/com/djrapitops/plan/system/settings/network/NetworkSettingsTest.java b/Plan/src/test/java/com/djrapitops/plan/system/settings/network/NetworkSettingsTest.java new file mode 100644 index 000000000..9b0973bb5 --- /dev/null +++ b/Plan/src/test/java/com/djrapitops/plan/system/settings/network/NetworkSettingsTest.java @@ -0,0 +1,70 @@ +package com.djrapitops.plan.system.settings.network; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.connection.UnsupportedTransferDatabaseException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.SQLiteDB; +import com.djrapitops.plan.system.database.databases.sql.tables.ServerTable; +import com.djrapitops.plan.system.info.server.Server; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plugin.StaticHolder; +import com.djrapitops.plugin.api.utility.log.Log; +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import utilities.Teardown; +import utilities.TestConstants; +import utilities.TestErrorManager; +import utilities.mocks.SystemMockUtil; + +import java.sql.SQLException; + +import static org.junit.Assert.assertEquals; + +public class NetworkSettingsTest { + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + private static SQLDB db; + + @BeforeClass + public static void setUpClass() throws Exception { + Teardown.resetSettingsTempValues(); + StaticHolder.saveInstance(NetworkSettingsTest.class, Plan.class); + + db = new SQLiteDB(); + SystemMockUtil.setUp(temporaryFolder.getRoot()) + .enableConfigSystem() + .enableDatabaseSystem(db) + .enableServerInfoSystem(); + + Log.setErrorManager(new TestErrorManager()); + Log.setDebugMode("console"); + Settings.DEV_MODE.setTemporaryValue(true); + } + + @AfterClass + public static void tearDownClass() { + if (db != null) { + db.close(); + } + Teardown.resetSettingsTempValues(); + } + + @Before + public void setUp() throws DBException, SQLException { + db.remove().everything(); + ServerTable serverTable = db.getServerTable(); + serverTable.saveCurrentServerInfo(new Server(-1, TestConstants.SERVER_UUID, "ServerName", "", 20)); + assertEquals(ServerInfo.getServerUUID(), TestConstants.SERVER_UUID); + } + + @Test + public void testTransfer() throws DBException, UnsupportedTransferDatabaseException { + NetworkSettings networkSettings = new NetworkSettings(); + networkSettings.placeToDatabase(); + networkSettings.loadFromDatabase(); + } + +} \ No newline at end of file diff --git a/Plan/src/test/java/com/djrapitops/plan/system/webserver/HTTPSWebServerAuthTest.java b/Plan/src/test/java/com/djrapitops/plan/system/webserver/HTTPSWebServerAuthTest.java new file mode 100644 index 000000000..43ea62a77 --- /dev/null +++ b/Plan/src/test/java/com/djrapitops/plan/system/webserver/HTTPSWebServerAuthTest.java @@ -0,0 +1,138 @@ +package com.djrapitops.plan.system.webserver; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.connection.*; +import com.djrapitops.plan.data.WebUser; +import com.djrapitops.plan.system.BukkitSystem; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.utilities.Base64Util; +import com.djrapitops.plan.utilities.PassEncryptUtil; +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.Teardown; +import utilities.mocks.BukkitMockUtil; + +import javax.net.ssl.*; +import java.io.File; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; + +@RunWith(MockitoJUnitRunner.Silent.class) +public class HTTPSWebServerAuthTest { + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + private static BukkitSystem bukkitSystem; + + @BeforeClass + public static void setUpClass() throws Exception { + BukkitMockUtil mockUtil = BukkitMockUtil.setUp() + .withDataFolder(temporaryFolder.getRoot()) + .withLogging() + .withPluginDescription() + .withResourceFetchingFromJar() + .withServer(); + Plan planMock = mockUtil.getPlanMock(); + + URL resource = HTTPSWebServerAuthTest.class.getResource("/Cert.keystore"); + String keyStore = resource.getPath(); + String absolutePath = new File(keyStore).getAbsolutePath(); + + Settings.WEBSERVER_CERTIFICATE_PATH.setTemporaryValue(absolutePath); + Settings.WEBSERVER_CERTIFICATE_KEYPASS.setTemporaryValue("MnD3bU5HpmPXag0e"); + Settings.WEBSERVER_CERTIFICATE_STOREPASS.setTemporaryValue("wDwwf663NLTm73gL"); + Settings.WEBSERVER_CERTIFICATE_ALIAS.setTemporaryValue("DefaultPlanCert"); + + Settings.WEBSERVER_PORT.setTemporaryValue(9000); + + bukkitSystem = new BukkitSystem(planMock); + bukkitSystem.enable(); + + bukkitSystem.getDatabaseSystem().getActiveDatabase().save() + .webUser(new WebUser("test", PassEncryptUtil.createHash("testPass"), 0)); + } + + @Before + public void setUp() { + Teardown.resetSettingsTempValues(); + } + + @After + public void tearDown() { + if (bukkitSystem != null) { + bukkitSystem.disable(); + } + Teardown.resetSettingsTempValues(); + } + + private static final TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { + //No need to implement. + } + + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { + //No need to implement. + } + } + }; + + private SSLSocketFactory getRelaxedSocketFactory() throws NoSuchAlgorithmException, KeyManagementException { + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + return sc.getSocketFactory(); + } + + /** + * Test case against "Perm level 0 required, got 0". + */ + @Test + public void testHTTPSAuthForPages() throws IOException, WebException, KeyManagementException, NoSuchAlgorithmException { + String address = "https://localhost:9000"; + URL url = new URL(address); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + if (address.startsWith("https")) { + HttpsURLConnection httpsConn = (HttpsURLConnection) connection; + + // Disables unsigned certificate & hostname check, because we're trusting the user given certificate. + // This allows https connections internally to local ports. + httpsConn.setHostnameVerifier((hostname, session) -> true); + httpsConn.setSSLSocketFactory(getRelaxedSocketFactory()); + } + connection.setConnectTimeout(10000); + connection.setInstanceFollowRedirects(false); + connection.setRequestMethod("GET"); + connection.setUseCaches(false); + + String user = Base64Util.encode("test:testPass"); + connection.setRequestProperty("Authorization", "Basic " + user); + + int responseCode = connection.getResponseCode(); + + switch (responseCode) { + case 200: + return; + case 400: + throw new BadRequestException("Bad Request: " + url.toString()); + case 403: + throw new ForbiddenException(url.toString() + " returned 403"); + case 404: + throw new NotFoundException(url.toString() + " returned a 404, ensure that your server is connected to an up to date Plan server."); + case 412: + throw new UnauthorizedServerException(url.toString() + " reported that it does not recognize this server. Make sure '/plan m setup' was successful."); + case 500: + throw new InternalErrorException(); + default: + throw new WebException(url.toString() + "| Wrong response code " + responseCode); + } + } +} \ No newline at end of file diff --git a/Plan/test/main/java/com/djrapitops/plan/utilities/FormatUtilsTest.java b/Plan/src/test/java/com/djrapitops/plan/utilities/FormatUtilsTest.java similarity index 70% rename from Plan/test/main/java/com/djrapitops/plan/utilities/FormatUtilsTest.java rename to Plan/src/test/java/com/djrapitops/plan/utilities/FormatUtilsTest.java index 41f89486b..e2066fc4a 100644 --- a/Plan/test/main/java/com/djrapitops/plan/utilities/FormatUtilsTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/utilities/FormatUtilsTest.java @@ -3,32 +3,35 @@ package com.djrapitops.plan.utilities; import com.djrapitops.plugin.api.TimeAmount; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.MockUtils; -import test.utilities.RandomData; -import test.utilities.TestInit; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.RandomData; +import utilities.Teardown; +import utilities.mocks.SystemMockUtil; +import utilities.mocks.objects.MockUtils; -import java.text.SimpleDateFormat; import java.util.Date; -import java.util.Locale; import static org.junit.Assert.*; /** * @author Rsl1122 */ -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) +@RunWith(MockitoJUnitRunner.Silent.class) public class FormatUtilsTest { - @Before - public void setUp() throws Exception { - TestInit.init(); + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @BeforeClass + public static void setUpClass() throws Exception { + SystemMockUtil.setUp(temporaryFolder.getRoot()) + .enableConfigSystem(); + Teardown.resetSettingsTempValues(); } @Test @@ -51,52 +54,7 @@ public class FormatUtilsTest { } @Test - public void testFormatTimeStamp() { - SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd, HH:mm", Locale.ENGLISH); - - Date date = new Date(); - date.setTime(0); - - String expResult = dateFormat.format(date); - - long epochZero = 0L; - String result = FormatUtils.formatTimeStamp(epochZero); - - assertEquals(expResult, result); - } - - @Test - public void testFormatTimeStampYear() { - SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd YYYY, HH:mm", Locale.ENGLISH); - - Date date = new Date(); - date.setTime(0); - - String expResult = dateFormat.format(date); - - long epochZero = 0L; - String result = FormatUtils.formatTimeStampYear(epochZero); - - assertEquals(expResult, result); - } - - @Test - public void testFormatTimeStampSecond() { - SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd, HH:mm:ss", Locale.ENGLISH); - - Date date = new Date(); - date.setTime(0); - - String expResult = dateFormat.format(date); - - long epochZero = 0L; - String result = FormatUtils.formatTimeStampSecond(epochZero); - - assertEquals(expResult, result); - } - - @Test - public void testFormatTimeStampMonths() { + public void testFormatTimeAmountMonths() { long time = TimeAmount.DAY.ms() * 40L; assertEquals("1 month, 10d ", FormatUtils.formatTimeAmount(time)); } diff --git a/Plan/test/main/java/com/djrapitops/plan/utilities/MiscUtilsTest.java b/Plan/src/test/java/com/djrapitops/plan/utilities/MiscUtilsTest.java similarity index 74% rename from Plan/test/main/java/com/djrapitops/plan/utilities/MiscUtilsTest.java rename to Plan/src/test/java/com/djrapitops/plan/utilities/MiscUtilsTest.java index 391520aa5..a1a44985d 100644 --- a/Plan/test/main/java/com/djrapitops/plan/utilities/MiscUtilsTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/utilities/MiscUtilsTest.java @@ -6,43 +6,56 @@ package com.djrapitops.plan.utilities; import com.djrapitops.plan.Plan; -import com.djrapitops.plan.database.databases.SQLDB; -import com.djrapitops.plan.database.databases.SQLiteDB; -import com.djrapitops.plan.database.tables.UsersTable; -import com.djrapitops.plan.systems.info.server.ServerInfo; +import com.djrapitops.plan.system.database.databases.Database; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.tables.UsersTable; +import com.djrapitops.plan.system.info.server.Server; import com.djrapitops.plugin.StaticHolder; import com.djrapitops.plugin.command.ISender; import com.djrapitops.plugin.command.bukkit.BukkitCMDSender; -import org.bukkit.Bukkit; -import org.bukkit.plugin.java.JavaPlugin; import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.MockUtils; -import test.utilities.RandomData; -import test.utilities.TestInit; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.RandomData; +import utilities.TestConstants; +import utilities.mocks.SystemMockUtil; +import utilities.mocks.objects.MockUtils; import java.util.List; import java.util.UUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.powermock.api.mockito.PowerMockito.when; /** * @author Rsl1122 */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({JavaPlugin.class, Bukkit.class}) +@RunWith(MockitoJUnitRunner.Silent.class) public class MiscUtilsTest { private SQLDB db; + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @BeforeClass + public static void setUpClass() throws Exception { + StaticHolder.saveInstance(MiscUtils.class, Plan.class); + SystemMockUtil.setUp(temporaryFolder.getRoot()) + .enableConfigSystem() + .enableDatabaseSystem() + .enableServerInfoSystem(); + + Database.getActive().save().serverInfoForThisServer(new Server(-1, TestConstants.SERVER_UUID, "ServerName", "", 20)); + } + @Before public void setUp() { - StaticHolder.saveInstance(MiscUtils.class, Plan.class); + db = (SQLDB) Database.getActive(); } @Test @@ -57,9 +70,7 @@ public class MiscUtilsTest { } @Test - public void testGetPlayerDisplayNameArgsNoPerm() throws Exception { - TestInit.init(); - + public void testGetPlayerDisplayNameArgsNoPerm() { String[] args = new String[]{"Rsl1122", "Test"}; ISender sender = new BukkitCMDSender(MockUtils.mockPlayer2()); @@ -115,8 +126,6 @@ public class MiscUtilsTest { @Test public void testGetMatchingNames() throws Exception { - setupDatabase(); - String exp1 = "TestName"; String exp2 = "TestName2"; @@ -137,16 +146,14 @@ public class MiscUtilsTest { @Test public void testGetMatchingNickNames() throws Exception { - setupDatabase(); - UUID uuid = UUID.randomUUID(); String userName = RandomData.randomString(10); db.getUsersTable().registerUser(uuid, 0L, userName); - db.getUsersTable().registerUser(MockUtils.getPlayerUUID(), 1L, "Not random"); + db.getUsersTable().registerUser(TestConstants.PLAYER_ONE_UUID, 1L, "Not random"); String nickname = "2" + RandomData.randomString(10); db.getNicknamesTable().saveUserName(uuid, nickname); - db.getNicknamesTable().saveUserName(MockUtils.getPlayerUUID(), "No nick"); + db.getNicknamesTable().saveUserName(TestConstants.PLAYER_ONE_UUID, "No nick"); String search = "2"; @@ -156,18 +163,4 @@ public class MiscUtilsTest { assertEquals(1, result.size()); assertEquals(userName, result.get(0)); } - - private void setupDatabase() throws Exception { - TestInit.init(); - - TestInit t = TestInit.init(); - Plan plan = t.getPlanMock(); - - db = new SQLiteDB("debug" + MiscUtils.getTime()); - db.init(); - - db.getServerTable().saveCurrentServerInfo(new ServerInfo(-1, TestInit.getServerUUID(), "ServerName", "", 20)); - - when(plan.getDB()).thenReturn(db); - } } diff --git a/Plan/test/main/java/com/djrapitops/plan/utilities/PassEncryptTest.java b/Plan/src/test/java/com/djrapitops/plan/utilities/PassEncryptTest.java similarity index 96% rename from Plan/test/main/java/com/djrapitops/plan/utilities/PassEncryptTest.java rename to Plan/src/test/java/com/djrapitops/plan/utilities/PassEncryptTest.java index 8c50ae4e6..1bdc75290 100644 --- a/Plan/test/main/java/com/djrapitops/plan/utilities/PassEncryptTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/utilities/PassEncryptTest.java @@ -2,7 +2,7 @@ package com.djrapitops.plan.utilities; import org.junit.Before; import org.junit.Test; -import test.utilities.RandomData; +import utilities.RandomData; import java.util.HashMap; import java.util.Map; diff --git a/Plan/test/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtilsTest.java b/Plan/src/test/java/com/djrapitops/plan/utilities/analysis/AnalysisUtilsTest.java similarity index 70% rename from Plan/test/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtilsTest.java rename to Plan/src/test/java/com/djrapitops/plan/utilities/analysis/AnalysisUtilsTest.java index e5eee8d5c..e4e020542 100644 --- a/Plan/test/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtilsTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/utilities/analysis/AnalysisUtilsTest.java @@ -5,13 +5,7 @@ */ package com.djrapitops.plan.utilities.analysis; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.TestInit; import java.util.Arrays; import java.util.Collections; @@ -22,15 +16,8 @@ import static org.junit.Assert.assertEquals; /** * @author Rsl1122 */ -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) public class AnalysisUtilsTest { - @Before - public void setUp() throws Exception { - TestInit.init(); - } - @Test public void testGetNewPlayers() { List registered = Arrays.asList(5L, 1L); diff --git a/Plan/test/main/java/com/djrapitops/plan/utilities/analysis/MathUtilsTest.java b/Plan/src/test/java/com/djrapitops/plan/utilities/analysis/MathUtilsTest.java similarity index 99% rename from Plan/test/main/java/com/djrapitops/plan/utilities/analysis/MathUtilsTest.java rename to Plan/src/test/java/com/djrapitops/plan/utilities/analysis/MathUtilsTest.java index 90bccbf6b..0039baf53 100644 --- a/Plan/test/main/java/com/djrapitops/plan/utilities/analysis/MathUtilsTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/utilities/analysis/MathUtilsTest.java @@ -6,7 +6,7 @@ package com.djrapitops.plan.utilities.analysis; import org.junit.Test; -import test.utilities.RandomData; +import utilities.RandomData; import java.io.Serializable; import java.util.ArrayList; diff --git a/Plan/test/main/java/com/djrapitops/plan/utilities/comparators/ComparatorTest.java b/Plan/src/test/java/com/djrapitops/plan/utilities/comparators/ComparatorTest.java similarity index 86% rename from Plan/test/main/java/com/djrapitops/plan/utilities/comparators/ComparatorTest.java rename to Plan/src/test/java/com/djrapitops/plan/utilities/comparators/ComparatorTest.java index 3808ab93a..a48715fe4 100644 --- a/Plan/test/main/java/com/djrapitops/plan/utilities/comparators/ComparatorTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/utilities/comparators/ComparatorTest.java @@ -4,13 +4,13 @@ import com.djrapitops.plan.data.WebUser; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.container.TPS; import com.djrapitops.plan.data.container.UserInfo; -import com.djrapitops.plan.settings.locale.Message; -import com.djrapitops.plan.settings.locale.Msg; +import com.djrapitops.plan.system.settings.locale.Message; +import com.djrapitops.plan.system.settings.locale.Msg; import com.djrapitops.plan.utilities.PassEncryptUtil; -import com.djrapitops.plan.utilities.analysis.Point; +import com.djrapitops.plan.utilities.html.graphs.line.Point; import com.google.common.collect.Ordering; import org.junit.Test; -import test.utilities.RandomData; +import utilities.RandomData; import java.util.*; import java.util.stream.Collectors; @@ -23,8 +23,8 @@ public class ComparatorTest { public void testPointComparator() { List points = RandomData.randomPoints(); - List longValues = points.stream().map(Point::getX).map(i -> (long) (double) i).collect(Collectors.toList()); - longValues.sort(Long::compare); + List longValues = points.stream().map(Point::getX).map(i -> (long) (double) i) + .sorted(Long::compare).collect(Collectors.toList()); points.sort(new PointComparator()); @@ -36,8 +36,8 @@ public class ComparatorTest { public void testSessionDataComparator() { List sessions = RandomData.randomSessions(); - List longValues = sessions.stream().map(Session::getSessionStart).collect(Collectors.toList()); - longValues.sort(Long::compare); + List longValues = sessions.stream().map(Session::getSessionStart) + .sorted(Long::compare).collect(Collectors.toList()); Collections.reverse(longValues); sessions.sort(new SessionStartComparator()); @@ -50,8 +50,8 @@ public class ComparatorTest { public void testTPSComparator() { List tpsList = RandomData.randomTPS(); - List longValues = tpsList.stream().map(TPS::getDate).collect(Collectors.toList()); - longValues.sort(Long::compare); + List longValues = tpsList.stream().map(TPS::getDate) + .sorted(Long::compare).collect(Collectors.toList()); tpsList.sort(new TPSComparator()); List afterSort = tpsList.stream().map(TPS::getDate).collect(Collectors.toList()); @@ -63,8 +63,8 @@ public class ComparatorTest { public void testUserDataLastPlayedComparator() { List userInfo = RandomData.randomUserData(); - List longValues = userInfo.stream().map(UserInfo::getLastSeen).collect(Collectors.toList()); - longValues.sort(Long::compare); + List longValues = userInfo.stream().map(UserInfo::getLastSeen) + .sorted(Long::compare).collect(Collectors.toList()); Collections.reverse(longValues); System.out.println(longValues); @@ -78,8 +78,8 @@ public class ComparatorTest { public void testUserDataNameComparator() { List userInfo = RandomData.randomUserData(); - List stringValues = userInfo.stream().map(UserInfo::getName).collect(Collectors.toList()); - Collections.sort(stringValues); + List stringValues = userInfo.stream().map(UserInfo::getName) + .sorted().collect(Collectors.toList()); userInfo.sort(new UserInfoNameComparator()); List afterSort = userInfo.stream().map(UserInfo::getName).collect(Collectors.toList()); @@ -91,8 +91,8 @@ public class ComparatorTest { public void testWebUserComparator() throws PassEncryptUtil.CannotPerformOperationException { List webUsers = RandomData.randomWebUsers(); - List intValues = webUsers.stream().map(WebUser::getPermLevel).collect(Collectors.toList()); - intValues.sort(Integer::compare); + List intValues = webUsers.stream().map(WebUser::getPermLevel) + .sorted(Integer::compare).collect(Collectors.toList()); Collections.reverse(intValues); webUsers.sort(new WebUserComparator()); diff --git a/Plan/test/main/java/com/djrapitops/plan/utilities/export/HastebinTest.java b/Plan/src/test/java/com/djrapitops/plan/utilities/export/HastebinTest.java similarity index 71% rename from Plan/test/main/java/com/djrapitops/plan/utilities/export/HastebinTest.java rename to Plan/src/test/java/com/djrapitops/plan/utilities/export/HastebinTest.java index dbf3ae165..6069be9c3 100644 --- a/Plan/test/main/java/com/djrapitops/plan/utilities/export/HastebinTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/utilities/export/HastebinTest.java @@ -1,20 +1,20 @@ package com.djrapitops.plan.utilities.export; -import com.djrapitops.plan.utilities.MiscUtils; +import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.utilities.file.export.Hastebin; import com.djrapitops.plugin.StaticHolder; import com.djrapitops.plugin.api.utility.log.Log; import com.google.common.collect.Iterables; -import org.bukkit.plugin.java.JavaPlugin; import org.json.simple.parser.ParseException; import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.RandomData; -import test.utilities.TestInit; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.RandomData; +import utilities.mocks.SystemMockUtil; import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; @@ -25,19 +25,25 @@ import static junit.framework.TestCase.assertNotNull; /** * @author Fuzzlemann */ -@PowerMockIgnore("javax.net.ssl.*") -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) +@RunWith(MockitoJUnitRunner.Silent.class) public class HastebinTest { private final AtomicBoolean testLink = new AtomicBoolean(false); - @Before - public void checkAvailability() throws Exception { - TestInit.init(); + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + @BeforeClass + public static void setUpClass() throws Exception { + SystemMockUtil.setUp(temporaryFolder.getRoot()) + .enableConfigSystem() + .enableDatabaseSystem(); + } + + @Before + public void checkAvailability() { Thread thread = new Thread(() -> { - StaticHolder.saveInstance(this.getClass(), MiscUtils.getIPlan().getClass()); + StaticHolder.saveInstance(this.getClass(), PlanPlugin.getInstance().getClass()); try { Hastebin.upload(RandomData.randomString(10)); } catch (IOException e) { @@ -75,14 +81,12 @@ public class HastebinTest { } @Test - public void testUpload() throws Exception { + public void testUpload() { if (!testLink.get()) { Log.info("Hastebin not available, skipping testUpload()"); return; } - TestInit.init(); - String link = Hastebin.safeUpload(RandomData.randomString(10)); assertNotNull(link); diff --git a/Plan/test/main/java/com/djrapitops/plan/ui/HtmlTest.java b/Plan/src/test/java/com/djrapitops/plan/utilities/html/HtmlTest.java similarity index 91% rename from Plan/test/main/java/com/djrapitops/plan/ui/HtmlTest.java rename to Plan/src/test/java/com/djrapitops/plan/utilities/html/HtmlTest.java index ef5af7060..0901c9a4b 100644 --- a/Plan/test/main/java/com/djrapitops/plan/ui/HtmlTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/utilities/html/HtmlTest.java @@ -3,9 +3,8 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.djrapitops.plan.ui; +package com.djrapitops.plan.utilities.html; -import com.djrapitops.plan.utilities.html.Html; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/Plan/test/main/java/com/djrapitops/plan/utilities/HtmlUtilsTest.java b/Plan/src/test/java/com/djrapitops/plan/utilities/html/HtmlUtilsTest.java similarity index 80% rename from Plan/test/main/java/com/djrapitops/plan/utilities/HtmlUtilsTest.java rename to Plan/src/test/java/com/djrapitops/plan/utilities/html/HtmlUtilsTest.java index 9a88ba575..8052eacc1 100644 --- a/Plan/test/main/java/com/djrapitops/plan/utilities/HtmlUtilsTest.java +++ b/Plan/src/test/java/com/djrapitops/plan/utilities/html/HtmlUtilsTest.java @@ -3,16 +3,11 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package com.djrapitops.plan.utilities; +package com.djrapitops.plan.utilities.html; -import com.djrapitops.plan.utilities.html.HtmlUtils; import com.google.common.collect.ImmutableMap; -import org.bukkit.plugin.java.JavaPlugin; import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.RandomData; +import utilities.RandomData; import java.io.Serializable; import java.util.Map; @@ -22,8 +17,8 @@ import static org.junit.Assert.assertEquals; /** * @author Rsl1122 */ -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) +//@RunWith(PowerMockRunner.class) +//@PrepareForTest(JavaPlugin.class) public class HtmlUtilsTest { @Test diff --git a/Plan/src/test/java/com/djrapitops/plan/utilities/html/graphs/GraphTest.java b/Plan/src/test/java/com/djrapitops/plan/utilities/html/graphs/GraphTest.java new file mode 100644 index 000000000..e1960f53a --- /dev/null +++ b/Plan/src/test/java/com/djrapitops/plan/utilities/html/graphs/GraphTest.java @@ -0,0 +1,118 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.plan.utilities.html.graphs; + +import com.djrapitops.plan.data.calculation.ActivityIndex; +import com.djrapitops.plan.data.container.TPS; +import com.djrapitops.plan.system.settings.Settings; +import com.djrapitops.plan.utilities.html.graphs.line.*; +import com.djrapitops.plan.utilities.html.graphs.stack.AbstractStackGraph; +import org.junit.Before; +import org.junit.Test; +import utilities.RandomData; + +import java.util.*; + +import static org.junit.Assert.assertTrue; + +/** + * Tests various Graphs. + * + * @author Rsl1122 + */ +public class GraphTest { + + private final List tpsList = new ArrayList<>(); + private final TreeMap>> activityData = new TreeMap<>(); + + @Before + public void setUp() { + String[] groups = ActivityIndex.getGroups(); + for (int i = 0; i < 10; i++) { + tpsList.add(new TPS(i, i, i, i, i, i, i)); + Map> gData = new HashMap<>(); + for (String group : groups) { + Set uuids = new HashSet<>(); + for (int j = 0; j < RandomData.randomInt(1, 20); j++) { + uuids.add(UUID.randomUUID()); + } + gData.put(group, uuids); + } + activityData.put((long) i, gData); + } + } + + @Test + public void testLineGraphsForBracketErrors() { + AbstractLineGraph[] graphs = new AbstractLineGraph[]{ + new CPUGraph(tpsList), + new OnlineActivityGraph(tpsList), + new RamGraph(tpsList), + new TPSGraph(tpsList), + new EntityGraph(tpsList), + new ChunkGraph(tpsList) + }; + + for (AbstractLineGraph graph : graphs) { + System.out.print("Bracket Test: " + graph.getClass().getSimpleName() + " | "); + String series = graph.toHighChartsSeries(); + + System.out.println(series); + + char[] chars = series.toCharArray(); + assertBracketMatch(chars); + } + } + + @Test + public void testStackGraphsForBracketErrors() { + Settings.FORMAT_DECIMALS.setTemporaryValue("#.##"); + + AbstractStackGraph[] graphs = new AbstractStackGraph[]{ + new ActivityStackGraph(activityData) + }; + + for (AbstractStackGraph graph : graphs) { + System.out.print("Bracket Test: " + graph.getClass().getSimpleName() + " | "); + String series = graph.toHighChartsSeries(); + System.out.println(series); + char[] chars = series.toCharArray(); + assertBracketMatch(chars); + + String labels = graph.toHighChartsLabels(); + System.out.println(labels); + chars = labels.toCharArray(); + assertBracketMatch(chars); + } + } + + private void assertBracketMatch(char[] chars) { + Stack bracketStack = new Stack<>(); + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + switch (c) { + case '{': + case '[': + case '(': + bracketStack.push(c); + break; + case ')': + Character pop = bracketStack.pop(); + assertTrue("Bracket mismatch at char: " + i + " Expected (, got " + pop, '(' == pop); + break; + case ']': + Character pop1 = bracketStack.pop(); + assertTrue("Bracket mismatch at char: " + i + " Expected [, got " + pop1, '[' == pop1); + break; + case '}': + Character pop2 = bracketStack.pop(); + assertTrue("Bracket mismatch at char: " + i + " Expected {, got " + pop2, '{' == pop2); + break; + default: + break; + } + } + } +} diff --git a/Plan/test/main/java/test/utilities/RandomData.java b/Plan/src/test/java/utilities/RandomData.java similarity index 96% rename from Plan/test/main/java/test/utilities/RandomData.java rename to Plan/src/test/java/utilities/RandomData.java index 812ec3070..e7204b375 100644 --- a/Plan/test/main/java/test/utilities/RandomData.java +++ b/Plan/src/test/java/utilities/RandomData.java @@ -1,11 +1,11 @@ -package test.utilities; +package utilities; import com.djrapitops.plan.data.WebUser; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.container.TPS; import com.djrapitops.plan.data.container.UserInfo; import com.djrapitops.plan.utilities.PassEncryptUtil; -import com.djrapitops.plan.utilities.analysis.Point; +import com.djrapitops.plan.utilities.html.graphs.line.Point; import org.apache.commons.lang3.RandomStringUtils; import java.util.ArrayList; diff --git a/Plan/src/test/java/utilities/Teardown.java b/Plan/src/test/java/utilities/Teardown.java new file mode 100644 index 000000000..4e301e5d4 --- /dev/null +++ b/Plan/src/test/java/utilities/Teardown.java @@ -0,0 +1,21 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package utilities; + +import com.djrapitops.plan.system.settings.Settings; + +/** + * Test utility for {@code @Teardown} tags. + * + * @author Rsl1122 + */ +public class Teardown { + + public static void resetSettingsTempValues() { + for (Settings settings : Settings.values()) { + settings.setTemporaryValue(null); + } + } +} \ No newline at end of file diff --git a/Plan/src/test/java/utilities/TestConstants.java b/Plan/src/test/java/utilities/TestConstants.java new file mode 100644 index 000000000..f112a64c7 --- /dev/null +++ b/Plan/src/test/java/utilities/TestConstants.java @@ -0,0 +1,23 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package utilities; + +import java.util.UUID; + +/** + * Test Constants go here. + * + * @author Rsl1122 + */ +public class TestConstants { + + public static final UUID SERVER_UUID = UUID.fromString("e4ec2edd-e0ed-3c58-a87d-8a9021899479"); + public static final UUID PLAYER_ONE_UUID = UUID.fromString("45b0dfdb-f71d-4cf3-8c21-27c9d4c651db"); + public static final UUID PLAYER_TWO_UUID = UUID.fromString("ec94a954-1fa1-445b-b09b-9b698519af80"); + + public static final int BUKKIT_MAX_PLAYERS = 20; + public static final int BUNGEE_MAX_PLAYERS = 100; + +} \ No newline at end of file diff --git a/Plan/src/test/java/utilities/TestErrorManager.java b/Plan/src/test/java/utilities/TestErrorManager.java new file mode 100644 index 000000000..292a40224 --- /dev/null +++ b/Plan/src/test/java/utilities/TestErrorManager.java @@ -0,0 +1,20 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package utilities; + +import com.djrapitops.plugin.api.utility.log.errormanager.ErrorManager; + +/** + * ErrorManager for tests that should throw the exceptions that occur. + * + * @author Rsl1122 + */ +public class TestErrorManager extends ErrorManager { + + @Override + public void toLog(String s, Throwable throwable, Class aClass) { + throw new RuntimeException("Error During Test.", throwable); + } +} \ No newline at end of file diff --git a/Plan/src/test/java/utilities/mocks/BukkitMockUtil.java b/Plan/src/test/java/utilities/mocks/BukkitMockUtil.java new file mode 100644 index 000000000..55e82dbab --- /dev/null +++ b/Plan/src/test/java/utilities/mocks/BukkitMockUtil.java @@ -0,0 +1,112 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package utilities.mocks; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plugin.StaticHolder; +import com.djrapitops.plugin.task.RunnableFactory; +import com.djrapitops.plugin.task.ThreadRunnable; +import org.bukkit.Server; +import org.bukkit.plugin.InvalidDescriptionException; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.scheduler.BukkitScheduler; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.Teardown; +import utilities.TestConstants; +import utilities.mocks.objects.FakeConsoleCmdSender; +import utilities.mocks.objects.TestLogger; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; + +import static org.mockito.Mockito.*; + +/** + * Mocking Utility for Bukkit version of Plan. + * + * @author Rsl1122 + */ +public class BukkitMockUtil extends MockUtil { + + private Plan planMock; + + private BukkitMockUtil() { + } + + public static BukkitMockUtil setUp() { + RunnableFactory.activateTestMode(); + Teardown.resetSettingsTempValues(); + return new BukkitMockUtil().mockPlugin(); + } + + private BukkitMockUtil mockPlugin() { + planMock = Mockito.mock(Plan.class); + super.planMock = planMock; + StaticHolder.register(Plan.class, planMock); + StaticHolder.register(planMock); + + StaticHolder.saveInstance(MockitoJUnitRunner.class, Plan.class); + StaticHolder.saveInstance(ThreadRunnable.class, Plan.class); + + doCallRealMethod().when(planMock).getVersion(); + doCallRealMethod().when(planMock).getColorScheme(); + + return this; + } + + public BukkitMockUtil withDataFolder(File tempFolder) { + when(planMock.getDataFolder()).thenReturn(tempFolder); + return this; + } + + public BukkitMockUtil withLogging() { + doCallRealMethod().when(planMock).log(Mockito.anyString(), Mockito.anyString()); + TestLogger testLogger = new TestLogger(); + doReturn(testLogger).when(planMock).getLogger(); + return this; + } + + + public BukkitMockUtil withPluginDescription() { + try { + File pluginYml = getFile("/plugin.yml"); + PluginDescriptionFile description = new PluginDescriptionFile(new FileInputStream(pluginYml)); + when(planMock.getDescription()).thenReturn(description); + } catch (FileNotFoundException | InvalidDescriptionException e) { + System.out.println("Error while setting plugin description"); + } + return this; + } + + public BukkitMockUtil withResourceFetchingFromJar() throws Exception { + withPluginFiles(); + return this; + } + + public BukkitMockUtil withServer() { + Server serverMock = Mockito.mock(Server.class); + when(serverMock.getIp()).thenReturn(""); + when(serverMock.getName()).thenReturn("Bukkit"); + when(serverMock.getServerName()).thenReturn("Bukkit"); + when(serverMock.getPort()).thenReturn(25565); + when(serverMock.getVersion()).thenReturn("1.12.2"); + when(serverMock.getBukkitVersion()).thenReturn("32423"); + when(serverMock.getMaxPlayers()).thenReturn(TestConstants.BUKKIT_MAX_PLAYERS); + FakeConsoleCmdSender sender = new FakeConsoleCmdSender(); + when(serverMock.getConsoleSender()).thenReturn(sender); + + BukkitScheduler bukkitScheduler = Mockito.mock(BukkitScheduler.class); + doReturn(bukkitScheduler).when(serverMock).getScheduler(); + + when(planMock.getServer()).thenReturn(serverMock); + return this; + } + + public Plan getPlanMock() { + return planMock; + } +} \ No newline at end of file diff --git a/Plan/src/test/java/utilities/mocks/BungeeMockUtil.java b/Plan/src/test/java/utilities/mocks/BungeeMockUtil.java new file mode 100644 index 000000000..0aa0920f2 --- /dev/null +++ b/Plan/src/test/java/utilities/mocks/BungeeMockUtil.java @@ -0,0 +1,107 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package utilities.mocks; + +import com.djrapitops.plan.PlanBungee; +import com.djrapitops.plugin.StaticHolder; +import com.djrapitops.plugin.task.RunnableFactory; +import com.djrapitops.plugin.task.ThreadRunnable; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.ProxyConfig; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.plugin.PluginDescription; +import net.md_5.bungee.api.plugin.PluginManager; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import utilities.Teardown; +import utilities.TestConstants; +import utilities.mocks.objects.FakeBungeeConsole; +import utilities.mocks.objects.TestLogger; + +import java.io.File; +import java.util.HashSet; + +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.when; + +/** + * Mocking Utility for Bungee version of Plan (PlanBungee). + * + * @author Rsl1122 + */ +public class BungeeMockUtil extends MockUtil { + + private PlanBungee planMock; + + private BungeeMockUtil() { + } + + public static BungeeMockUtil setUp() { + RunnableFactory.activateTestMode(); + Teardown.resetSettingsTempValues(); + return new BungeeMockUtil().mockPlugin(); + } + + private BungeeMockUtil mockPlugin() { + planMock = Mockito.mock(PlanBungee.class); + super.planMock = planMock; + StaticHolder.register(PlanBungee.class, planMock); + StaticHolder.register(planMock); + + StaticHolder.saveInstance(MockitoJUnitRunner.class, PlanBungee.class); + StaticHolder.saveInstance(ThreadRunnable.class, PlanBungee.class); + + doCallRealMethod().when(planMock).getVersion(); + doCallRealMethod().when(planMock).getColorScheme(); + return this; + } + + public BungeeMockUtil withDataFolder(File tempFolder) { + when(planMock.getDataFolder()).thenReturn(tempFolder); + return this; + } + + public BungeeMockUtil withResourceFetchingFromJar() throws Exception { + withPluginFiles(); + return this; + } + + public BungeeMockUtil withLogging() { + doCallRealMethod().when(planMock).log(Mockito.anyString(), Mockito.anyString()); + TestLogger testLogger = new TestLogger(); + when(planMock.getLogger()).thenReturn(testLogger); + return this; + } + + public BungeeMockUtil withProxy() { + ProxyServer proxyMock = Mockito.mock(ProxyServer.class); + when(proxyMock.getVersion()).thenReturn("1.12.2"); + + CommandSender console = new FakeBungeeConsole(); + when(proxyMock.getConsole()).thenReturn(console); + + ProxyConfig proxyConfig = Mockito.mock(ProxyConfig.class); + when(proxyConfig.getPlayerLimit()).thenReturn(TestConstants.BUNGEE_MAX_PLAYERS); + when(proxyMock.getConfig()).thenReturn(proxyConfig); + + PluginManager pm = Mockito.mock(PluginManager.class); + when(proxyMock.getPluginManager()).thenReturn(pm); + + when(planMock.getProxy()).thenReturn(proxyMock); + return this; + } + + public BungeeMockUtil withPluginDescription() { + File pluginYml = getFile("/bungee.yml"); + HashSet empty = new HashSet<>(); + PluginDescription pluginDescription = new PluginDescription("Plan", "", "9.9.9", "Rsl1122", empty, empty, pluginYml, ""); + when(planMock.getDescription()).thenReturn(pluginDescription); + return this; + } + + public PlanBungee getPlanMock() { + return planMock; + } +} \ No newline at end of file diff --git a/Plan/src/test/java/utilities/mocks/MockUtil.java b/Plan/src/test/java/utilities/mocks/MockUtil.java new file mode 100644 index 000000000..964b6c85b --- /dev/null +++ b/Plan/src/test/java/utilities/mocks/MockUtil.java @@ -0,0 +1,50 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package utilities.mocks; + +import com.djrapitops.plan.PlanPlugin; + +import java.io.File; +import java.io.FileInputStream; + +import static org.mockito.Mockito.doReturn; + +/** + * Abstract MockUtil for methods that can be used for both Bungee and Bukkit. + * + * @author Rsl1122 + */ +abstract class MockUtil { + + PlanPlugin planMock; + + File getFile(String fileName) { + return new File(getClass().getResource(fileName).getPath()); + } + + private void withPluginFile(String fileName) throws Exception { + if (planMock.getDataFolder() == null) { + throw new IllegalStateException("withDataFolder needs to be called before setting files"); + } + try { + File file = getFile("/" + fileName); + doReturn(new FileInputStream(file)).when(planMock).getResource(fileName); + } catch (NullPointerException e) { + System.out.println("File is missing! " + fileName); + } + } + + void withPluginFiles() throws Exception { + withPluginFile("bungeeconfig.yml"); + withPluginFile("config.yml"); + withPluginFile("web/server.html"); + withPluginFile("web/player.html"); + withPluginFile("web/network.html"); + withPluginFile("web/error.html"); + withPluginFile("themes/theme.yml"); + withPluginFile("DefaultServerInfoFile.yml"); + } + +} \ No newline at end of file diff --git a/Plan/src/test/java/utilities/mocks/SystemMockUtil.java b/Plan/src/test/java/utilities/mocks/SystemMockUtil.java new file mode 100644 index 000000000..7f32a0004 --- /dev/null +++ b/Plan/src/test/java/utilities/mocks/SystemMockUtil.java @@ -0,0 +1,75 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package utilities.mocks; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.api.exceptions.EnableException; +import com.djrapitops.plan.api.exceptions.database.DBException; +import com.djrapitops.plan.system.BukkitSystem; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plugin.StaticHolder; + +import java.io.File; + +/** + * Utility for mocking only certain parts of systems. + * + * @author Rsl1122 + */ +public class SystemMockUtil { + + private BukkitSystem bukkitSystem; + + public static SystemMockUtil setUp(File dataFolder) throws Exception { + StaticHolder.saveInstance(SystemMockUtil.class, Plan.class); + return new SystemMockUtil().initializeBukkitSystem(dataFolder); + } + + public SystemMockUtil enableConfigSystem() throws Exception { + bukkitSystem.getFileSystem().enable(); + bukkitSystem.getConfigSystem().enable(); + return this; + } + + public SystemMockUtil enableCacheSystem() throws Exception { + bukkitSystem.getCacheSystem().enable(); + return this; + } + + private SystemMockUtil initializeBukkitSystem(File dataFolder) throws Exception { + Plan planMock = BukkitMockUtil.setUp() + .withDataFolder(dataFolder) + .withLogging() + .withResourceFetchingFromJar() + .withPluginDescription() + .withServer() + .getPlanMock(); + bukkitSystem = new BukkitSystem(planMock); + return this; + } + + public SystemMockUtil enableProcessingQueue() { + bukkitSystem.getProcessingQueue().enable(); + return this; + } + + public SystemMockUtil enableDatabaseSystem() throws EnableException { + bukkitSystem.getDatabaseSystem().enable(); + return this; + } + + public SystemMockUtil enableServerInfoSystem() throws EnableException { + bukkitSystem.getServerInfo().enable(); + return this; + } + + public SystemMockUtil enableDatabaseSystem(SQLDB db) throws EnableException, DBException { + DBSystem dbSystem = bukkitSystem.getDatabaseSystem(); + dbSystem.enable(); + dbSystem.setActiveDatabase(db); + return this; + } +} \ No newline at end of file diff --git a/Plan/src/test/java/utilities/mocks/objects/FakeBungeeConsole.java b/Plan/src/test/java/utilities/mocks/objects/FakeBungeeConsole.java new file mode 100644 index 000000000..82d84cc09 --- /dev/null +++ b/Plan/src/test/java/utilities/mocks/objects/FakeBungeeConsole.java @@ -0,0 +1,79 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package utilities.mocks.objects; + +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.chat.BaseComponent; + +import java.util.Collection; + +/** + * Fake console to return as mock for Bungee. + *

    + * Logs with System.out.print. + * + * @author Rsl1122 + */ +public class FakeBungeeConsole implements CommandSender { + + @Override + public String getName() { + return null; + } + + @Override + public void sendMessage(String s) { + System.out.println(s); + } + + @Override + public void sendMessages(String... strings) { + for (String string : strings) { + sendMessage(string); + } + } + + @Override + public void sendMessage(BaseComponent... baseComponents) { + for (BaseComponent baseComponent : baseComponents) { + sendMessage(baseComponent); + } + } + + @Override + public void sendMessage(BaseComponent baseComponent) { + sendMessage(baseComponent.toPlainText()); + } + + @Override + public Collection getGroups() { + return null; + } + + @Override + public void addGroups(String... strings) { + + } + + @Override + public void removeGroups(String... strings) { + + } + + @Override + public boolean hasPermission(String s) { + return true; + } + + @Override + public void setPermission(String s, boolean b) { + + } + + @Override + public Collection getPermissions() { + return null; + } +} \ No newline at end of file diff --git a/Plan/src/test/java/utilities/mocks/objects/FakeConsoleCmdSender.java b/Plan/src/test/java/utilities/mocks/objects/FakeConsoleCmdSender.java new file mode 100644 index 000000000..6c69f2163 --- /dev/null +++ b/Plan/src/test/java/utilities/mocks/objects/FakeConsoleCmdSender.java @@ -0,0 +1,147 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package utilities.mocks.objects; + +import org.bukkit.Server; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.conversations.Conversation; +import org.bukkit.conversations.ConversationAbandonedEvent; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionAttachment; +import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.plugin.Plugin; + +import java.util.Set; + +/** + * Fake ConsoleCommandSender + * + * @author Rsl1122 + */ +public class FakeConsoleCmdSender implements ConsoleCommandSender { + + @Override + public void sendMessage(String s) { + System.out.println("Log: " + s); + } + + @Override + public void sendMessage(String[] strings) { + for (String string : strings) { + sendMessage(string); + } + } + + @Override + public Server getServer() { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public Spigot spigot() { + return null; + } + + @Override + public boolean isConversing() { + return false; + } + + @Override + public void acceptConversationInput(String s) { + + } + + @Override + public boolean beginConversation(Conversation conversation) { + return false; + } + + @Override + public void abandonConversation(Conversation conversation) { + + } + + @Override + public void abandonConversation(Conversation conversation, ConversationAbandonedEvent conversationAbandonedEvent) { + + } + + @Override + public void sendRawMessage(String s) { + + } + + @Override + public boolean isPermissionSet(String s) { + return false; + } + + @Override + public boolean isPermissionSet(Permission permission) { + return false; + } + + @Override + public boolean hasPermission(String s) { + return false; + } + + @Override + public boolean hasPermission(Permission permission) { + return false; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b) { + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin) { + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b, int i) { + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, int i) { + return null; + } + + @Override + public void removeAttachment(PermissionAttachment permissionAttachment) { + + } + + @Override + public void recalculatePermissions() { + + } + + @Override + public Set getEffectivePermissions() { + return null; + } + + @Override + public boolean isOp() { + return false; + } + + @Override + public void setOp(boolean b) { + + } + +} \ No newline at end of file diff --git a/Plan/test/main/java/test/utilities/MockUtils.java b/Plan/src/test/java/utilities/mocks/objects/MockUtils.java similarity index 87% rename from Plan/test/main/java/test/utilities/MockUtils.java rename to Plan/src/test/java/utilities/mocks/objects/MockUtils.java index 7e11296de..43bb31d2d 100644 --- a/Plan/test/main/java/test/utilities/MockUtils.java +++ b/Plan/src/test/java/utilities/mocks/objects/MockUtils.java @@ -1,4 +1,4 @@ -package test.utilities; +package utilities.mocks.objects; import com.sun.net.httpserver.*; import org.bukkit.GameMode; @@ -7,7 +7,6 @@ import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; import java.io.*; import java.net.InetSocketAddress; @@ -17,11 +16,13 @@ import java.nio.charset.Charset; import java.util.*; import java.util.zip.GZIPInputStream; -import static org.powermock.api.mockito.PowerMockito.when; +import static org.mockito.Mockito.when; /** * @author Rsl1122 + * @deprecated To Be Refactored into multiple classes. */ +@Deprecated public class MockUtils { public static World mockWorld() { @@ -31,7 +32,7 @@ public class MockUtils { } public static Player mockPlayer() { - Player p = PowerMockito.mock(Player.class); + Player p = Mockito.mock(Player.class); when(p.getGameMode()).thenReturn(GameMode.SURVIVAL); when(p.getUniqueId()).thenReturn(UUID.fromString("45b0dfdb-f71d-4cf3-8c21-27c9d4c651db")); when(p.getFirstPlayed()).thenReturn(1234567L); @@ -45,12 +46,8 @@ public class MockUtils { return p; } - public static UUID getPlayerUUID() { - return UUID.fromString("45b0dfdb-f71d-4cf3-8c21-27c9d4c651db"); - } - public static Player mockPlayer2() { - Player p = PowerMockito.mock(Player.class); + Player p = Mockito.mock(Player.class); when(p.getGameMode()).thenReturn(GameMode.SPECTATOR); when(p.getUniqueId()).thenReturn(UUID.fromString("ec94a954-1fa1-445b-b09b-9b698519af80")); when(p.getFirstPlayed()).thenReturn(3423434L); @@ -64,19 +61,8 @@ public class MockUtils { return p; } - public static UUID getPlayer2UUID() { - return UUID.fromString("ec94a954-1fa1-445b-b09b-9b698519af80"); - } - - public static Set getUUIDs() { - Set uuids = new HashSet<>(); - uuids.add(getPlayerUUID()); - uuids.add(getPlayer2UUID()); - return uuids; - } - public static Player mockBrokenPlayer() { - Player p = PowerMockito.mock(Player.class); + Player p = Mockito.mock(Player.class); when(p.getGameMode()).thenReturn(GameMode.SURVIVAL); when(p.getUniqueId()).thenReturn(UUID.fromString("45b0dfdb-f71d-4cf3-8c21-27c9d4c651db")); when(p.getFirstPlayed()).thenReturn(1234567L); @@ -90,11 +76,11 @@ public class MockUtils { } public static CommandSender mockConsoleSender() { - return PowerMockito.mock(CommandSender.class); + return Mockito.mock(CommandSender.class); } public static HttpServer mockHTTPServer() { - HttpServer httpServer = PowerMockito.mock(HttpServer.class); + HttpServer httpServer = Mockito.mock(HttpServer.class); when(httpServer.getAddress()).thenReturn(new InetSocketAddress(80)); when(httpServer.getExecutor()).thenReturn(command -> System.out.println("HTTP Server command received")); return httpServer; diff --git a/Plan/src/test/java/utilities/mocks/objects/TestLogger.java b/Plan/src/test/java/utilities/mocks/objects/TestLogger.java new file mode 100644 index 000000000..4def4e7ed --- /dev/null +++ b/Plan/src/test/java/utilities/mocks/objects/TestLogger.java @@ -0,0 +1,25 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package utilities.mocks.objects; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Logger to use during tests with Mockito. + * + * @author Rsl1122 + */ +public class TestLogger extends Logger { + + public TestLogger() { + super("TestLogger", null); + } + + @Override + public void log(Level level, String msg) { + System.out.println(level.getName() + ": " + msg); + } +} \ No newline at end of file diff --git a/Plan/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/Plan/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 000000000..ca6ee9cea --- /dev/null +++ b/Plan/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline \ No newline at end of file diff --git a/Plan/test/main/java/com/djrapitops/plan/PermissionsTest.java b/Plan/test/main/java/com/djrapitops/plan/PermissionsTest.java deleted file mode 100644 index cc3bad2d1..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/PermissionsTest.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.djrapitops.plan; - -import com.djrapitops.plan.settings.Permissions; -import org.junit.Test; -import test.utilities.TestUtils; - -import static org.junit.Assert.assertEquals; - -/** - * @author Rsl1122 - */ -public class PermissionsTest { - - @Test - public void testGetPermission() throws NoSuchFieldException, IllegalAccessException { - for (Permissions type : Permissions.values()) { - String exp = TestUtils.getStringFieldValue(type, "permission"); - - assertEquals(exp, type.getPermission()); - assertEquals(exp, type.getPerm()); - } - } -} \ No newline at end of file diff --git a/Plan/test/main/java/com/djrapitops/plan/ServerVariableHolderTest.java b/Plan/test/main/java/com/djrapitops/plan/ServerVariableHolderTest.java deleted file mode 100644 index 008cc3774..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/ServerVariableHolderTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.djrapitops.plan; - -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.TestInit; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertFalse; - -/** - * @author Fuzzlemann - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) -public class ServerVariableHolderTest { - - @Before - public void setUp() throws Exception { - TestInit.init(); - } - - @Test - public void testServerVariable() { - boolean usingPaper = Plan.getInstance().getVariable().isUsingPaper(); - assertFalse(usingPaper); - - String exp = Plan.getInstance().getVariable().getIp(); - assertEquals(exp, "0.0.0.0"); - } -} diff --git a/Plan/test/main/java/com/djrapitops/plan/SettingsTest.java b/Plan/test/main/java/com/djrapitops/plan/SettingsTest.java deleted file mode 100644 index e8e924600..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/SettingsTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.djrapitops.plan; - -import com.djrapitops.plan.settings.Settings; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.TestInit; - -import java.util.Collections; -import java.util.List; - -import static org.junit.Assert.*; - -/** - * @author Rsl1122 - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) -public class SettingsTest { - - @Before - public void setUp() throws Exception { - TestInit.init(); - } - - @Test - public void testIsTrue() { - assertTrue("COMBINE_COMMAND_ALIASES supposed to be true by default", Settings.COMBINE_COMMAND_ALIASES.isTrue()); - } - - @Test - public void testSetValue() { - Settings gatherCommands = Settings.LOG_UNKNOWN_COMMANDS; - - gatherCommands.setValue(false); - assertFalse(gatherCommands.isTrue()); - - gatherCommands.setValue(true); - assertTrue(gatherCommands.isTrue()); - } - - @Test - public void testToString() { - assertEquals("SQLite", Settings.DB_TYPE.toString()); - } - - @Test - public void testGetNumber() { - assertEquals(8804, Settings.WEBSERVER_PORT.getNumber()); - } - - @Test - public void testGetStringList() { - List exp = Collections.singletonList("ExampleTown"); - List result = Settings.HIDE_TOWNS.getStringList(); - - assertEquals(exp, result); - } - - @Test - public void testGetPath() { - assertEquals("WebServer.Port", Settings.WEBSERVER_PORT.getPath()); - } -} diff --git a/Plan/test/main/java/com/djrapitops/plan/data/SessionTest.java b/Plan/test/main/java/com/djrapitops/plan/data/SessionTest.java deleted file mode 100644 index 554a5f988..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/data/SessionTest.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.djrapitops.plan.data; - -import com.djrapitops.plan.data.container.Session; -import org.junit.Before; - -/** - * @author Rsl1122 - */ -public class SessionTest { - - private Session session; - - @Before - public void setUp() { - } - - // TODO Rewrite -} diff --git a/Plan/test/main/java/com/djrapitops/plan/data/UserInfoTest.java b/Plan/test/main/java/com/djrapitops/plan/data/UserInfoTest.java deleted file mode 100644 index ab526a3f4..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/data/UserInfoTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.djrapitops.plan.data; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.data.container.UserInfo; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.TestInit; - -/** - * @author Rsl1122 - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) -@Ignore -public class UserInfoTest { - // TODO Rewrite - - private UserInfo session; - private Plan plan; - - @Before - public void setUp() throws Exception { - TestInit.init(); - } - - @Test - public void test() { - // TODO Rewrite - } -} diff --git a/Plan/test/main/java/com/djrapitops/plan/data/cache/DataCacheTest.java b/Plan/test/main/java/com/djrapitops/plan/data/cache/DataCacheTest.java deleted file mode 100644 index a093737f5..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/data/cache/DataCacheTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.djrapitops.plan.data.cache; - -import com.djrapitops.plan.database.Database; -import com.djrapitops.plan.systems.cache.DataCache; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) -public class DataCacheTest { - - private Database db; - private DataCache dataCache; - - private int callsToSaveCommandUse; - private int callsToSaveUserData; - private int callsToSaveMultiple; - - @Before - public void setUp() { - - } - - @After - public void tearDown() { - - } - - @Ignore - @Test - public void testHandler() { - // TODO - } -} diff --git a/Plan/test/main/java/com/djrapitops/plan/data/cache/PageCacheTest.java b/Plan/test/main/java/com/djrapitops/plan/data/cache/PageCacheTest.java deleted file mode 100644 index 1efd781d8..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/data/cache/PageCacheTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.djrapitops.plan.data.cache; - -import com.djrapitops.plan.systems.webserver.pagecache.PageCache; -import com.djrapitops.plan.systems.webserver.pagecache.PageLoader; -import com.djrapitops.plan.systems.webserver.response.Response; -import org.junit.Test; -import test.utilities.RandomData; - -import static junit.framework.TestCase.*; - -/** - * @author Fuzzlemann - */ -public class PageCacheTest { - private final String IDENTIFIER = RandomData.randomString(10); - private final String RESPONSE_STRING = RandomData.randomString(10); - private final Response RESPONSE = new Response() { - @Override - public String getResponse() { - return RESPONSE_STRING; - } - }; - private final PageLoader LOADER = () -> RESPONSE; - - @Test - public void testCreateResponse() { - String expResponse = RESPONSE.getResponse(); - String response = LOADER.createResponse().getResponse(); - - assertEquals(expResponse, response); - } - - @Test - public void testCache() { - Response expResponse = LOADER.createResponse(); - - assertFalse(PageCache.isCached(IDENTIFIER)); - - Response response = PageCache.loadPage(IDENTIFIER, LOADER); - assertTrue(PageCache.isCached(IDENTIFIER)); - - assertEquals(expResponse, response); - } - - @Test - public void testClearCache() { - PageCache.cachePage(IDENTIFIER, LOADER); - assertTrue(PageCache.isCached(IDENTIFIER)); - - PageCache.clearCache(); - assertFalse(PageCache.isCached(IDENTIFIER)); - } - - @Test - public void testRemoveIf() { - PageCache.cachePage(IDENTIFIER, LOADER); - assertTrue(PageCache.isCached(IDENTIFIER)); - - PageCache.removeIf(identifier -> identifier.equals(IDENTIFIER)); - assertFalse(PageCache.isCached(IDENTIFIER)); - } -} diff --git a/Plan/test/main/java/com/djrapitops/plan/data/cache/SessionCacheTest.java b/Plan/test/main/java/com/djrapitops/plan/data/cache/SessionCacheTest.java deleted file mode 100644 index 5a2372f94..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/data/cache/SessionCacheTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.djrapitops.plan.data.cache; - -import com.djrapitops.plan.systems.cache.SessionCache; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.TestInit; - -/** - * @author Rsl1122 - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) -public class SessionCacheTest { - - private SessionCache test; - - @Before - public void setUp() throws Exception { - TestInit.init(); - } - - @Test - public void test() { - // TODO Rewrite - } -} diff --git a/Plan/test/main/java/com/djrapitops/plan/database/DBUtilsTest.java b/Plan/test/main/java/com/djrapitops/plan/database/DBUtilsTest.java deleted file mode 100644 index 1969dfe88..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/database/DBUtilsTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.djrapitops.plan.database; - -import org.junit.Test; -import test.utilities.RandomData; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.junit.Assert.assertEquals; - -/** - * @author ristolah - */ -public class DBUtilsTest { - - @Test - public void testSplitIntoBatches() { - List list = new ArrayList<>(); - for (int i = 0; i < 21336; i++) { - list.add(i); - } - - List> result = DBUtils.splitIntoBatches(list); - - assertEquals(3, result.size()); - assertEquals(10192, result.get(0).size()); - assertEquals(10192, result.get(1).size()); - assertEquals(952, result.get(2).size()); - } - - @Test - public void testSplitIntoBatchesSingleBatch() { - List list = new ArrayList<>(); - for (int i = 0; i < 10192; i++) { - list.add(i); - } - - List> result = DBUtils.splitIntoBatches(list); - - assertEquals(1, result.size()); - assertEquals(10192, result.get(0).size()); - } - - @Test - public void testSplitIntoBatchesId() { - Map> map = new HashMap<>(); - for (int i = 0; i < 10; i++) { - for (int j = 0; j < 2133; j++) { - map.computeIfAbsent(i, k -> new ArrayList<>()); - map.get(i).add(j); - } - } - - List>> result = DBUtils.splitIntoBatchesId(map); - - assertEquals(3, result.size()); - assertEquals(10192, result.get(0).size()); - assertEquals(10192, result.get(1).size()); - assertEquals(946, result.get(2).size()); - } - - @Test - public void testContainers() { - Object object = new Object(); - int id = RandomData.randomInt(1, 100); - - Container container = new Container<>(object, id); - - assertEquals(id, container.getId()); - assertEquals(object, container.getObject()); - } - -} diff --git a/Plan/test/main/java/com/djrapitops/plan/systems/webserver/WebServerTest.java b/Plan/test/main/java/com/djrapitops/plan/systems/webserver/WebServerTest.java deleted file mode 100644 index 08b657f65..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/systems/webserver/WebServerTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.djrapitops.plan.systems.webserver; - -import com.djrapitops.plan.Plan; -import com.sun.net.httpserver.HttpExchange; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.MockUtils; -import test.utilities.TestInit; - -import java.io.IOException; -import java.util.HashMap; - -/** - * //TODO Class Javadoc Comment - * - * @author Rsl1122 - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({JavaPlugin.class}) -public class WebServerTest { - - private WebServer webServer; - private RequestHandler requestHandler; - - @Before - public void setUp() throws Exception { - TestInit testInit = TestInit.init(); - Plan plugin = testInit.getPlanMock(); - webServer = new WebServer(plugin); - requestHandler = new RequestHandler(plugin, webServer); - } - - @Test - public void testMockSetup() throws IOException { - HttpExchange exchange = MockUtils.getHttpExchange( - "POST", - "/api/pingwebapi", - "", - new HashMap<>() - ); - requestHandler.handle(exchange); - System.out.println(MockUtils.getResponseStream(exchange)); - } -} \ No newline at end of file diff --git a/Plan/test/main/java/com/djrapitops/plan/ui/graphs/GraphTest.java b/Plan/test/main/java/com/djrapitops/plan/ui/graphs/GraphTest.java deleted file mode 100644 index 05695ef92..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/ui/graphs/GraphTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package com.djrapitops.plan.ui.graphs; - -import com.djrapitops.plan.data.container.Session; -import com.djrapitops.plan.data.container.TPS; -import com.djrapitops.plan.data.time.WorldTimes; -import com.djrapitops.plan.utilities.analysis.Point; -import com.djrapitops.plan.utilities.html.graphs.PunchCardGraph; -import com.djrapitops.plan.utilities.html.graphs.line.*; -import org.apache.commons.lang3.StringUtils; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.RandomData; -import test.utilities.TestInit; - -import java.util.*; - -import static junit.framework.TestCase.assertEquals; - -/** - * @author Fuzzlemann - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({JavaPlugin.class}) -public class GraphTest { - - private final List tpsList = new ArrayList<>(); - private final List sessionList = new ArrayList<>(); - private final Map geoList = new HashMap<>(); - private final WorldTimes worldTimes = new WorldTimes("WORLD", "SURVIVAL"); - - private List points = new ArrayList<>(); - - @Before - public void setUp() throws Exception { - TestInit t = TestInit.init(); - for (int i = 0; i < 10; i++) { - tpsList.add(new TPS(i, i, i, i, i, i, i)); - sessionList.add(new Session(i, (long) i, (long) i, i, i)); - geoList.put(String.valueOf(i), i); - } - - points = RandomData.randomPoints(); - } - - @Test - public void testGraphCreators() { - String expected = "[[0,0.0],[1,1.0],[2,2.0],[3,3.0],[4,4.0],[5,5.0],[6,6.0],[7,7.0],[8,8.0],[9,9.0]]"; - assertEquals(expected, CPUGraph.createSeries(tpsList)); - assertEquals(expected, PlayerActivityGraph.createSeries(tpsList)); - // TODO Fix TimeZone Dependency of this test - // assertEquals("[{x:3600000, y:3, z:14, marker: { radius:14}},]", PunchCardGraph.createSeries(sessionList)); - - assertEquals(expected, RamGraph.createSeries(tpsList)); - assertEquals(expected, TPSGraph.createSeries(tpsList)); - assertEquals(expected, WorldLoadGraph.createSeriesChunks(tpsList)); - assertEquals(expected, WorldLoadGraph.createSeriesEntities(tpsList)); -// assertEquals("[{'code':'1','value':1},{'code':'2','value':2},{'code':'3','value':3},{'code':'4','value':4},{'code':'5','value':5},{'code':'6','value':6},{'code':'7','value':7},{'code':'8','value':8},{'code':'9','value':9}]", WorldMap.createSeries(geoList)); - // TODO fix config mock dependency - // assertEquals("[[{name:'WORLD',y:0,drilldown: 'WORLD'}], [{name:'WORLD', id:'WORLD',colors: gmPieColors,data: [['SURVIVAL',0],['SPECTATOR',0],['CREATIVE',0],['ADVENTURE',0]]}]]", -// Arrays.toString(WorldPie.createSeries(worldTimes))); - } - - @Test - public void testGraphCreatorsForBracketMistakes() { - String[] series = new String[]{ - CPUGraph.createSeries(tpsList), - PlayerActivityGraph.createSeries(tpsList), - PunchCardGraph.createSeries(sessionList), - RamGraph.createSeries(tpsList), - TPSGraph.createSeries(tpsList), - WorldLoadGraph.createSeriesChunks(tpsList), - WorldLoadGraph.createSeriesEntities(tpsList), -// WorldMap.createSeries(geoList), - // TODO fix config mock dependency -// Arrays.toString(WorldPie.createSeries(worldTimes)) - }; - for (String test : series) { - int opened = StringUtils.countMatches(test, "{"); - int closed = StringUtils.countMatches(test, "}"); - Assert.assertEquals(opened, closed); - opened = StringUtils.countMatches(test, "["); - closed = StringUtils.countMatches(test, "]"); - Assert.assertEquals(opened, closed); - } - } - - @Test - public void testSeriesCreator() { - String result = StringUtils.removeAll(LineSeries.createSeries(points, false, false), "[\\[\\]]"); - String[] splittedResult = result.split(","); - - Map expected = new LinkedHashMap<>(); - - for (int i = 0; i < splittedResult.length; i++) { - expected.put(splittedResult[i++], splittedResult[i]); - } - - int i2 = 0; - for (Map.Entry entry : expected.entrySet()) { - String expectedX = entry.getKey(); - String expectedY = entry.getValue(); - - Point point = points.get(i2); - - assertEquals("Given X does not match expected X", expectedX, String.valueOf((long) point.getX())); - assertEquals("Given Y does not match expected Y", expectedY, String.valueOf(point.getY())); - - i2++; - } - } -} diff --git a/Plan/test/main/java/com/djrapitops/plan/utilities/ConditionTest.java b/Plan/test/main/java/com/djrapitops/plan/utilities/ConditionTest.java deleted file mode 100644 index 8ae9aba3d..000000000 --- a/Plan/test/main/java/com/djrapitops/plan/utilities/ConditionTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.djrapitops.plan.utilities; - -import com.djrapitops.plugin.command.ISender; -import com.djrapitops.plugin.command.bukkit.BukkitCMDSender; -import org.bukkit.plugin.java.JavaPlugin; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import test.utilities.MockUtils; -import test.utilities.RandomData; -import test.utilities.TestInit; - -import static junit.framework.TestCase.assertFalse; -import static junit.framework.TestCase.assertTrue; - -/** - * @author Fuzzlemann - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest(JavaPlugin.class) -public class ConditionTest { - - @Before - public void setUp() throws Exception { - TestInit.init(); - } - - @Test - public void testTrueCheck() { - String message = RandomData.randomString(10); - - assertTrue(Condition.isTrue(true, message)); - } - - @Test - public void testTrueAtISenderCheck() { - String message = RandomData.randomString(10); - ISender sender = new BukkitCMDSender(MockUtils.mockPlayer()); - - assertTrue(Condition.isTrue(true, message, sender)); - assertFalse(Condition.isTrue(false, message, sender)); - } - - @Test - public void testErrorCheck() { - String message = RandomData.randomString(10); - - assertTrue(Condition.errorIfFalse(true, message)); - assertFalse(Condition.errorIfFalse(false, message)); - } -} diff --git a/Plan/test/main/java/test/utilities/DBTestSuite.java b/Plan/test/main/java/test/utilities/DBTestSuite.java deleted file mode 100644 index 8a02fd347..000000000 --- a/Plan/test/main/java/test/utilities/DBTestSuite.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package test.utilities; - -import com.djrapitops.plan.database.DatabaseTest; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -import java.io.File; - -/** - * @author Fuzzlemann - */ -@RunWith(Suite.class) -@Suite.SuiteClasses({DatabaseTest.class}) -public class DBTestSuite { - @BeforeClass - public static void setUp() { - clean(); - } - - @AfterClass - public static void tearDown() { - clean(); - } - - private static void clean() { - File testFolder = TestInit.getTestFolder(); - - if (!testFolder.exists() || !testFolder.isDirectory()) { - return; - } - - File[] files = testFolder.listFiles(); - - if (files == null) { - return; - } - - for (File f : files) { - if (!f.delete()) { - f.deleteOnExit(); - } - } - } -} diff --git a/Plan/test/main/java/test/utilities/TestInit.java b/Plan/test/main/java/test/utilities/TestInit.java deleted file mode 100644 index 5b2be68ed..000000000 --- a/Plan/test/main/java/test/utilities/TestInit.java +++ /dev/null @@ -1,297 +0,0 @@ -package test.utilities; - -import com.djrapitops.plan.Plan; -import com.djrapitops.plan.ServerVariableHolder; -import com.djrapitops.plan.settings.Settings; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.systems.cache.DataCache; -import com.djrapitops.plan.systems.info.server.BukkitServerInfoManager; -import com.djrapitops.plan.utilities.file.FileUtil; -import com.djrapitops.plugin.IPlugin; -import com.djrapitops.plugin.StaticHolder; -import com.djrapitops.plugin.api.config.Config; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.settings.ColorScheme; -import com.djrapitops.plugin.task.RunnableFactory; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; -import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.conversations.Conversation; -import org.bukkit.conversations.ConversationAbandonedEvent; -import org.bukkit.permissions.Permission; -import org.bukkit.permissions.PermissionAttachment; -import org.bukkit.permissions.PermissionAttachmentInfo; -import org.bukkit.plugin.Plugin; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.modules.junit4.PowerMockRunner; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Logger; - -import static org.powermock.api.mockito.PowerMockito.when; - -/** - * @author Rsl1122 - */ -public class TestInit { - - private static final UUID serverUUID = UUID.fromString("9a27457b-f1a2-4b71-be7f-daf2170a1b66"); - private Plan planMock; - - /** - * Init locale with empty messages. - *

    - * Does not load any messages from anywhere because that would cause exceptions. - */ - public static void initEmptyLocale() { - new Locale(); - } - - /** - * Init locale with mocked Plan. - *

    - * requires getDataFolder mock. - * - * @param plan Mocked Plan - */ - public static void initLocale(Plan plan) { - new Locale().loadLocale(); - } - - public static TestInit init() throws Exception { - TestInit t = new TestInit(); - t.setUp(); - return t; - } - - static File getTestFolder() { - File testFolder = new File("temporaryTestFolder"); - testFolder.mkdir(); - return testFolder; - } - - public static UUID getServerUUID() { - return serverUUID; - } - - private void setUp() throws Exception { - planMock = PowerMockito.mock(Plan.class); - - StaticHolder.register(Plan.class, planMock); - StaticHolder.register(planMock); - - // Hacks to make APF find classes - StaticHolder.register(IPlugin.class, planMock); - StaticHolder.saveInstance(this.getClass(), Plan.class); - StaticHolder.saveInstance(PowerMockRunner.class, Plan.class); - - Log.setDebugMode("console"); - - File testFolder = getTestFolder(); - when(planMock.getDataFolder()).thenReturn(testFolder); - - // Files - File config = new File(getClass().getResource("/config.yml").getPath()); - when(planMock.getResource("config.yml")).thenReturn(new FileInputStream(config)); - File analysis = new File(getClass().getResource("/web/server.html").getPath()); - when(planMock.getResource("/web/server.html")).thenReturn(new FileInputStream(analysis)); - File player = new File(getClass().getResource("/web/player.html").getPath()); - when(planMock.getResource("/web/player.html")).thenReturn(new FileInputStream(player)); - - File tempConfigFile = new File(planMock.getDataFolder(), "config.yml"); - Config iConfig = new Config(tempConfigFile, FileUtil.lines(planMock, "config.yml")) { - @Override - public void save() { - } - }; - when(planMock.getMainConfig()).thenReturn(iConfig); - - Server mockServer = mockServer(); - - when(planMock.getServer()).thenReturn(mockServer); - - // Test log settings - when(planMock.getLogger()).thenReturn(Logger.getGlobal()); - Settings.DEBUG.setValue(true); - - ServerVariableHolder serverVariableHolder = new ServerVariableHolder(mockServer); - - when(planMock.getVariable()).thenReturn(serverVariableHolder); - BukkitServerInfoManager bukkitServerInfoManager = PowerMockito.mock(BukkitServerInfoManager.class); - - DataCache dataCache = new DataCache(planMock) { - @Override - public String getName(UUID uuid) { - return ""; - } - }; - when(planMock.getDataCache()).thenReturn(dataCache); - - when(bukkitServerInfoManager.getServerUUID()).thenReturn(serverUUID); - when(planMock.getServerUuid()).thenReturn(serverUUID); - when(planMock.getServerInfoManager()).thenReturn(bukkitServerInfoManager); - ColorScheme cs = new ColorScheme(ChatColor.BLACK, ChatColor.BLACK, ChatColor.BLACK, ChatColor.BLACK); - when(planMock.getColorScheme()).thenReturn(cs); - initLocale(null); - - RunnableFactory.activateTestMode(); - } - - private Server mockServer() { - Server mockServer = PowerMockito.mock(Server.class); - - OfflinePlayer[] ops = new OfflinePlayer[]{MockUtils.mockPlayer(), MockUtils.mockPlayer2()}; - - when(mockServer.getIp()).thenReturn("0.0.0.0"); - when(mockServer.getMaxPlayers()).thenReturn(20); - when(mockServer.getName()).thenReturn("Bukkit"); - when(mockServer.getOfflinePlayers()).thenReturn(ops); - ConsoleCommandSender sender = mockServerCmdSender(); - when(mockServer.getConsoleSender()).thenReturn(sender); - return mockServer; - } - - private ConsoleCommandSender mockServerCmdSender() { - return new ConsoleCommandSender() { - @Override - public void sendMessage(String s) { - System.out.println("Log: " + s); - } - - @Override - public void sendMessage(String[] strings) { - for (String string : strings) { - sendMessage(string); - } - } - - @Override - public Server getServer() { - return null; - } - - @Override - public String getName() { - return null; - } - - @Override - public Spigot spigot() { - return null; - } - - @Override - public boolean isConversing() { - return false; - } - - @Override - public void acceptConversationInput(String s) { - - } - - @Override - public boolean beginConversation(Conversation conversation) { - return false; - } - - @Override - public void abandonConversation(Conversation conversation) { - - } - - @Override - public void abandonConversation(Conversation conversation, ConversationAbandonedEvent conversationAbandonedEvent) { - - } - - @Override - public void sendRawMessage(String s) { - - } - - @Override - public boolean isPermissionSet(String s) { - return false; - } - - @Override - public boolean isPermissionSet(Permission permission) { - return false; - } - - @Override - public boolean hasPermission(String s) { - return false; - } - - @Override - public boolean hasPermission(Permission permission) { - return false; - } - - @Override - public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b) { - return null; - } - - @Override - public PermissionAttachment addAttachment(Plugin plugin) { - return null; - } - - @Override - public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b, int i) { - return null; - } - - @Override - public PermissionAttachment addAttachment(Plugin plugin, int i) { - return null; - } - - @Override - public void removeAttachment(PermissionAttachment permissionAttachment) { - - } - - @Override - public void recalculatePermissions() { - - } - - @Override - public Set getEffectivePermissions() { - return null; - } - - @Override - public boolean isOp() { - return false; - } - - @Override - public void setOp(boolean b) { - - } - }; - } - - private YamlConfiguration mockConfig() throws IOException, InvalidConfigurationException { - File configFile = new File(getClass().getResource("/config.yml").getPath()); - YamlConfiguration configuration = new YamlConfiguration(); - configuration.load(configFile.getAbsolutePath()); - return configuration; - } - - public Plan getPlanMock() { - return planMock; - } -} diff --git a/Plan/test/main/java/test/utilities/TestUtils.java b/Plan/test/main/java/test/utilities/TestUtils.java deleted file mode 100644 index 3f5686966..000000000 --- a/Plan/test/main/java/test/utilities/TestUtils.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package test.utilities; - -import java.lang.reflect.Field; - -/** - * @author Fuzzlemann - */ -public class TestUtils { - public static String getStringFieldValue(Enum enumeration, String modifier) throws NoSuchFieldException, IllegalAccessException { - Field field = enumeration.getClass().getDeclaredField(modifier); - field.setAccessible(true); - return (String) field.get(enumeration); - } -} diff --git a/Plan/test/test/java/utils/DBTestSuite.java b/Plan/test/test/java/utils/DBTestSuite.java deleted file mode 100644 index f44d301e3..000000000 --- a/Plan/test/test/java/utils/DBTestSuite.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package test.java.utils; - -import main.java.com.djrapitops.plan.database.DatabaseTest; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -import java.io.File; -import java.io.IOException; - -/** - * @author Fuzzlemann - */ -@RunWith(Suite.class) -@Suite.SuiteClasses({DatabaseTest.class}) -public class DBTestSuite { - @BeforeClass - public static void setUp() throws IOException { - clean(); - } - - @AfterClass - public static void tearDown() throws IOException { - clean(); - } - - private static void clean() { - File testFolder = TestInit.getTestFolder(); - - if (!testFolder.exists() || !testFolder.isDirectory()) { - return; - } - - File[] files = testFolder.listFiles(); - - if (files == null) { - return; - } - - for (File f : files) { - if (!f.delete()) { - f.deleteOnExit(); - } - } - } -} diff --git a/Plan/test/test/java/utils/MockUtils.java b/Plan/test/test/java/utils/MockUtils.java deleted file mode 100644 index 26aeffe2f..000000000 --- a/Plan/test/test/java/utils/MockUtils.java +++ /dev/null @@ -1,216 +0,0 @@ -package test.java.utils; - -import com.sun.net.httpserver.*; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; - -import java.io.*; -import java.net.InetSocketAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.Charset; -import java.util.*; -import java.util.zip.GZIPInputStream; - -import static org.powermock.api.mockito.PowerMockito.when; - -/** - * @author Rsl1122 - */ -public class MockUtils { - - public static World mockWorld() { - World mockWorld = Mockito.mock(World.class); - when(mockWorld.toString()).thenReturn("World"); - return mockWorld; - } - - public static Player mockPlayer() { - Player p = PowerMockito.mock(Player.class); - when(p.getGameMode()).thenReturn(GameMode.SURVIVAL); - when(p.getUniqueId()).thenReturn(UUID.fromString("45b0dfdb-f71d-4cf3-8c21-27c9d4c651db")); - when(p.getFirstPlayed()).thenReturn(1234567L); - World mockWorld = mockWorld(); - when(p.getLocation()).thenReturn(new Location(mockWorld, 0, 0, 0)); - when(p.isOp()).thenReturn(true); - when(p.isBanned()).thenReturn(true); - when(p.isOnline()).thenReturn(true); - when(p.getName()).thenReturn("TestName"); - when(p.hasPermission("plan.inspect.other")).thenReturn(true); - return p; - } - - public static UUID getPlayerUUID() { - return UUID.fromString("45b0dfdb-f71d-4cf3-8c21-27c9d4c651db"); - } - - public static Player mockPlayer2() { - Player p = PowerMockito.mock(Player.class); - when(p.getGameMode()).thenReturn(GameMode.SPECTATOR); - when(p.getUniqueId()).thenReturn(UUID.fromString("ec94a954-1fa1-445b-b09b-9b698519af80")); - when(p.getFirstPlayed()).thenReturn(3423434L); - World mockWorld = mockWorld(); - when(p.getLocation()).thenReturn(new Location(mockWorld, 1, 0, 1)); - when(p.isOp()).thenReturn(false); - when(p.isBanned()).thenReturn(false); - when(p.isOnline()).thenReturn(false); - when(p.hasPermission("plan.inspect.other")).thenReturn(false); - when(p.getName()).thenReturn("TestName2"); - return p; - } - - public static UUID getPlayer2UUID() { - return UUID.fromString("ec94a954-1fa1-445b-b09b-9b698519af80"); - } - - public static Set getUUIDs() { - Set uuids = new HashSet<>(); - uuids.add(getPlayerUUID()); - uuids.add(getPlayer2UUID()); - return uuids; - } - - public static Player mockBrokenPlayer() { - Player p = PowerMockito.mock(Player.class); - when(p.getGameMode()).thenReturn(GameMode.SURVIVAL); - when(p.getUniqueId()).thenReturn(UUID.fromString("45b0dfdb-f71d-4cf3-8c21-27c9d4c651db")); - when(p.getFirstPlayed()).thenReturn(1234567L); - World mockWorld = mockWorld(); - when(p.getLocation()).thenReturn(new Location(mockWorld, 0, 0, 0)); - when(p.isOp()).thenReturn(true); - when(p.isBanned()).thenThrow(Exception.class); - when(p.isOnline()).thenReturn(true); - when(p.getName()).thenReturn("TestName"); - return p; - } - - public static CommandSender mockConsoleSender() { - return PowerMockito.mock(CommandSender.class); - } - - public static HttpServer mockHTTPServer() { - HttpServer httpServer = PowerMockito.mock(HttpServer.class); - when(httpServer.getAddress()).thenReturn(new InetSocketAddress(80)); - when(httpServer.getExecutor()).thenReturn(command -> System.out.println("HTTP Server command received")); - return httpServer; - } - - public static HttpExchange getHttpExchange(String requestMethod, String requestURI, String body, Map> responseHeaders) { - return new HttpExchange() { - private ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - - @Override - public Headers getRequestHeaders() { - Headers headers = new Headers(); - headers.put("Authorization", new ArrayList<>()); - return headers; - } - - @Override - public Headers getResponseHeaders() { - Headers headers = new Headers(); - headers.putAll(responseHeaders); - return headers; - } - - @Override - public URI getRequestURI() { - try { - return new URI(requestURI); - } catch (URISyntaxException e) { - return null; - } - } - - @Override - public String getRequestMethod() { - return requestMethod; - } - - @Override - public HttpContext getHttpContext() { - return null; - } - - @Override - public void close() { - - } - - @Override - public InputStream getRequestBody() { - return new ByteArrayInputStream(body.getBytes(Charset.forName("UTF-8"))); - } - - @Override - public OutputStream getResponseBody() { - return outputStream; - } - - @Override - public InetSocketAddress getRemoteAddress() { - return null; - } - - @Override - public InetSocketAddress getLocalAddress() { - return null; - } - - @Override - public String getProtocol() { - return null; - } - - @Override - public Object getAttribute(String name) { - return null; - } - - @Override - public void sendResponseHeaders(int i, long l) throws IOException { - - } - - @Override - public int getResponseCode() { - return 0; - } - - @Override - public void setAttribute(String s, Object o) { - - } - - @Override - public void setStreams(InputStream inputStream, OutputStream outputStream) { - - } - - @Override - public HttpPrincipal getPrincipal() { - return null; - } - }; - } - - public static String getResponseStream(HttpExchange requestExchange) throws IOException { - InputStream in = new GZIPInputStream( - new ByteArrayInputStream(( - (ByteArrayOutputStream) requestExchange.getResponseBody() - ).toByteArray()) - ); - try (Scanner scanner = new Scanner(in)) { - StringBuilder s = new StringBuilder(); - while (scanner.hasNextLine()) { - s.append(scanner.nextLine()).append("\n"); - } - return s.toString(); - } - } -} diff --git a/Plan/test/test/java/utils/RandomData.java b/Plan/test/test/java/utils/RandomData.java deleted file mode 100644 index 37292fb98..000000000 --- a/Plan/test/test/java/utils/RandomData.java +++ /dev/null @@ -1,77 +0,0 @@ -package test.java.utils; - -import main.java.com.djrapitops.plan.data.WebUser; -import main.java.com.djrapitops.plan.data.container.Session; -import main.java.com.djrapitops.plan.data.container.TPS; -import main.java.com.djrapitops.plan.data.container.UserInfo; -import main.java.com.djrapitops.plan.utilities.PassEncryptUtil; -import main.java.com.djrapitops.plan.utilities.analysis.Point; -import org.apache.commons.lang3.RandomStringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.UUID; -import java.util.concurrent.ThreadLocalRandom; - -public class RandomData { - - private static final Random r = new Random(); - - public static int randomInt(int rangeStart, int rangeEnd) { - return ThreadLocalRandom.current().nextInt(rangeStart, rangeEnd); - } - - public static String randomString(int size) { - return RandomStringUtils.randomAlphanumeric(size); - } - - public static List randomWebUsers() throws PassEncryptUtil.CannotPerformOperationException { - List test = new ArrayList<>(); - for (int i = 0; i < 20; i++) { - test.add(new WebUser(randomString(5), PassEncryptUtil.createHash(randomString(7)), r.nextInt())); - } - return test; - } - - public static List randomTPS() { - List test = new ArrayList<>(); - for (int i = 0; i < 20; i++) { - int randInt = r.nextInt(); - long randLong = r.nextLong(); - test.add(new TPS(randLong, randLong, randInt, randLong, randLong, randInt, randInt)); - } - return test; - } - - public static List randomSessions() { - List test = new ArrayList<>(); - for (int i = 0; i < 20; i++) { - test.add(new Session(1, r.nextLong(), r.nextLong(), 0, 0)); - } - return test; - } - - public static List randomPoints() { - List test = new ArrayList<>(); - for (int i = 0; i < 20; i++) { - test.add(new Point(r.nextLong(), r.nextLong())); - } - return test; - } - - public static T randomEnum(Class clazz) { - int x = r.nextInt(clazz.getEnumConstants().length); - return clazz.getEnumConstants()[x]; - } - - public static List randomUserData() { - List test = new ArrayList<>(); - for (int i = 0; i < 20; i++) { - UserInfo info = new UserInfo(UUID.randomUUID(), randomString(10), r.nextLong(), r.nextBoolean(), r.nextBoolean()); - info.setLastSeen(r.nextLong()); - test.add(info); - } - return test; - } -} diff --git a/Plan/test/test/java/utils/TestInit.java b/Plan/test/test/java/utils/TestInit.java deleted file mode 100644 index 9b8500611..000000000 --- a/Plan/test/test/java/utils/TestInit.java +++ /dev/null @@ -1,297 +0,0 @@ -package test.java.utils; - -import com.djrapitops.plugin.IPlugin; -import com.djrapitops.plugin.StaticHolder; -import com.djrapitops.plugin.api.config.Config; -import com.djrapitops.plugin.api.utility.log.Log; -import com.djrapitops.plugin.settings.ColorScheme; -import com.djrapitops.plugin.task.RunnableFactory; -import main.java.com.djrapitops.plan.Plan; -import main.java.com.djrapitops.plan.ServerVariableHolder; -import main.java.com.djrapitops.plan.settings.Settings; -import main.java.com.djrapitops.plan.settings.locale.Locale; -import main.java.com.djrapitops.plan.systems.cache.DataCache; -import main.java.com.djrapitops.plan.systems.info.server.BukkitServerInfoManager; -import main.java.com.djrapitops.plan.utilities.file.FileUtil; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; -import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.conversations.Conversation; -import org.bukkit.conversations.ConversationAbandonedEvent; -import org.bukkit.permissions.Permission; -import org.bukkit.permissions.PermissionAttachment; -import org.bukkit.permissions.PermissionAttachmentInfo; -import org.bukkit.plugin.Plugin; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.modules.junit4.PowerMockRunner; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Logger; - -import static org.powermock.api.mockito.PowerMockito.when; - -/** - * @author Rsl1122 - */ -public class TestInit { - - private static final UUID serverUUID = UUID.fromString("9a27457b-f1a2-4b71-be7f-daf2170a1b66"); - private Plan planMock; - - /** - * Init locale with empty messages. - *

    - * Does not load any messages from anywhere because that would cause exceptions. - */ - public static void initEmptyLocale() { - new Locale(); - } - - /** - * Init locale with mocked Plan. - *

    - * requires getDataFolder mock. - * - * @param plan Mocked Plan - */ - public static void initLocale(Plan plan) { - new Locale().loadLocale(); - } - - public static TestInit init() throws Exception { - TestInit t = new TestInit(); - t.setUp(); - return t; - } - - static File getTestFolder() { - File testFolder = new File("temporaryTestFolder"); - testFolder.mkdir(); - return testFolder; - } - - public static UUID getServerUUID() { - return serverUUID; - } - - private void setUp() throws Exception { - planMock = PowerMockito.mock(Plan.class); - - StaticHolder.register(Plan.class, planMock); - StaticHolder.register(planMock); - - // Hacks to make APF find classes - StaticHolder.register(IPlugin.class, planMock); - StaticHolder.saveInstance(this.getClass(), Plan.class); - StaticHolder.saveInstance(PowerMockRunner.class, Plan.class); - - Log.setDebugMode("console"); - - File testFolder = getTestFolder(); - when(planMock.getDataFolder()).thenReturn(testFolder); - - // Files - File config = new File(getClass().getResource("/config.yml").getPath()); - when(planMock.getResource("config.yml")).thenReturn(new FileInputStream(config)); - File analysis = new File(getClass().getResource("/web/server.html").getPath()); - when(planMock.getResource("/web/server.html")).thenReturn(new FileInputStream(analysis)); - File player = new File(getClass().getResource("/web/player.html").getPath()); - when(planMock.getResource("/web/player.html")).thenReturn(new FileInputStream(player)); - - File tempConfigFile = new File(planMock.getDataFolder(), "config.yml"); - Config iConfig = new Config(tempConfigFile, FileUtil.lines(planMock, "config.yml")) { - @Override - public void save() throws IOException { - } - }; - when(planMock.getMainConfig()).thenReturn(iConfig); - - Server mockServer = mockServer(); - - when(planMock.getServer()).thenReturn(mockServer); - - // Test log settings - when(planMock.getLogger()).thenReturn(Logger.getGlobal()); - Settings.DEBUG.setValue(true); - - ServerVariableHolder serverVariableHolder = new ServerVariableHolder(mockServer); - - when(planMock.getVariable()).thenReturn(serverVariableHolder); - BukkitServerInfoManager bukkitServerInfoManager = PowerMockito.mock(BukkitServerInfoManager.class); - - DataCache dataCache = new DataCache(planMock) { - @Override - public String getName(UUID uuid) { - return ""; - } - }; - when(planMock.getDataCache()).thenReturn(dataCache); - - when(bukkitServerInfoManager.getServerUUID()).thenReturn(serverUUID); - when(planMock.getServerUuid()).thenReturn(serverUUID); - when(planMock.getServerInfoManager()).thenReturn(bukkitServerInfoManager); - ColorScheme cs = new ColorScheme(ChatColor.BLACK, ChatColor.BLACK, ChatColor.BLACK, ChatColor.BLACK); - when(planMock.getColorScheme()).thenReturn(cs); - initLocale(null); - - RunnableFactory.activateTestMode(); - } - - private Server mockServer() { - Server mockServer = PowerMockito.mock(Server.class); - - OfflinePlayer[] ops = new OfflinePlayer[]{MockUtils.mockPlayer(), MockUtils.mockPlayer2()}; - - when(mockServer.getIp()).thenReturn("0.0.0.0"); - when(mockServer.getMaxPlayers()).thenReturn(20); - when(mockServer.getName()).thenReturn("Bukkit"); - when(mockServer.getOfflinePlayers()).thenReturn(ops); - ConsoleCommandSender sender = mockServerCmdSender(); - when(mockServer.getConsoleSender()).thenReturn(sender); - return mockServer; - } - - private ConsoleCommandSender mockServerCmdSender() { - return new ConsoleCommandSender() { - @Override - public void sendMessage(String s) { - System.out.println("Log: " + s); - } - - @Override - public void sendMessage(String[] strings) { - for (String string : strings) { - sendMessage(string); - } - } - - @Override - public Server getServer() { - return null; - } - - @Override - public String getName() { - return null; - } - - @Override - public Spigot spigot() { - return null; - } - - @Override - public boolean isConversing() { - return false; - } - - @Override - public void acceptConversationInput(String s) { - - } - - @Override - public boolean beginConversation(Conversation conversation) { - return false; - } - - @Override - public void abandonConversation(Conversation conversation) { - - } - - @Override - public void abandonConversation(Conversation conversation, ConversationAbandonedEvent conversationAbandonedEvent) { - - } - - @Override - public void sendRawMessage(String s) { - - } - - @Override - public boolean isPermissionSet(String s) { - return false; - } - - @Override - public boolean isPermissionSet(Permission permission) { - return false; - } - - @Override - public boolean hasPermission(String s) { - return false; - } - - @Override - public boolean hasPermission(Permission permission) { - return false; - } - - @Override - public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b) { - return null; - } - - @Override - public PermissionAttachment addAttachment(Plugin plugin) { - return null; - } - - @Override - public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b, int i) { - return null; - } - - @Override - public PermissionAttachment addAttachment(Plugin plugin, int i) { - return null; - } - - @Override - public void removeAttachment(PermissionAttachment permissionAttachment) { - - } - - @Override - public void recalculatePermissions() { - - } - - @Override - public Set getEffectivePermissions() { - return null; - } - - @Override - public boolean isOp() { - return false; - } - - @Override - public void setOp(boolean b) { - - } - }; - } - - private YamlConfiguration mockConfig() throws IOException, InvalidConfigurationException { - File configFile = new File(getClass().getResource("/config.yml").getPath()); - YamlConfiguration configuration = new YamlConfiguration(); - configuration.load(configFile.getAbsolutePath()); - return configuration; - } - - public Plan getPlanMock() { - return planMock; - } -} diff --git a/Plan/test/test/java/utils/TestUtils.java b/Plan/test/test/java/utils/TestUtils.java deleted file mode 100644 index 09e3be2bf..000000000 --- a/Plan/test/test/java/utils/TestUtils.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Licence is provided in the jar as license.yml also here: - * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml - */ -package test.java.utils; - -import java.lang.reflect.Field; - -/** - * @author Fuzzlemann - */ -public class TestUtils { - public static String getStringFieldValue(Enum enumeration, String modifier) throws NoSuchFieldException, IllegalAccessException { - Field field = enumeration.getClass().getDeclaredField(modifier); - field.setAccessible(true); - return (String) field.get(enumeration); - } -} diff --git a/PlanPluginBridge/PlanPluginBridge-4.1.3.2.jar b/PlanPluginBridge/PlanPluginBridge-4.1.3.2.jar deleted file mode 100644 index 4568649bb..000000000 Binary files a/PlanPluginBridge/PlanPluginBridge-4.1.3.2.jar and /dev/null differ diff --git a/PlanPluginBridge/PlanPluginBridge-4.1.3.jar b/PlanPluginBridge/PlanPluginBridge-4.1.3.jar deleted file mode 100644 index 91e61cf5f..000000000 Binary files a/PlanPluginBridge/PlanPluginBridge-4.1.3.jar and /dev/null differ diff --git a/PlanPluginBridge/PlanPluginBridge-4.2.0.jar b/PlanPluginBridge/PlanPluginBridge-4.2.0.jar new file mode 100644 index 000000000..1a27f6d98 Binary files /dev/null and b/PlanPluginBridge/PlanPluginBridge-4.2.0.jar differ diff --git a/PlanPluginBridge/pom.xml b/PlanPluginBridge/pom.xml index 16dce44b8..d1ffb0542 100644 --- a/PlanPluginBridge/pom.xml +++ b/PlanPluginBridge/pom.xml @@ -57,6 +57,10 @@ jitpack.io https://jitpack.io + + redprotect-repo + https://raw.github.com/FabioZumbi12/RedProtect/mvn-repo/ + viaversion-repo https://repo.viaversion.com @@ -145,6 +149,13 @@ 16.7.1 provided + + + net.kaikk.mc + GriefPreventionPlus + RELEASE + provided + litebans api @@ -189,8 +200,8 @@ br.net.fabiozumbi12.RedProtect - RedProtect - 7.3.0 + RedProtect-Spigot + RELEASE provided @@ -208,7 +219,7 @@ maven-install-plugin 2.5.2 - +