Reworked PluginData API completely (Does not compile)

This commit is contained in:
Rsl1122 2017-11-26 11:07:08 +02:00
parent cc6fbce791
commit 8065d21ee1
12 changed files with 270 additions and 461 deletions

View File

@ -3,7 +3,6 @@ package main.java.com.djrapitops.plan.api;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.AnalysisData;
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.systems.info.BukkitInformationManager;
import main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility;

View File

@ -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 main.java.com.djrapitops.plan.data.additional;
import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
/**
* Container used to parse data for Analysis page.
* <p>
* Similar to InspectContainer, but can contain data for each player for a bigger Player data table.
* <p>
* Can contain values: addValue("Total Examples", 1) parses into ("Total Examples: 1")
* Html: addHtml(key, "{@code <html>}") parses into ("{@code <html>}")
* Tables: addTable(key, TableContainer) parses into ("{@code <table>...</table}")
* Player Data for a big table: {@code addTableData("header", Map<UUID, value>)} parses a new column to Plugin data player table.
* <p>
* Has methods for adding icons to Strings:
* getWithIcon("text", "cube") parses into {@code "<i class=\"fa fa-cube\"></i> text"}
* getWithColoredIcon("text", "cube", "light-green") parses into {@code "<i class=\"col-light-green fa fa-cube\"></i> text"}
*
* @author Rsl1122
* @see TableContainer
* @see InspectContainer
* @since 4.1.0
*/
public class AnalysisContainer extends InspectContainer {
private TreeMap<String, Map<UUID, Serializable>> playerTableValues;
public AnalysisContainer() {
playerTableValues = new TreeMap<>();
}
public TreeMap<String, Map<UUID, Serializable>> getPlayerTableValues() {
return playerTableValues;
}
}

View File

@ -1,142 +0,0 @@
package main.java.com.djrapitops.plan.data.additional;
/**
* This class contains Enum values for different types of Analysis that can be
* performed on values of PluginData.
* <p>
* The enum determines what should be done to the return value of
* PluginData.getValue() method when the analysis is run.
* <p>
* Refer to the documentation on GitHub for additional information.
*
* @author Rsl1122
* @since 3.1.0
*/
public enum AnalysisType {
/**
* Used when the getValue() method returns an integer and average should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
INT_AVG("_avgInt", "Average "),
/**
* Used when the getValue() method returns a long and average should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_AVG("_avgLong", "Average "),
/**
* Used when the getValue() method returns double and average should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
DOUBLE_AVG("_avgDouble", "Average "),
/**
* Used when the getValue() method returns an integer and total should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
INT_TOTAL("_totalInt", "Total "),
/**
* Used when the getValue() method returns a long and total should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_TOTAL("_totalLong", "Total "),
/**
* Used when the getValue() method returns a double and total should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
DOUBLE_TOTAL("_totalDouble", "Total "),
/**
* Used when the getValue() method returns an amount of milliseconds as long
* and average should be calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_TIME_MS_AVG("_avgTimeMs", "Average "),
/**
* Used when the getValue() method returns an amount of milliseconds as long
* and total should be calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_TIME_MS_TOTAL("_totalTimeMs"),
/**
* Used when the getValue() method returns an Epoch Millisecond as long and
* average of differences between the millisecond and current millisecond
* should be calculated.
* <p>
* For example if a player has dropped a Foo on epoch ms 1494486504000 and
* that was 5s (5000ms) ago. Now you want to calculate the average
* time-since for all players. Then you use this one.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_EPOCH_MS_MINUS_NOW_AVG("_avgEpochMsMinusNow", "Average "),
/**
* Used to calculate %-true for the returned boolean values of getValue().
*/
BOOLEAN_PERCENTAGE("_perchBool", "Percentage "),
/**
* Used to calculate number of true values for the returned boolean values
* of getValue().
* <p>
* Will be presented as "n / total".
*/
BOOLEAN_TOTAL("_totalBool"),
/**
* Used to add html tags to the plugins tab.
* <p>
* Can be used to add Tables, Images (for example maps) and other html
* elements.
*/
HTML;
private final String modifier;
private final String placeholderModifier;
AnalysisType(String placeholderModifier, String modifier) {
this.placeholderModifier = placeholderModifier;
this.modifier = modifier;
}
AnalysisType(String placeholderModifier) {
this.placeholderModifier = placeholderModifier;
this.modifier = "";
}
AnalysisType() {
this.placeholderModifier = "";
this.modifier = "";
}
/**
* Used to get the modifier for the Prefix of the value.
* <p>
* For example: "Average Votes" when INT_AVG is used and Prefix is set as
* "Votes".
*
* @return Modifier, can be empty.
*/
public String getModifier() {
return modifier;
}
/**
* Used to get the Placeholder modifier.
*
* @return for example "_total"
*/
public String getPlaceholderModifier() {
return placeholderModifier;
}
}

View File

@ -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 main.java.com.djrapitops.plan.data.additional;
import java.util.Collection;
import java.util.UUID;
/**
* Interface for PluginData objects that affect Ban state of players.
*
* @author Rsl1122
*/
public interface BanData {
boolean isBanned(UUID uuid);
/**
* Method that should return only banned players of the given UUIDs.
*
* @param uuids UUIDs to filter.
* @return UUIDs from the collection uuids that are banned.
*/
Collection<UUID> filterBanned(Collection<UUID> uuids);
}

View File

@ -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 main.java.com.djrapitops.plan.data.additional;
/**
* Enum class for PluginData to estimate the required width of the contained items.
*
* @author Rsl1122
*/
public enum ContainerSize {
THIRD,
TWO_THIRDS,
WHOLE,
TAB
}

View File

@ -0,0 +1,77 @@
/*
* 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 main.java.com.djrapitops.plan.data.additional;
import main.java.com.djrapitops.plan.utilities.html.Html;
import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap;
/**
* Container used to parse data for Inspect page.
* <p>
* Can contain values: addValue("Total Examples", 1) parses into ("Total Examples: 1")
* Html: addHtml(key, "{@code <html>}") parses into ("{@code <html>}")
* Tables: addTable(key, TableContainer) parses into ("{@code <table>...</table}")
* <p>
* Has methods for adding icons to Strings:
* getWithIcon("text", "cube") parses into {@code "<i class=\"fa fa-cube\"></i> text"}
* getWithColoredIcon("text", "cube", "light-green") parses into {@code "<i class=\"col-light-green fa fa-cube\"></i> text"}
*
* @author Rsl1122
* @see TableContainer
* @since 4.1.0
*/
public class InspectContainer {
protected TreeMap<String, String> values;
protected TreeMap<String, String> html;
protected TreeMap<String, TableContainer> tables;
public InspectContainer() {
values = new TreeMap<>();
html = new TreeMap<>();
tables = new TreeMap<>();
}
public String getWithIcon(String text, String icon) {
return getWithColoredIcon(text, icon, "black");
}
public String getWithColoredIcon(String text, String icon, String color) {
return Html.FA_COLORED_ICON.parse(color, icon) + " " + text;
}
public void addValue(String label, Serializable value) {
values.put(label, value.toString());
}
public void addHtml(String key, String html) {
this.html.put(key, html);
}
public void addTable(String key, TableContainer table) {
tables.put(key, table);
}
public String parseHtml() {
StringBuilder html = new StringBuilder();
for (Map.Entry<String, String> entry : values.entrySet()) {
html.append("<p>").append(entry.getKey()).append(": ").append(entry.getValue()).append("</p>");
}
for (Map.Entry<String, String> entry : this.html.entrySet()) {
html.append(entry.getValue());
}
for (Map.Entry<String, TableContainer> entry : tables.entrySet()) {
html.append(entry.getValue().parseHtml());
}
return html.toString();
}
}

View File

@ -1,354 +1,65 @@
package main.java.com.djrapitops.plan.data.additional;
import main.java.com.djrapitops.plan.Plan;
import com.google.common.base.Objects;
import main.java.com.djrapitops.plan.utilities.html.Html;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.io.Serializable;
import java.util.*;
import java.util.Collection;
import java.util.UUID;
/**
* This is an abstract class that can be used to add data from a plugin to the
* "Plugins"-tab of Analysis and Inspect pages.
* "Plugins"-sections of Analysis and Inspect pages.
* <p>
* API-section of documentation has examples on the usage of this class and how
* to register objects extending this class.
*
* @author Rsl1122
* @since 3.1.0
* @since 4.1.0
*/
public abstract class PluginData {
/**
* A list containing the AnalysisType enums that determine what should be
* done with the data on the analysis page.
*/
protected final List<AnalysisType> analysisTypes;
/**
* Placeholder string, for example "stepsTaken". This will be used when
* building the structure of the Plugins tab.
* <p>
* The complete placeholder also includes the plugin name and if analysis is
* run, a modifier.
* <p>
* Second parameter of any super constructor.
*/
protected final String placeholder;
/**
* Name of the plugin the data is coming from.
* <p>
* All sources of data with the same sourcePlugin will be placed in the same
* "box" in the "Plugins" tab.
* <p>
* A box has a max height of 600px, and higher than that will add a
* scrollbar.
* <p>
* First parameter of any super constructor.
*/
protected final String sourcePlugin;
/**
* Determines if the datapoint should only be used for the analysis page.
* <p>
* If set to false, the datapoint will be added to the inspect page as well.
*/
protected boolean analysisOnly;
/**
* Font Awesome icon name.
* <p>
* http://fontawesome.io/icons/
*/
protected String icon;
/**
* Prefix shown before the data, for example "Steps taken: ".
*/
protected String prefix;
/**
* Suffix shown after the data, for example " steps".
*/
protected String suffix;
private final ContainerSize size;
private final String sourcePlugin;
/**
* Main constructor.
* <p>
* Defaults analysisOnly to true.
* <p>
* Defaults icon, prefix and suffix to "".
*
* @param sourcePlugin Name of the plugin the data is coming from
* @param placeholder Placeholder string, for example "stepsTaken"
* @param analysisTypes A list containing the AnalysisType enums that
* determine what should be done with the data on the analysis page
*/
public PluginData(String sourcePlugin, String placeholder, List<AnalysisType> analysisTypes) {
this.placeholder = placeholder;
private String pluginIcon;
public PluginData(ContainerSize size, String sourcePlugin) {
this.size = size;
this.sourcePlugin = sourcePlugin;
analysisOnly = true;
this.analysisTypes = analysisTypes;
this.icon = "";
this.prefix = "";
this.suffix = "";
}
/**
* Constructor for accepting single, multiple and arrays of AnalysisType.
*
* @param sourcePlugin Name of the plugin the data is coming from
* @param placeholder Placeholder string, for example "stepsTaken"
* @param analysisTypes AnalysisType enums that determine what should be
* done with the data on the analysis page
*/
public PluginData(String sourcePlugin, String placeholder, AnalysisType... analysisTypes) {
this(sourcePlugin, placeholder, Arrays.asList(analysisTypes));
public abstract InspectContainer getPlayerData(UUID uuid, InspectContainer fillThis) throws Exception;
public abstract AnalysisContainer getServerData(Collection<UUID> uuids, AnalysisContainer fillThis) throws Exception;
protected void setPluginIcon(String pluginIcon) {
this.pluginIcon = pluginIcon;
}
/**
* Constructor for Inspect-page only data point.
* <p>
* analysisOnly will be set to false.
*
* @param sourcePlugin Name of the plugin the data is coming from
* @param placeholder Placeholder string, for example "stepsTaken"
*/
public PluginData(String sourcePlugin, String placeholder) {
this(sourcePlugin, placeholder, new ArrayList<>());
analysisOnly = false;
public String parsePluginIcon() {
return pluginIcon != null ? Html.FONT_AWESOME_ICON.parse(pluginIcon) : Html.FONT_AWESOME_ICON.parse("cube");
}
/**
* Returns the list of AnalysisTypes.
* <p>
* Used by Analysis
*
* @return a list.
*/
public final List<AnalysisType> getAnalysisTypes() {
return analysisTypes;
public ContainerSize getSize() {
return size;
}
/**
* This method should be used with the return values of
* getHtmlReplaceValue(String, UUID).
* <p>
* It will add the div, icon, modifier, prefix and suffix to the value.
* Modifier is for example, if calculating AnalysisType.INT_AVG "Average ",
* it is a text that helps user understand that a calculation has been made.
*
* @param modifier For example "Average " - Determined by value of
* AnalysisType's modifier-variable.
* @param contents The data, number/string/html that should be placed on the
* page.
* @return a proper format for the html.
* @see AnalysisType
*/
public final String parseContainer(String modifier, String contents) {
boolean html = analysisTypes.contains(AnalysisType.HTML);
return "<div class=\"plugin-data\">" + (html ? "" : "<p>") + (icon.isEmpty() ? "" : Html.FONT_AWESOME_ICON.parse(icon)) + " " + modifier + prefix + contents + suffix + (html ? "" : "</p>") + "</div>";
}
/**
* Used to get the full placeholder.
* <p>
* Used to avoid conflicts with existing placeholders and placeholders of
* other plugins.
*
* @param modifier Modifier determined by AnalysisType's
* placeholderModifier-variable.
* @return for example "${StepCounter_stepsTaken_total}"
* @see AnalysisType
*/
public final String getPlaceholder(String modifier) {
return "${" + getPlaceholderName(modifier) + "}";
}
/**
* Used to get the placeholder without the modifier.
*
* @return for example "${StepCounter_stepsTaken}"
* @see #getPlaceholder(String)
*/
public final String getPlaceholder() {
return "${" + getPlaceholderName() + "}";
}
/**
* Used to get the placeholder name with modifier.
*
* @return for example "StepCounter_stepsTaken_modifier"
* @see #getPlaceholder(String)
*/
public final String getPlaceholderName(String modifier) {
return getPlaceholderName() + modifier;
}
/**
* Used to get the placeholder name.
*
* @return for example "StepCounter_stepsTaken"
* @see #getPlaceholder(String)
*/
public final String getPlaceholderName() {
return sourcePlugin + "_" + placeholder;
}
/**
* Used to get the source plugin's name.
*
* @return for example "StepCounter"
*/
public final String getSourcePlugin() {
public String getSourcePlugin() {
return sourcePlugin;
}
/**
* Used to get the string for the html page.
* <p>
* parseContainer(modifierPrefix, value); should be used for all return
* values so that div, icon, prefix and suffix are added.
* <p>
* This method is used when AnalysisType.HTML is set, or while getting the
* value for the inspect page.
* <p>
* When using AnalysisType.HTML a random UUID is given, so it should be
* disregarded. modifierPrefix is empty in that case.
*
* @param modifierPrefix Modifier determined by AnalysisType's
* modifier-variable.
* @param uuid UUID of the player or random UUID if AnalysisType.HTML is
* used.
* @return html for the page.
*/
public abstract String getHtmlReplaceValue(String modifierPrefix, UUID uuid);
/**
* Used to get the value for analysis. The return value is determined by
* AnalysisType you have specified. If the AnalysisType's name has a BOOLEAN
* in it, Analysis will expect boolean values etc.
* <p>
* If the Type and return value mismatch, exception is thrown and the result
* on the analysis page will say that error occurred as the value.
* <p>
* If a player has no value a -1 should be returned in the case of a Number.
* -1 is excluded from the Average calculation's size and total.
*
* @param uuid UUID of the player the value belongs to.
* @return Long, Integer, Double, Boolean or String, return -1 if the player
* has no value.
* @throws UnsupportedOperationException if implementing class has not overridden the method.
*/
public abstract Serializable getValue(UUID uuid);
public Map<UUID, Serializable> getValues(Collection<UUID> uuids) {
throw new UnsupportedOperationException("Not overridden.");
}
/**
* Used to set the Font Awesome icon.
*
* @param iconName Icon's name http://fontawesome.io/icons/
*/
public final void setIcon(String iconName) {
this.icon = iconName + " ";
}
/**
* Used to set the analysisOnly parameter.
* <p>
* true: only used for Analysis page false: used for both if AnalysisTypes
* specified, if no AnalysisTypes are specified only used for Inspect page.
*
* @param analysisOnly true/false
*/
public final void setAnalysisOnly(boolean analysisOnly) {
this.analysisOnly = analysisOnly;
}
/**
* Used to get the analysisOnly parameter.
*
* @return true/false
*/
public final boolean analysisOnly() {
return analysisOnly;
}
/**
* Used to get the prefix.
*
* @return example: "Steps Taken "
*/
public final String getPrefix() {
return prefix;
}
/**
* Used to set the prefix.
*
* @param prefix for example "Steps Taken: " or a Html start tag.
*/
public final void setPrefix(String prefix) {
this.prefix = prefix;
}
/**
* Used to get the suffix.
*
* @return example: " steps"
*/
public final String getSuffix() {
return suffix;
}
/**
* Used to set the suffix.
*
* @param suffix for example " steps" or a html end tag.
*/
public final void setSuffix(String suffix) {
this.suffix = suffix;
}
public final boolean isBanData() {
return placeholder.contains("banned")
&& analysisTypes.contains(AnalysisType.BOOLEAN_TOTAL);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PluginData that = (PluginData) o;
return analysisOnly == that.analysisOnly &&
Objects.equals(analysisTypes, that.analysisTypes) &&
Objects.equals(placeholder, that.placeholder) &&
Objects.equals(sourcePlugin, that.sourcePlugin) &&
Objects.equals(icon, that.icon) &&
Objects.equals(prefix, that.prefix) &&
Objects.equals(suffix, that.suffix);
return size == that.size &&
Objects.equal(sourcePlugin, that.sourcePlugin) &&
Objects.equal(pluginIcon, that.pluginIcon);
}
@Override
public int hashCode() {
return Objects.hash(analysisTypes, placeholder, sourcePlugin, analysisOnly, icon, prefix, suffix);
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("analysisTypes", analysisTypes)
.append("placeholder", placeholder)
.append("sourcePlugin", sourcePlugin)
.append("analysisOnly", analysisOnly)
.append("icon", icon)
.append("prefix", prefix)
.append("suffix", suffix)
.toString();
}
protected Set<UUID> getUUIDsBeingAnalyzed() {
return Plan.getInstance().getDataCache().getUuids();
}
protected String getNameOf(UUID uuid) {
return Plan.getInstance().getDataCache().getName(uuid);
return Objects.hashCode(size, sourcePlugin, pluginIcon);
}
}

View File

@ -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 main.java.com.djrapitops.plan.data.additional;
import main.java.com.djrapitops.plan.utilities.html.Html;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Container used for parsing Html tables.
*
* @author Rsl1122
*/
public class TableContainer {
private final String[] header;
private List<Serializable[]> values;
/**
* Constructor, call with super(...).
*
* @param header Required: example {@code new TableContainer("1st", "2nd"} parses into {@code <thead><tr><th>1st</th><th>2nd</th></tr></thead}.
*/
public TableContainer(String... header) {
this.header = header;
values = new ArrayList<>();
}
protected void addRow(Serializable... values) {
this.values.add(values);
}
public String parseHtml() {
StringBuilder table = new StringBuilder(Html.TABLE.parse());
table.append(parseHeader());
table.append(parseBody());
return table.append("</table>").toString();
}
private String parseBody() {
StringBuilder body = new StringBuilder();
if (values.isEmpty()) {
addRow("No Data");
}
for (Serializable[] row : values) {
int maxIndex = row.length - 1;
body.append("<tr>");
for (int i = 0; i < header.length; i++) {
body.append("<td>");
if (i > maxIndex) {
body.append("-");
} else {
body.append(row[i]);
}
body.append("</td>");
}
body.append("</tr>");
}
return Html.TABLE_BODY.parse(body.toString());
}
public String parseHeader() {
StringBuilder header = new StringBuilder("<tr>");
for (String title : this.header) {
header.append("<th>").append(title).append("</th>");
}
header.append("</tr>");
return Html.TABLE_HEAD.parse(header.toString());
}
}

View File

@ -10,7 +10,6 @@ import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.AnalysisData;
import main.java.com.djrapitops.plan.data.ServerProfile;
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.database.Database;

View File

@ -4,7 +4,6 @@ import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.api.utility.log.Log;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.data.time.GMTimes;
import main.java.com.djrapitops.plan.data.time.WorldTimes;

View File

@ -53,6 +53,9 @@ public enum Html {
ROW("<div class=\"row\">${0}</div>"),
//
TABLE_END("</tbody></table>"),
TABLE("<table class=\"table table-striped\">"),
TABLE_HEAD("<thead>${0}</thead>"),
TABLE_BODY("<tbody>${0}</tbody>"),
TABLE_START_2("<table class=\"table table-striped\"><thead><tr><th>${0}</th><th>${1}</th></tr></thead><tbody>"),
TABLE_START_3("<table class=\"table table-striped\"><thead><tr><th>${0}</th><th>${1}</th><th>${2}</th></tr></thead><tbody>"),
TABLE_START_4("<table class=\"table table-striped\"><thead><tr><th>${0}</th><th>${1}</th><th>${2}</th><th>${3}</th></tr></thead><tbody>"),

View File

@ -10,7 +10,6 @@ import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.ServerVariableHolder;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.systems.info.BukkitInformationManager;