mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-27 03:27:37 +01:00
* Plan api module * Information annotations for DataExtension API * Added BooleanProvider annotation * Added NumberProvider * Added DoubleProvider * Added PercentageProvider * Added StringProvider * Retention and Target to Providers * Validation class for annotations * Refactored ExtensionExtractor, Added Group parameter * Method names used as provider identifiers * Begun work on extracting data providers * Provider Extraction + priority to Providers: Implemented methods for extracting each kind of Provider annotation related method information to a DataProvider. DataProviders required some duplicate code due to type erasure of the parameter class. ---- Added Display-priority to Providers, highest value is placed top most. InvalidateMethod annotations are now extracted. * Small amount of code cleanup * Storage of plugin info, icon and tabs of DataExtension * Simplified Provider method calling: - Added an enum for each method kind - Moved parameter resolution to the end of the chain, right before invoking the method. - The enum is used for storage in DataProviders for easier access. - ProviderInformation created as early as possible * Player data gathering for all providers: - Incremental condition resolution of BooleanProvider conditions - Gathering of Number and String values - Gathering and disambiguation between double and percentage providers. * Storage of Provider icons * String provider extra info * plan_extension_providers table information * plan_extension_user_values table information * BooleanProvider store transaction * NumberProvider store transaction * StringProvider store transaction * DoubleProvider, PercentageProvider store transaction * Boolean result store transaction * Double result store transaction * Number result store transaction * Percentage result store transaction * String result store transaction * Transaction for removing invalid providers from storage * Interface for registering DataExtensions * ExtensionService implementation * Handling of by default empty annotation values * Extension table create table statements * Annotation String length enforcement: - Description is 150 characters max, truncated - Others are 50 characters max, truncated - StringProvider value is 50 characters max, truncated * Logging of implementation mistake warnings * Added 'extensions' module: - Module is in charge of registering built in DataExtensions - This is done via ExtensionRegister * Config enable check for DataExtension registration * Fixed Extension SQL syntax errors * Debug logging of DataExtension registration * Extension data updating to login listeners * Fix Extension SQL Syntax errors related to id selection * Fixed many Extension Provider store errors * Data objects for extension data about a player These objects make it easier to construct query data from database. * Fix flipped double and percentage storage transactions * getByName to Extension enums * Query for DataExtension data of a single player * Deprecated player plugin tab related things * DataExtension API player page plugin tab generation * Registered AdvancedBan extension * Added BooleanProvider#hidden * Added Conditional#negated * Added booleans to PluginInfo for controlling method calls. * Bump extension API to 0.0.2 * Extract method call booleans from PluginInfo * Added flow for Negated conditions Negated conditions' names are prefixed with not_ This allows checking against negated Conditionals and does not need adding more table rows. * Registered BanManager Extension * Transaction for removing unsatisfied Conditional data: This is one of the most complex queries I have made. - Select all fulfilled conditions for all players (conditionName when true and not_conditionName when false) - Left join with player value & provider tables when uuids match, and when condition matches a condition in the query above. - Filter the join query for values where the condition did not match any provided condition in the join (Is null) - Delete all player values with IDs that are returned by the left join query after filtering In addition: - Added test for the transaction - Added extension data removal to RemoveEverythingTransaction - Added unregister method to ExtensionService * Reverse table names since MySQL can not select and update: More information https://stackoverflow.com/questions/4429319/you-cant-specify-target-table-for-update-in-from-clause Attempts to fix: 'You can't specify target table 'plan_extension_user_values' for update in FROM clause' * Nest query since MySQL can not select and update: More information https://stackoverflow.com/a/9843719 Attempts to fix: 'You can't specify target table 'plan_extension_user_values' for update in FROM clause' * Added missing "as ..." to the query: Attempts to fix "Every derived table must have its own alias" * Added comment about nested query * Implemented BooleanProvider hidden parameter * Bump extension versions * Registered DiscordSRV extension * Fixing some new code smells: Critical: - String literal duplication fixed in a few places - Cognitive complexity reduced in BooleanProviderValueGatherer Major: - Called Optional#isPresent before accessing value 16 instances in ProviderTransactions - private constructor to Extension tables - Missing deprecated tags to deprecated plugin tab stuff - Unused class variable removal - Throw dedicated exceptions in ServerServerInfo - Unused method removal Minor: - Renamed 'API' field to 'service' in ExtensionService - Unused variable removal * Fix SQL error introduced when 'hidden' was added * Color replacement to StringProvider values * Gatherer methods for server providers * Storage for extension server data * Moved some results classes around * ExtensionServerData class * Fixed ConfigReader sometimes adding empty string to a null value. * ExtensionServerDataQuery + BooleanAggregateQuery: - Queries plan_extension_server_values - Queries plan_extension_player_values for aggregates * More Aggregate Queries * Server ExtensionData visualization * Network ExtensionData visualization * Removed date values from number aggregate query * Registered Essentials extension * Registered Sponge Economy Extension * Removed update booleans from PluginInfo * More flexible definition of calling Extension methods * Implemented Caller and CallEvents filtering * Implemented Extension player method calls * CallEvents.SERVER_EXTENSION_REGISTER call * CallEvents.SERVER_PERIODICAL calls * Updated extension versions * Updated Essentials extension * Fixed 'sponge' module test errors * Fix some code smells * Fixed Transaction#executeOther when using dbType * Fixed Aggregate label issues * TableContainer no longer displays 'null' * '(Legacy)' added to PluginData tabs
This commit is contained in:
commit
802f0749eb
41
Plan/api/build.gradle
Normal file
41
Plan/api/build.gradle
Normal file
@ -0,0 +1,41 @@
|
||||
plugins {
|
||||
id "com.jfrog.bintray" version "1.8.1"
|
||||
}
|
||||
|
||||
ext.apiVersion = '0.0.3'
|
||||
|
||||
bintray {
|
||||
user = System.getenv('BINTRAY_USER')
|
||||
key = System.getenv('BINTRAY_KEY')
|
||||
pkg {
|
||||
repo = 'Plan-repository'
|
||||
name = 'Plan-API'
|
||||
licenses = ['LGPL-v3.0']
|
||||
vcsUrl = 'https://github.com/plan-player-analytics/Plan'
|
||||
issueTrackerUrl = 'https://github.com/plan-player-analytics/Plan/issues'
|
||||
version {
|
||||
name = "$apiVersion"
|
||||
desc = "Plan APIv5 version $apiVersion"
|
||||
}
|
||||
publications = ['BintrayPublication']
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
BintrayPublication(MavenPublication) {
|
||||
groupId = 'com.djrapitops'
|
||||
artifactId = 'Plan-api'
|
||||
version = "$apiVersion"
|
||||
|
||||
artifact jar
|
||||
}
|
||||
mavenJava(MavenPublication) {
|
||||
groupId = 'com.djrapitops'
|
||||
artifactId = 'Plan-api'
|
||||
version = "$apiVersion"
|
||||
|
||||
artifact jar
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
/**
|
||||
* Enum representing different events when Plan calls methods of {@link DataExtension} automatically.
|
||||
* <p>
|
||||
* You can also call the update methods via {@link Caller} manually.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public enum CallEvents {
|
||||
|
||||
/**
|
||||
* This event represents a manual call via {@link Caller}.
|
||||
* Definition inside {@link DataExtension#callExtensionMethodsOn()} is NOT REQUIRED for using Caller methods.
|
||||
*/
|
||||
MANUAL,
|
||||
/**
|
||||
* This event represents call to player methods on a Player Join event.
|
||||
* <p>
|
||||
* The call is made from a listener at the last event priority (Bukkit/Bungee: MONITOR, Sponge: POST).
|
||||
* Method calls are asynchronous.
|
||||
*/
|
||||
PLAYER_JOIN,
|
||||
/**
|
||||
* This event represents a call to player methods on a Player Leave event.
|
||||
* <p>
|
||||
* The call is made from a listener at the first event priority (Bukkit/Bungee: LOWEST, Sponge: PRE).
|
||||
* Method calls are asynchronous.
|
||||
*/
|
||||
PLAYER_LEAVE,
|
||||
/**
|
||||
* This event represents a call to server methods when the {@link DataExtension} is registered.
|
||||
* <p>
|
||||
* Server methods include any {@link Group} parameter methods.
|
||||
* <p>
|
||||
* Method calls are asynchronous.
|
||||
*/
|
||||
SERVER_EXTENSION_REGISTER,
|
||||
/**
|
||||
* This event represents a call to server methods via a periodical task.
|
||||
* <p>
|
||||
* Server methods include any {@link Group} parameter methods.
|
||||
* <p>
|
||||
* Periodic task with a runs user configured period (Plan config).
|
||||
* Method calls are asynchronous.
|
||||
*/
|
||||
SERVER_PERIODICAL
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Interface for manually calling update methods on a registered {@link DataExtension}.
|
||||
* <p>
|
||||
* You can obtain an instance by registering an extension via {@link ExtensionService#register(DataExtension)}.
|
||||
* <p>
|
||||
* Plan calls the methods in DataExtension based on {@link CallEvents} defined by {@link }
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface Caller {
|
||||
|
||||
/**
|
||||
* Calls all player methods of the associated {@link DataExtension}.
|
||||
* <p>
|
||||
* Player methods have {@code UUID} or {@code String} as a method parameter and a Provider annotation.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @param playerName Name of the player.
|
||||
* @throws IllegalArgumentException If playerUUID or playerName is null.
|
||||
*/
|
||||
void updatePlayerData(UUID playerUUID, String playerName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Calls all server methods of the associated {@link DataExtension}.
|
||||
* <p>
|
||||
* Server methods have no parameters or {@link Group} method parameter and a Provider annotation.
|
||||
*/
|
||||
void updateServerData();
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
/**
|
||||
* Interface to implement data extensions with.
|
||||
* <p>
|
||||
* The class implementing this interface should be annotated with {@link com.djrapitops.plan.extension.annotation.PluginInfo}.
|
||||
* If the extension is given to Plan API without the annotation it will be rejected.
|
||||
* <hr>
|
||||
* <p>
|
||||
* Public methods in the class should be annotated with appropriate Provider annotations.
|
||||
* Provider annotations:
|
||||
* {@link com.djrapitops.plan.extension.annotation.BooleanProvider} for {@code boolean} values and conditions for {@link com.djrapitops.plan.extension.annotation.Conditional}.
|
||||
* {@link com.djrapitops.plan.extension.annotation.NumberProvider} for {@code long} values. (Use this for integers by casting to long) Has option for formatting.
|
||||
* {@link com.djrapitops.plan.extension.annotation.DoubleProvider} for {@code double} values.
|
||||
* {@link com.djrapitops.plan.extension.annotation.PercentageProvider} for {@code double} values that represent a percentage.
|
||||
* {@link com.djrapitops.plan.extension.annotation.StringProvider} for {@link String} values.
|
||||
* <hr>
|
||||
* <p>
|
||||
* Methods can have one of the following as method parameters:
|
||||
* {@code UUID playerUUID} - UUID of the player the data is about
|
||||
* {@code String playerName} - Name of the player the data is about
|
||||
* {@link Group group} - Provided group the data is about (In case a group needs additional information)
|
||||
* nothing - The data is interpreted to be about the server.
|
||||
* <hr>
|
||||
* <p>
|
||||
* The name of the method will be used as an identifier in the database, so that a single provider does not duplicate entries.
|
||||
* Only first 50 characters of the method name are stored.
|
||||
* If you need to change a method name add a class annotation with the old method name: {@link com.djrapitops.plan.extension.annotation.InvalidateMethod}
|
||||
* <p>
|
||||
* Some additional annotations are available for controlling appearance of the results:
|
||||
* {@link com.djrapitops.plan.extension.annotation.Conditional} A {@code boolean} returned by {@link com.djrapitops.plan.extension.annotation.BooleanProvider} has to be {@code true} for this method to be called.
|
||||
* {@link com.djrapitops.plan.extension.annotation.Tab} The value of this provider should be placed on a tab with a specific name
|
||||
* {@link com.djrapitops.plan.extension.annotation.TabInfo} Optional Structure information about a tab
|
||||
* {@link com.djrapitops.plan.extension.annotation.TabOrder} Optional information about preferred tab
|
||||
* <hr>
|
||||
* <p>
|
||||
* Method calls are asynchronous. You can control when the calls are made via {@link DataExtension#callExtensionMethodsOn()} and {@link Caller}.
|
||||
* <p>
|
||||
* You can check against implementation violations by using {@link com.djrapitops.plan.extension.extractor.ExtensionExtractor#validateAnnotations()} in your Unit Tests.
|
||||
* <p>
|
||||
* Implementation violations:
|
||||
* - No {@link com.djrapitops.plan.extension.annotation.PluginInfo} class annotation
|
||||
* - Class contains no public methods with Provider annotations
|
||||
* - Class contains private method with Provider annotation
|
||||
* - Non-primitive return type when primitive is required (eg. Boolean instead of boolean)
|
||||
* - Method doesn't have correct parameters (see above)
|
||||
* - {@link com.djrapitops.plan.extension.annotation.BooleanProvider} is annotated with a {@link com.djrapitops.plan.extension.annotation.Conditional} that requires same condition the provider provides.
|
||||
* - {@link com.djrapitops.plan.extension.annotation.Conditional} without a {@link com.djrapitops.plan.extension.annotation.BooleanProvider} that provides value for the condition
|
||||
* - Annotation variable is over 50 characters (Or 150 if description)
|
||||
* - Method name is over 50 characters (Used as an identifier for storage)
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see com.djrapitops.plan.extension.annotation.PluginInfo Required Annotation
|
||||
* @see CallEvents for method call event types.
|
||||
*/
|
||||
public interface DataExtension {
|
||||
|
||||
/**
|
||||
* Determines when DataExtension methods are called automatically by Plan.
|
||||
* <p>
|
||||
* Override this method to determine more suitable call times for your plugin.
|
||||
* You can also use {@link Caller} to update manually.
|
||||
* <p>
|
||||
* If an empty array is supplied the DataExtension methods are not called by Plan automatically.
|
||||
*
|
||||
* @return Event types that will trigger method calls to the DataExtension.
|
||||
* @see CallEvents for details when the methods are called.
|
||||
*/
|
||||
default CallEvents[] callExtensionMethodsOn() {
|
||||
return new CallEvents[]{
|
||||
CallEvents.PLAYER_JOIN,
|
||||
CallEvents.PLAYER_LEAVE,
|
||||
CallEvents.SERVER_EXTENSION_REGISTER
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Enum representing big elements of a plugin.
|
||||
* <p>
|
||||
* Used for determining in which order elements are placed on a {@link com.djrapitops.plan.extension.annotation.Tab} by
|
||||
* using {@link com.djrapitops.plan.extension.annotation.TabInfo}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public enum ElementOrder {
|
||||
/**
|
||||
* Represents text - value pair box.
|
||||
*/
|
||||
VALUES,
|
||||
/**
|
||||
* Represents tables.
|
||||
*/
|
||||
TABLE,
|
||||
/**
|
||||
* Represents graphs.
|
||||
*/
|
||||
GRAPH;
|
||||
|
||||
public static String serialize(ElementOrder[] order) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
int length = order.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
builder.append(order[i].name());
|
||||
if (i < length - 1) {
|
||||
builder.append(',');
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static ElementOrder[] deserialize(String serializedOrder) {
|
||||
if (serializedOrder == null || serializedOrder.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] split = serializedOrder.split(",");
|
||||
|
||||
List<ElementOrder> order = new ArrayList<>();
|
||||
for (String elementName : split) {
|
||||
try {
|
||||
ElementOrder element = valueOf(elementName);
|
||||
order.add(element);
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
/* Has been deleted */
|
||||
}
|
||||
}
|
||||
|
||||
return order.toArray(new ElementOrder[0]);
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
import com.djrapitops.plan.extension.extractor.ExtensionExtractor;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Interface for registering {@link DataExtension}s.
|
||||
* <p>
|
||||
* Obtaining instance:
|
||||
* - Obtain instance with {@link ExtensionService#getInstance()}.
|
||||
* - Make sure to catch a possible NoClassDefFoundError in case Plan is not installed
|
||||
* - Catch IllegalStateException in case ExtensionService is not enabled
|
||||
* <p>
|
||||
* Registering {@link DataExtension}:
|
||||
* - Register your {@link DataExtension} with {@link ExtensionService#register(DataExtension)}
|
||||
* - Catch a possible IllegalArgumentException in case the DataExtension implementation is invalid.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface ExtensionService {
|
||||
|
||||
/**
|
||||
* Obtain instance of ExtensionService.
|
||||
*
|
||||
* @return ExtensionService implementation.
|
||||
* @throws NoClassDefFoundError If Plan is not installed and this class can not be found or if older Plan version is installed.
|
||||
* @throws IllegalStateException If Plan is installed, but not enabled.
|
||||
*/
|
||||
static ExtensionService getInstance() {
|
||||
return Optional.ofNullable(ExtensionServiceHolder.service)
|
||||
.orElseThrow(() -> new IllegalStateException("ExtensionService has not been initialised yet."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register your {@link DataExtension} implementation.
|
||||
* <p>
|
||||
* You can use {@link ExtensionExtractor#validateAnnotations()} in your Unit Tests to prevent IllegalArgumentExceptions here at runtime.
|
||||
*
|
||||
* @param extension Your DataExtension implementation, see {@link DataExtension} for requirements.
|
||||
* @return Optional {@link Caller} that can be used to call for data update in Plan database manually - If the Optional is not present the user has disabled the extension in Plan config.
|
||||
* @throws IllegalArgumentException If an implementation violation is found.
|
||||
*/
|
||||
Optional<Caller> register(DataExtension extension);
|
||||
|
||||
/**
|
||||
* Unregister your {@link DataExtension} implementation.
|
||||
* <p>
|
||||
* This method should be used if calling methods on the DataExtension suddenly becomes unavailable, due to
|
||||
* plugin disable for example.
|
||||
*
|
||||
* @param extension Your DataExtension implementation that was registered before.
|
||||
*/
|
||||
void unregister(DataExtension extension);
|
||||
|
||||
class ExtensionServiceHolder {
|
||||
static ExtensionService service;
|
||||
|
||||
private ExtensionServiceHolder() {
|
||||
/* Static variable holder */
|
||||
}
|
||||
|
||||
static void set(ExtensionService service) {
|
||||
ExtensionServiceHolder.service = service;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Enum for determining additional formatter for a value given by a {@link com.djrapitops.plan.extension.annotation.NumberProvider}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public enum FormatType {
|
||||
|
||||
/**
|
||||
* Formats a long value (Epoch ms) to a readable timestamp, year is important.
|
||||
*/
|
||||
DATE_YEAR,
|
||||
/**
|
||||
* Formats a long value (Epoch ms) to a readable timestamp, second is important.
|
||||
*/
|
||||
DATE_SECOND,
|
||||
/**
|
||||
* Formats a long value (ms) to a readable format.
|
||||
*/
|
||||
TIME_MILLISECONDS,
|
||||
/**
|
||||
* Applies no formatting to the value.
|
||||
*/
|
||||
NONE;
|
||||
|
||||
public static Optional<FormatType> getByName(String name) {
|
||||
try {
|
||||
return Optional.of(valueOf(name));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
/**
|
||||
* Method parameter for providing values about a group with provider annotations.
|
||||
* <p>
|
||||
* Usage Example: {@code @StringProvider String provideStringAboutGroup(Group group)}
|
||||
* <p>
|
||||
* Group names of users are provided with {@code @GroupProvider String[] provideGroups(UUID playerUUID)}
|
||||
* {@code Group} parameter methods are not called without knowledge of a group name.
|
||||
* <p>
|
||||
* This method parameter is used since it is not possible to differentiate String playerName and String groupName.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface Group {
|
||||
|
||||
String getGroupName();
|
||||
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method annotation to provide a boolean value about a Player.
|
||||
* <p>
|
||||
* Usage: {@code @BooleanProvider boolean method(UUID playerUUID)}
|
||||
* <p>
|
||||
* The provided boolean can be used as a condition for calls to other Provider
|
||||
* methods by defining the name of the condition and using {@link Conditional}
|
||||
* on the other method with a Provider annotation.
|
||||
* <p>
|
||||
* For example:
|
||||
* {@code @BooleanProvider(condition="example") boolean condition(UUID playerUUID);}
|
||||
* {@code @Conditional("example") @NumberProvider long someValue(UUID playerUUID);}
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface BooleanProvider {
|
||||
|
||||
/**
|
||||
* Text displayed before the value, limited to 50 characters.
|
||||
* <p>
|
||||
* Should inform the user what the value represents, for example
|
||||
* "Banned", "Has Island"
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String text();
|
||||
|
||||
/**
|
||||
* Display-priority of the value, highest value is placed top most.
|
||||
* <p>
|
||||
* Two values with same priority may appear in a random order.
|
||||
*
|
||||
* @return Priority between 0 and {@code Integer.MAX_VALUE}.
|
||||
*/
|
||||
int priority() default 0;
|
||||
|
||||
/**
|
||||
* Text displayed when hovering over the value, limited to 150 characters.
|
||||
* <p>
|
||||
* Should be used to clarify what the value is if not self evident, for example
|
||||
* text: "Boat", description: "Whether or not the player is on a boat."
|
||||
*
|
||||
* @return String of max 150 characters, remainder will be clipped.
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* Name of the {@link Conditional} condition limited to 50 characters.
|
||||
*
|
||||
* @return Case sensitive string of max 50 characters.
|
||||
*/
|
||||
String conditionName() default "";
|
||||
|
||||
/**
|
||||
* Should the result of this method be hidden from the user.
|
||||
*
|
||||
* @return true if the value should not be displayed on the page.
|
||||
*/
|
||||
boolean hidden() default false;
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "question";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color iconColor() default Color.NONE;
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method Annotation to determine that a method can not be called unless a condition is fulfilled.
|
||||
* <p>
|
||||
* Condition information is provided with {@link com.djrapitops.plan.extension.annotation.data.BooleanProvider}.
|
||||
* If {@link com.djrapitops.plan.extension.annotation.BooleanProvider} for the condition is not specified the
|
||||
* method tagged with this annotation will not be called, (Condition is assumed false).
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Conditional {
|
||||
|
||||
/**
|
||||
* Name of the condition limited to 50 characters.
|
||||
*
|
||||
* @return Case sensitive string of max 50 characters.
|
||||
*/
|
||||
String value();
|
||||
|
||||
/**
|
||||
* Reverse the condition.
|
||||
* <p>
|
||||
* Example:
|
||||
* - Method with {@code Conditional("expires", negated = true)} will only be called when the condition "expires" is false.
|
||||
*
|
||||
* @return {@code false} by default.
|
||||
*/
|
||||
boolean negated() default false;
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method annotation to provide a double value about a Player.
|
||||
* <p>
|
||||
* Usage: {@code @DoubleProvider double method(UUID playerUUID)}
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface DoubleProvider {
|
||||
|
||||
/**
|
||||
* Text displayed before the value, limited to 50 characters.
|
||||
* <p>
|
||||
* Should inform the user what the value represents, for example
|
||||
* "Distance from spawn", "Balance"
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String text();
|
||||
|
||||
/**
|
||||
* Display-priority of the value, highest value is placed top most.
|
||||
* <p>
|
||||
* Two values with same priority may appear in a random order.
|
||||
*
|
||||
* @return Priority between 0 and {@code Integer.MAX_VALUE}.
|
||||
*/
|
||||
int priority() default 0;
|
||||
|
||||
/**
|
||||
* Text displayed when hovering over the value, limited to 150 characters.
|
||||
* <p>
|
||||
* Should be used to clarify what the value is if not self evident, for example
|
||||
* text: "Balance", description: "Economy balance of the player"
|
||||
*
|
||||
* @return String of max 150 characters, remainder will be clipped.
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "question";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color iconColor() default Color.NONE;
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Annotation used to invalidate old method values.
|
||||
* <p>
|
||||
* The name of the methods are used as an identifier in the database, so that a single provider does not duplicate entries.
|
||||
* Only first 50 characters of the method name are stored.
|
||||
* If you need to change a method name add this class annotation with the old method name.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Repeatable(InvalidateMethod.Multiple.class)
|
||||
public @interface InvalidateMethod {
|
||||
|
||||
/**
|
||||
* Name of the old method, values of which should be removed from the database.
|
||||
*
|
||||
* @return Name of the old method, case sensitive. Only first 50 characters are used.
|
||||
*/
|
||||
String value();
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@interface Multiple {
|
||||
|
||||
InvalidateMethod[] value();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.FormatType;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method annotation to provide a long (64bit number) value about a Player.
|
||||
* <p>
|
||||
* If you want to return int values, use this provider with a long as
|
||||
* return type of the method.
|
||||
* <p>
|
||||
* Usage: {@code @NumberProvider long method(UUID playerUUID)}
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface NumberProvider {
|
||||
|
||||
/**
|
||||
* Text displayed before the value, limited to 50 characters.
|
||||
* <p>
|
||||
* Should inform the user what the value represents, for example
|
||||
* "Owned Chickens", "Claimed Blocks"
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String text();
|
||||
|
||||
/**
|
||||
* Display-priority of the value, highest value is placed top most.
|
||||
* <p>
|
||||
* Two values with same priority may appear in a random order.
|
||||
*
|
||||
* @return Priority between 0 and {@code Integer.MAX_VALUE}.
|
||||
*/
|
||||
int priority() default 0;
|
||||
|
||||
/**
|
||||
* Text displayed when hovering over the value, limited to 150 characters.
|
||||
* <p>
|
||||
* Should be used to clarify what the value is if not self evident, for example
|
||||
* text: "Fished", description: "How long the player has fished for"
|
||||
*
|
||||
* @return String of max 150 characters, remainder will be clipped.
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* Apply special formatting to the value before presentation.
|
||||
*
|
||||
* @return {@link FormatType} that best represents the long value.
|
||||
* @see FormatType for available formatters.
|
||||
*/
|
||||
FormatType format() default FormatType.NONE;
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "question";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color iconColor() default Color.NONE;
|
||||
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method annotation to provide a double (Percentage) about a Player.
|
||||
* <p>
|
||||
* Usage: {@code @PercentageProvider double method(UUID playerUUID)}
|
||||
* <p>
|
||||
* The returned value should be between (or one of) 0.0 (0%) and 1.0 (100%).
|
||||
* Other values will be ignored.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface PercentageProvider {
|
||||
|
||||
/**
|
||||
* Text displayed before the value, limited to 50 characters.
|
||||
* <p>
|
||||
* Should inform the user what the value represents, for example
|
||||
* "Health", "Power"
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String text();
|
||||
|
||||
/**
|
||||
* Display-priority of the value, highest value is placed top most.
|
||||
* <p>
|
||||
* Two values with same priority may appear in a random order.
|
||||
*
|
||||
* @return Priority between 0 and {@code Integer.MAX_VALUE}.
|
||||
*/
|
||||
int priority() default 0;
|
||||
|
||||
/**
|
||||
* Text displayed when hovering over the value, limited to 150 characters.
|
||||
* <p>
|
||||
* Should be used to clarify what the value is if not self evident, for example
|
||||
* text: "Power", description: "Faction power, affects ability of faction to perform actions. Regenerates"
|
||||
*
|
||||
* @return String of max 150 characters, remainder will be clipped.
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "question";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color iconColor() default Color.NONE;
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Class Annotation for informing Plan about a plugin.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see TabOrder to determine preferred tab ordering if you use {@link Tab}s.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface PluginInfo {
|
||||
|
||||
/**
|
||||
* Name of the plugin, limited to 50 characters.
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "cube";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color color() default Color.NONE;
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method annotation to provide a String value about a Player.
|
||||
* <p>
|
||||
* Usage: {@code @StringProvider String method(UUID playerUUID)}
|
||||
* <p>
|
||||
* The returned value is limited to 100 characters, remainder will be clipped.
|
||||
* <p>
|
||||
* If the value is a player name, provide value for playerName=true.
|
||||
* This will allow linking between pages.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface StringProvider {
|
||||
|
||||
/**
|
||||
* Text displayed before the value, limited to 50 characters.
|
||||
* <p>
|
||||
* Should inform the user what the value represents, for example
|
||||
* "Town Name", "Pet Name"
|
||||
*
|
||||
* @return String of max 50 characters, remainder will be clipped.
|
||||
*/
|
||||
String text();
|
||||
|
||||
/**
|
||||
* Display-priority of the value, highest value is placed top most.
|
||||
* <p>
|
||||
* Two values with same priority may appear in a random order.
|
||||
*
|
||||
* @return Priority between 0 and {@code Integer.MAX_VALUE}.
|
||||
*/
|
||||
int priority() default 0;
|
||||
|
||||
/**
|
||||
* Text displayed when hovering over the value, limited to 150 characters.
|
||||
* <p>
|
||||
* Should be used to clarify what the value is if not self evident, for example
|
||||
* text: "Power", description: "Faction power, affects ability of faction to perform actions. Regenerates"
|
||||
*
|
||||
* @return String of max 150 characters, remainder will be clipped.
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* Determine if this value represents a Player name, for example a mayor of a town.
|
||||
*
|
||||
* @return {@code true} if the name can be used as a link to another player's page.
|
||||
*/
|
||||
boolean playerName() default false;
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "question";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Color preference of the plugin.
|
||||
* <p>
|
||||
* This color will be set as the default color to use for plugin's elements.
|
||||
*
|
||||
* @return Preferred color. If none are specified defaults are used.
|
||||
*/
|
||||
Color iconColor() default Color.NONE;
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Method Annotation for determining Tab the given element should appear on.
|
||||
* <p>
|
||||
* If not specified Plan places the item on the default tab.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see TabInfo if you want to determine an icon or element order for a Tab.
|
||||
* @see TabOrder to determine preferred tab ordering if you use Tabs.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Tab {
|
||||
|
||||
/**
|
||||
* Name of the tab to place this item on.
|
||||
*
|
||||
* @return Tab name, limited to 50 characters.
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Class Annotation that allows determining an Icon and {@link ElementOrder} of a tab.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Repeatable(TabInfo.Multiple.class)
|
||||
public @interface TabInfo {
|
||||
|
||||
/**
|
||||
* Name of the tab this information is about.
|
||||
*
|
||||
* @return Tab name, limited to 50 characters.
|
||||
*/
|
||||
String tab();
|
||||
|
||||
/**
|
||||
* Name of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Name of the icon, if name is not valid no icon is shown.
|
||||
*/
|
||||
String iconName() default "circle";
|
||||
|
||||
/**
|
||||
* Family of Font Awesome icon.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @return Family that matches an icon, if there is no icon for this family no icon is shown.
|
||||
*/
|
||||
Family iconFamily() default Family.SOLID;
|
||||
|
||||
/**
|
||||
* Order preference for the large elements of a tab.
|
||||
* <p>
|
||||
* If an ordering is not present they will be added to the end in the default order.
|
||||
* If a duplicate ordering exists only the first will be used for determining the order.
|
||||
*
|
||||
* @return ElementOrders in the order that they want to be displayed in.
|
||||
*/
|
||||
ElementOrder[] elementOrder();
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@interface Multiple {
|
||||
TabInfo[] value();
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Class Annotation for informing Plan about plugin's tab order preference.
|
||||
* <p>
|
||||
* If tab order is not defined alphabetical order is used.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface TabOrder {
|
||||
|
||||
/**
|
||||
* Order preference of different {@link Tab}s.
|
||||
* <p>
|
||||
* If a tab is defined that is not present it is ignored.
|
||||
* If a tab is not defined but is present alphabetical order is used.
|
||||
*
|
||||
* @return Names of the defined tabs (case sensitive).
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
}
|
@ -0,0 +1,360 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.extractor;
|
||||
|
||||
import com.djrapitops.plan.extension.DataExtension;
|
||||
import com.djrapitops.plan.extension.Group;
|
||||
import com.djrapitops.plan.extension.annotation.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Implementation detail, for extracting methods from {@link com.djrapitops.plan.extension.DataExtension}.
|
||||
* <p>
|
||||
* This class can be used for testing validity of annotation implementations
|
||||
* in your unit tests to avoid runtime errors. {@link ExtensionExtractor#validateAnnotations()}
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public final class ExtensionExtractor {
|
||||
|
||||
private final DataExtension extension;
|
||||
private final String extensionName;
|
||||
|
||||
private final List<String> warnings = new ArrayList<>();
|
||||
|
||||
private PluginInfo pluginInfo;
|
||||
private TabOrder tabOrder;
|
||||
private List<TabInfo> tabInformation;
|
||||
private List<InvalidateMethod> invalidMethods;
|
||||
private MethodAnnotations methodAnnotations;
|
||||
|
||||
private static final String WAS_OVER_50_CHARACTERS = "' was over 50 characters.";
|
||||
|
||||
public ExtensionExtractor(DataExtension extension) {
|
||||
this.extension = extension;
|
||||
extensionName = extension.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method in an unit test to validate your DataExtension.
|
||||
*
|
||||
* @throws IllegalArgumentException If an implementation error is found.
|
||||
*/
|
||||
public void validateAnnotations() {
|
||||
extractAnnotationInformation();
|
||||
|
||||
if (!warnings.isEmpty()) {
|
||||
throw new IllegalArgumentException("Warnings: " + warnings.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Annotation> Optional<T> getClassAnnotation(Class<T> ofClass) {
|
||||
return Optional.ofNullable(extension.getClass().getAnnotation(ofClass));
|
||||
}
|
||||
|
||||
private Method[] getMethods() {
|
||||
return extension.getClass().getDeclaredMethods();
|
||||
}
|
||||
|
||||
public void extractAnnotationInformation() {
|
||||
extractPluginInfo();
|
||||
extractInvalidMethods();
|
||||
|
||||
extractMethodAnnotations();
|
||||
validateMethodAnnotations();
|
||||
|
||||
validateConditionals();
|
||||
|
||||
extractTabInfo();
|
||||
}
|
||||
|
||||
private void extractMethodAnnotations() {
|
||||
methodAnnotations = new MethodAnnotations();
|
||||
|
||||
for (Method method : getMethods()) {
|
||||
if (!Modifier.isPublic(method.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MethodAnnotations.get(method, BooleanProvider.class).ifPresent(annotation -> methodAnnotations.put(method, BooleanProvider.class, annotation));
|
||||
MethodAnnotations.get(method, NumberProvider.class).ifPresent(annotation -> methodAnnotations.put(method, NumberProvider.class, annotation));
|
||||
MethodAnnotations.get(method, DoubleProvider.class).ifPresent(annotation -> methodAnnotations.put(method, DoubleProvider.class, annotation));
|
||||
MethodAnnotations.get(method, PercentageProvider.class).ifPresent(annotation -> methodAnnotations.put(method, PercentageProvider.class, annotation));
|
||||
MethodAnnotations.get(method, StringProvider.class).ifPresent(annotation -> methodAnnotations.put(method, StringProvider.class, annotation));
|
||||
|
||||
MethodAnnotations.get(method, Conditional.class).ifPresent(annotation -> methodAnnotations.put(method, Conditional.class, annotation));
|
||||
MethodAnnotations.get(method, Tab.class).ifPresent(annotation -> methodAnnotations.put(method, Tab.class, annotation));
|
||||
}
|
||||
|
||||
if (methodAnnotations.isEmpty()) {
|
||||
throw new IllegalArgumentException(extensionName + " class had no methods annotated with a Provider annotation");
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void validateReturnType(Method method, Class<T> expectedType) {
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (!expectedType.isAssignableFrom(returnType)) {
|
||||
throw new IllegalArgumentException(extensionName + "." + method.getName() + " has invalid return type. was: " + returnType.getName() + ", expected: " + expectedType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMethodAnnotationPropertyLength(String property, String name, int maxLength, Method method) {
|
||||
if (property.length() > maxLength) {
|
||||
warnings.add(extensionName + "." + method.getName() + " '" + name + WAS_OVER_50_CHARACTERS);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMethodArguments(Method method, boolean parameterIsRequired, Class... parameterOptions) {
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
|
||||
// Possible parameters for the methods:
|
||||
// UUID playerUUID, String playerName, Group group, none
|
||||
|
||||
int parameters = parameterTypes.length;
|
||||
|
||||
if (parameterIsRequired && parameters == 0) {
|
||||
// Does not have parameters, but one is required
|
||||
throw new IllegalArgumentException(extensionName + "." + method.getName() + " requires one of " + Arrays.toString(parameterOptions) + " as a parameter.");
|
||||
} else if (parameters == 0) {
|
||||
// Has no parameters & it is acceptable.
|
||||
return;
|
||||
}
|
||||
|
||||
if (parameters > 1) {
|
||||
// Has too many parameters
|
||||
throw new IllegalArgumentException(extensionName + "." + method.getName() + " has too many parameters, only one of " + Arrays.toString(parameterOptions) + " is required as a parameter.");
|
||||
}
|
||||
|
||||
Class<?> methodParameter = parameterTypes[0];
|
||||
|
||||
boolean validParameter = false;
|
||||
for (Class option : parameterOptions) {
|
||||
if (option.equals(methodParameter)) {
|
||||
validParameter = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validParameter) {
|
||||
// Has invalid parameter
|
||||
throw new IllegalArgumentException(extensionName + "." + method.getName() + " has invalid parameter: '" + methodParameter.getName() + "' one of " + Arrays.toString(parameterOptions) + " is required as a parameter.");
|
||||
}
|
||||
// Has valid parameter & it is acceptable.
|
||||
}
|
||||
|
||||
private void validateMethodAnnotations() {
|
||||
validateBooleanProviderAnnotations();
|
||||
validateNumberProviderAnnotations();
|
||||
validateDoubleProviderAnnotations();
|
||||
validatePercentageProviderAnnotations();
|
||||
validateStringProviderAnnotations();
|
||||
}
|
||||
|
||||
private void validateBooleanProviderAnnotations() {
|
||||
for (Map.Entry<Method, BooleanProvider> booleanProvider : methodAnnotations.getMethodAnnotations(BooleanProvider.class).entrySet()) {
|
||||
Method method = booleanProvider.getKey();
|
||||
BooleanProvider annotation = booleanProvider.getValue();
|
||||
|
||||
validateReturnType(method, boolean.class);
|
||||
validateMethodAnnotationPropertyLength(annotation.text(), "text", 50, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.description(), "description", 150, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.conditionName(), "conditionName", 50, method);
|
||||
validateMethodArguments(method, false, UUID.class, String.class, Group.class);
|
||||
|
||||
String condition = MethodAnnotations.get(method, Conditional.class).map(Conditional::value).orElse(null);
|
||||
if (annotation.conditionName().equals(condition)) {
|
||||
warnings.add(extensionName + "." + method.getName() + " can not be conditional of itself. required condition: " + condition + ", provided condition: " + annotation.conditionName());
|
||||
}
|
||||
|
||||
if (annotation.conditionName().isEmpty() && annotation.hidden()) {
|
||||
throw new IllegalArgumentException(extensionName + "." + method.getName() + " can not be 'hidden' without a 'conditionName'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateNumberProviderAnnotations() {
|
||||
for (Map.Entry<Method, NumberProvider> numberProvider : methodAnnotations.getMethodAnnotations(NumberProvider.class).entrySet()) {
|
||||
Method method = numberProvider.getKey();
|
||||
NumberProvider annotation = numberProvider.getValue();
|
||||
|
||||
validateReturnType(method, long.class);
|
||||
validateMethodAnnotationPropertyLength(annotation.text(), "text", 50, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.description(), "description", 150, method);
|
||||
validateMethodArguments(method, false, UUID.class, String.class, Group.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateDoubleProviderAnnotations() {
|
||||
for (Map.Entry<Method, DoubleProvider> numberProvider : methodAnnotations.getMethodAnnotations(DoubleProvider.class).entrySet()) {
|
||||
Method method = numberProvider.getKey();
|
||||
DoubleProvider annotation = numberProvider.getValue();
|
||||
|
||||
validateReturnType(method, double.class);
|
||||
validateMethodAnnotationPropertyLength(annotation.text(), "text", 50, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.description(), "description", 150, method);
|
||||
validateMethodArguments(method, false, UUID.class, String.class, Group.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void validatePercentageProviderAnnotations() {
|
||||
for (Map.Entry<Method, PercentageProvider> numberProvider : methodAnnotations.getMethodAnnotations(PercentageProvider.class).entrySet()) {
|
||||
Method method = numberProvider.getKey();
|
||||
PercentageProvider annotation = numberProvider.getValue();
|
||||
|
||||
validateReturnType(method, double.class);
|
||||
validateMethodAnnotationPropertyLength(annotation.text(), "text", 50, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.description(), "description", 150, method);
|
||||
validateMethodArguments(method, false, UUID.class, String.class, Group.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateStringProviderAnnotations() {
|
||||
for (Map.Entry<Method, StringProvider> numberProvider : methodAnnotations.getMethodAnnotations(StringProvider.class).entrySet()) {
|
||||
Method method = numberProvider.getKey();
|
||||
StringProvider annotation = numberProvider.getValue();
|
||||
|
||||
validateReturnType(method, String.class);
|
||||
validateMethodAnnotationPropertyLength(annotation.text(), "text", 50, method);
|
||||
validateMethodAnnotationPropertyLength(annotation.description(), "description", 150, method);
|
||||
validateMethodArguments(method, false, UUID.class, String.class, Group.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateConditionals() {
|
||||
Collection<Conditional> conditionals = methodAnnotations.getAnnotations(Conditional.class);
|
||||
Collection<BooleanProvider> conditionProviders = methodAnnotations.getAnnotations(BooleanProvider.class);
|
||||
|
||||
Set<String> providedConditions = conditionProviders.stream().map(BooleanProvider::conditionName).collect(Collectors.toSet());
|
||||
|
||||
for (Conditional condition : conditionals) {
|
||||
String conditionName = condition.value();
|
||||
|
||||
if (conditionName.length() > 50) {
|
||||
warnings.add(extensionName + ": '" + conditionName + "' conditionName was over 50 characters.");
|
||||
}
|
||||
|
||||
if (!providedConditions.contains(conditionName)) {
|
||||
warnings.add(extensionName + ": '" + conditionName + "' Condition was not provided by any BooleanProvider.");
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that all methods annotated with Conditional have a Provider annotation
|
||||
Collection<Method> conditionalMethods = methodAnnotations.getMethodAnnotations(Conditional.class).keySet();
|
||||
for (Method conditionalMethod : conditionalMethods) {
|
||||
if (!MethodAnnotations.hasAnyOf(conditionalMethod,
|
||||
BooleanProvider.class, DoubleProvider.class, NumberProvider.class,
|
||||
PercentageProvider.class, StringProvider.class
|
||||
)) {
|
||||
throw new IllegalArgumentException(extensionName + "." + conditionalMethod.getName() + " did not have any associated Provider for Conditional.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractPluginInfo() {
|
||||
pluginInfo = getClassAnnotation(PluginInfo.class).orElseThrow(() -> new IllegalArgumentException("Given class had no PluginInfo annotation"));
|
||||
|
||||
if (pluginInfo.name().length() > 50) {
|
||||
warnings.add(extensionName + " PluginInfo 'name' was over 50 characters.");
|
||||
}
|
||||
}
|
||||
|
||||
private void extractTabInfo() {
|
||||
tabInformation = new ArrayList<>();
|
||||
getClassAnnotation(TabInfo.Multiple.class).ifPresent(tabs -> {
|
||||
for (TabInfo tabInfo : tabs.value()) {
|
||||
String tabName = tabInfo.tab();
|
||||
|
||||
// Length restriction check
|
||||
if (tabName.length() > 50) {
|
||||
warnings.add(extensionName + " tabName '" + tabName + WAS_OVER_50_CHARACTERS);
|
||||
}
|
||||
|
||||
tabInformation.add(tabInfo);
|
||||
}
|
||||
});
|
||||
|
||||
tabOrder = getClassAnnotation(TabOrder.class).orElse(null);
|
||||
|
||||
Map<Method, Tab> tabs = this.methodAnnotations.getMethodAnnotations(Tab.class);
|
||||
Set<String> tabNames = tabs.values().stream().map(Tab::value).collect(Collectors.toSet());
|
||||
|
||||
// Check for unused TabInfo annotations
|
||||
for (TabInfo tabInfo : tabInformation) {
|
||||
String tabName = tabInfo.tab();
|
||||
|
||||
if (tabName.length() > 50) {
|
||||
warnings.add(extensionName + " TabInfo " + tabName + " name was over 50 characters.");
|
||||
}
|
||||
|
||||
if (!tabNames.contains(tabName)) {
|
||||
warnings.add(extensionName + " has TabInfo for " + tabName + ", but it is not used.");
|
||||
}
|
||||
}
|
||||
|
||||
// Check Tab name lengths
|
||||
for (Map.Entry<Method, Tab> tab : tabs.entrySet()) {
|
||||
String tabName = tab.getValue().value();
|
||||
if (tabName.length() > 50) {
|
||||
warnings.add(extensionName + "." + tab.getKey().getName() + " Tab '" + tabName + "' name was over 50 characters.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractInvalidMethods() {
|
||||
invalidMethods = new ArrayList<>();
|
||||
getClassAnnotation(InvalidateMethod.Multiple.class).ifPresent(tabs -> {
|
||||
for (InvalidateMethod tabInfo : tabs.value()) {
|
||||
String methodName = tabInfo.value();
|
||||
|
||||
// Length restriction check
|
||||
if (methodName.length() > 50) {
|
||||
warnings.add(extensionName + " invalidated method '" + methodName + WAS_OVER_50_CHARACTERS);
|
||||
}
|
||||
|
||||
invalidMethods.add(tabInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public List<String> getWarnings() {
|
||||
return warnings;
|
||||
}
|
||||
|
||||
public PluginInfo getPluginInfo() {
|
||||
return pluginInfo;
|
||||
}
|
||||
|
||||
public Optional<TabOrder> getTabOrder() {
|
||||
return Optional.ofNullable(tabOrder);
|
||||
}
|
||||
|
||||
public List<TabInfo> getTabInformation() {
|
||||
return tabInformation != null ? tabInformation : Collections.emptyList();
|
||||
}
|
||||
|
||||
public MethodAnnotations getMethodAnnotations() {
|
||||
return methodAnnotations;
|
||||
}
|
||||
|
||||
public List<InvalidateMethod> getInvalidateMethodAnnotations() {
|
||||
return invalidMethods != null ? invalidMethods : Collections.emptyList();
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.extractor;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Implementation detail, utility class for handling method annotations.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class MethodAnnotations {
|
||||
|
||||
private final Map<Class, Map<Method, Annotation>> byAnnotationType;
|
||||
|
||||
public MethodAnnotations() {
|
||||
byAnnotationType = new HashMap<>();
|
||||
}
|
||||
|
||||
public static boolean hasAnyOf(Method method, Class... annotationClasses) {
|
||||
for (Annotation annotation : method.getAnnotations()) {
|
||||
for (Class annotationClass : annotationClasses) {
|
||||
if (annotationClass.isAssignableFrom(annotation.getClass())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static <T extends Annotation> Optional<T> get(Method from, Class<T> ofClass) {
|
||||
return Optional.ofNullable(from.getAnnotation(ofClass));
|
||||
}
|
||||
|
||||
public <T extends Annotation> void put(Method method, Class<T> annotationClass, T annotation) {
|
||||
Map<Method, Annotation> methods = byAnnotationType.getOrDefault(annotationClass, new HashMap<>());
|
||||
methods.put(method, annotation);
|
||||
byAnnotationType.put(annotationClass, methods);
|
||||
}
|
||||
|
||||
public <T extends Annotation> Map<Method, T> getMethodAnnotations(Class<T> ofType) {
|
||||
return (Map<Method, T>) byAnnotationType.getOrDefault(ofType, new HashMap<>());
|
||||
}
|
||||
|
||||
public <T extends Annotation> Collection<T> getAnnotations(Class<T> ofType) {
|
||||
return getMethodAnnotations(ofType).values();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return byAnnotationType.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MethodAnnotations{" + byAnnotationType + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.icon;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Enum to determine what color to use for some element.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public enum Color {
|
||||
|
||||
RED,
|
||||
PINK,
|
||||
PURPLE,
|
||||
DEEP_PURPLE,
|
||||
INDIGO,
|
||||
BLUE,
|
||||
LIGHT_BLUE,
|
||||
CYAN,
|
||||
TEAL,
|
||||
GREEN,
|
||||
LIGHT_GREEN,
|
||||
LIME,
|
||||
YELLOW,
|
||||
AMBER,
|
||||
ORANGE,
|
||||
DEEP_ORANGE,
|
||||
BROWN,
|
||||
GREY,
|
||||
BLUE_GREY,
|
||||
BLACK,
|
||||
NONE;
|
||||
|
||||
public static Optional<Color> getByName(String name) {
|
||||
try {
|
||||
return Optional.of(valueOf(name));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.icon;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Enum to determine font-awesome icon family.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public enum Family {
|
||||
SOLID,
|
||||
REGULAR,
|
||||
BRAND;
|
||||
|
||||
public static Optional<Family> getByName(String name) {
|
||||
try {
|
||||
return Optional.of(valueOf(name));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.icon;
|
||||
|
||||
/**
|
||||
* Object that represents an icon on the website.
|
||||
* <p>
|
||||
* See https://fontawesome.com/icons?d=gallery&m=free for icons and their {@link Family}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class Icon {
|
||||
|
||||
private Family type;
|
||||
private String name;
|
||||
private Color color;
|
||||
|
||||
private Icon() {
|
||||
type = Family.SOLID;
|
||||
color = Color.NONE;
|
||||
}
|
||||
|
||||
public Icon(Family type, String name, Color color) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public static Builder called(String name) {
|
||||
return new Builder().called(name);
|
||||
}
|
||||
|
||||
public static Builder of(Family type) {
|
||||
return new Builder().of(type);
|
||||
}
|
||||
|
||||
public static Builder of(Color color) {
|
||||
return new Builder().of(color);
|
||||
}
|
||||
|
||||
public Family getFamily() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Icon{" + type.name() + ", '" + name + '\'' + ", " + color.name() + '}';
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private final Icon icon;
|
||||
|
||||
Builder() {
|
||||
this.icon = new Icon();
|
||||
}
|
||||
|
||||
public Builder called(String name) {
|
||||
icon.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder of(Color color) {
|
||||
icon.color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder of(Family type) {
|
||||
icon.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Icon build() {
|
||||
if (icon.name == null) {
|
||||
throw new IllegalStateException("'name' was not defined yet!");
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.extractor;
|
||||
|
||||
import com.djrapitops.plan.extension.DataExtension;
|
||||
import com.djrapitops.plan.extension.annotation.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.platform.runner.JUnitPlatform;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* Tests for different validations of ExtensionExtractor.
|
||||
* <p>
|
||||
* This Test class contains only INVALID implementations of the DataExtension API.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@RunWith(JUnitPlatform.class)
|
||||
class ExtensionExtractorTest {
|
||||
|
||||
@Test
|
||||
void pluginInfoIsRequired() {
|
||||
class Extension implements DataExtension {}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Given class had no PluginInfo annotation", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void providerMethodsAreRequired() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension class had no methods annotated with a Provider annotation", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void publicProviderMethodsAreRequired() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@BooleanProvider(text = "Banned")
|
||||
private boolean method(UUID playerUUID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension class had no methods annotated with a Provider annotation", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void pluginInfoNameOver50Chars() {
|
||||
@PluginInfo(name = "five five five five five five five five five five -")
|
||||
class Extension implements DataExtension {
|
||||
@BooleanProvider(text = "Required Provider")
|
||||
public boolean method() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Warnings: [Extension PluginInfo 'name' was over 50 characters.]", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanProviderMustReturnBoolean() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@BooleanProvider(text = "Banned")
|
||||
public String method(UUID playerUUID) {
|
||||
return "false";
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.String, expected: boolean", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanProviderMustReturnPrimitiveBoolean() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@BooleanProvider(text = "Banned")
|
||||
public Boolean method(UUID playerUUID) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.Boolean, expected: boolean", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void numberProviderMustReturnPrimitiveLong() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@NumberProvider(text = "Achievements")
|
||||
public Long method(UUID playerUUID) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.Long, expected: long", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void doubleProviderMustReturnPrimitiveDouble() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@DoubleProvider(text = "Money")
|
||||
public Double method(UUID playerUUID) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.Double, expected: double", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void percentageProviderMustReturnPrimitiveDouble() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@PercentageProvider(text = "Achievements awarded")
|
||||
public Double method(UUID playerUUID) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.Double, expected: double", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void stringProviderMustReturnString() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@StringProvider(text = "Town")
|
||||
public Double method(UUID playerUUID) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid return type. was: java.lang.Double, expected: java.lang.String", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void booleanProviderCanNotSupplyItsOwnConditional() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@Conditional("hasJoined")
|
||||
@BooleanProvider(text = "Banned", conditionName = "hasJoined")
|
||||
public boolean method(UUID playerUUID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Warnings: [Extension.method can not be conditional of itself. required condition: hasJoined, provided condition: hasJoined]", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void conditionalMethodRequiresProvider() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@Conditional("hasJoined")
|
||||
public boolean method(UUID playerUUID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method did not have any associated Provider for Conditional.", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void conditionalNeedsToBeProvided() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@Conditional("hasJoined")
|
||||
@BooleanProvider(text = "Banned", conditionName = "isBanned")
|
||||
public boolean method(UUID playerUUID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Warnings: [Extension: 'hasJoined' Condition was not provided by any BooleanProvider.]", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodNeedsValidParameters() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@Conditional("hasJoined")
|
||||
@BooleanProvider(text = "Banned", conditionName = "isBanned")
|
||||
public boolean method(Integer invalid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has invalid parameter: 'java.lang.Integer' one of [class java.util.UUID, class java.lang.String, interface com.djrapitops.plan.extension.Group] is required as a parameter.", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodHasTooManyParameters() {
|
||||
@PluginInfo(name = "Extension")
|
||||
class Extension implements DataExtension {
|
||||
@Conditional("hasJoined")
|
||||
@BooleanProvider(text = "Banned", conditionName = "isBanned")
|
||||
public boolean method(String playerName, UUID playerUUID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionExtractor underTest = new ExtensionExtractor(new Extension());
|
||||
assertEquals("Extension.method has too many parameters, only one of [class java.util.UUID, class java.lang.String, interface com.djrapitops.plan.extension.Group] is required as a parameter.", assertThrows(IllegalArgumentException.class, underTest::validateAnnotations).getMessage());
|
||||
}
|
||||
|
||||
}
|
@ -4,13 +4,13 @@ dependencies {
|
||||
compile "com.djrapitops:AbstractPluginFramework-bukkit:$abstractPluginFrameworkVersion"
|
||||
compile "org.bstats:bstats-bukkit:$bstatsVersion"
|
||||
|
||||
compileOnly "com.destroystokyo.paper:paper-api:$paperVersion"
|
||||
compileOnly "org.spigotmc:spigot-api:$spigotVersion"
|
||||
compileOnly "org.bukkit:bukkit:$bukkitVersion"
|
||||
// compileOnly "org.spigotmc:spigot-api:$spigotVersion"
|
||||
// compileOnly "org.bukkit:bukkit:$bukkitVersion"
|
||||
compileOnly "com.destroystokyo.paper:paper-api:$paperVersion"
|
||||
|
||||
testCompile "com.destroystokyo.paper:paper-api:$paperVersion"
|
||||
testCompile "org.spigotmc:spigot-api:$spigotVersion"
|
||||
testCompile "org.bukkit:bukkit:$bukkitVersion"
|
||||
// testCompile "org.spigotmc:spigot-api:$spigotVersion"
|
||||
// testCompile "org.bukkit:bukkit:$bukkitVersion"
|
||||
testCompile "com.destroystokyo.paper:paper-api:$paperVersion"
|
||||
|
||||
testCompile project(path: ":common", configuration: 'testArtifacts')
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ public class CommandListener implements Listener {
|
||||
try {
|
||||
command = plugin.getServer().getCommandMap().getCommand(commandName);
|
||||
} catch (NoSuchMethodError ignored) {
|
||||
/* Ignored, Bukkit 1.8 has no such method */
|
||||
/* Ignored, Bukkit 1.8 has no such method. This method is from Paper */
|
||||
}
|
||||
}
|
||||
return command;
|
||||
|
@ -20,6 +20,8 @@ import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.data.store.objects.Nickname;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.events.*;
|
||||
import com.djrapitops.plan.extension.CallEvents;
|
||||
import com.djrapitops.plan.extension.ExtensionServiceImplementation;
|
||||
import com.djrapitops.plan.system.cache.GeolocationCache;
|
||||
import com.djrapitops.plan.system.cache.NicknameCache;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
@ -57,6 +59,7 @@ public class PlayerOnlineListener implements Listener {
|
||||
private final Processing processing;
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final ExtensionServiceImplementation extensionService;
|
||||
private final GeolocationCache geolocationCache;
|
||||
private final NicknameCache nicknameCache;
|
||||
private final SessionCache sessionCache;
|
||||
@ -70,6 +73,7 @@ public class PlayerOnlineListener implements Listener {
|
||||
Processing processing,
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
ExtensionServiceImplementation extensionService,
|
||||
GeolocationCache geolocationCache,
|
||||
NicknameCache nicknameCache,
|
||||
SessionCache sessionCache,
|
||||
@ -81,6 +85,7 @@ public class PlayerOnlineListener implements Listener {
|
||||
this.processing = processing;
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.extensionService = extensionService;
|
||||
this.geolocationCache = geolocationCache;
|
||||
this.nicknameCache = nicknameCache;
|
||||
this.sessionCache = sessionCache;
|
||||
@ -139,11 +144,11 @@ public class PlayerOnlineListener implements Listener {
|
||||
private void actOnJoinEvent(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
UUID uuid = player.getUniqueId();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
UUID serverUUID = serverInfo.getServerUUID();
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
AFKListener.AFK_TRACKER.performedAction(uuid, time);
|
||||
AFKListener.AFK_TRACKER.performedAction(playerUUID, time);
|
||||
|
||||
String world = player.getWorld().getName();
|
||||
String gm = player.getGameMode().name();
|
||||
@ -159,21 +164,29 @@ public class PlayerOnlineListener implements Listener {
|
||||
boolean gatheringGeolocations = config.isTrue(DataGatheringSettings.GEOLOCATIONS);
|
||||
if (gatheringGeolocations) {
|
||||
database.executeTransaction(
|
||||
new GeoInfoStoreTransaction(uuid, address, time, geolocationCache::getCountry)
|
||||
new GeoInfoStoreTransaction(playerUUID, address, time, geolocationCache::getCountry)
|
||||
);
|
||||
}
|
||||
|
||||
database.executeTransaction(new PlayerServerRegisterTransaction(uuid, player::getFirstPlayed, playerName, serverUUID));
|
||||
sessionCache.cacheSession(uuid, new Session(uuid, serverUUID, time, world, gm))
|
||||
database.executeTransaction(new PlayerServerRegisterTransaction(playerUUID, player::getFirstPlayed, playerName, serverUUID));
|
||||
sessionCache.cacheSession(playerUUID, new Session(playerUUID, serverUUID, time, world, gm))
|
||||
.ifPresent(previousSession -> database.executeTransaction(new SessionEndTransaction(previousSession)));
|
||||
|
||||
database.executeTransaction(new NicknameStoreTransaction(
|
||||
uuid, new Nickname(displayName, time, serverUUID),
|
||||
(playerUUID, name) -> name.equals(nicknameCache.getDisplayName(playerUUID))
|
||||
playerUUID, new Nickname(displayName, time, serverUUID),
|
||||
(uuid, name) -> name.equals(nicknameCache.getDisplayName(uuid))
|
||||
));
|
||||
|
||||
processing.submitNonCritical(processors.info().playerPageUpdateProcessor(uuid));
|
||||
processing.submitNonCritical(processors.info().playerPageUpdateProcessor(playerUUID));
|
||||
processing.submitNonCritical(() -> extensionService.updatePlayerValues(playerUUID, playerName, CallEvents.PLAYER_JOIN));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void beforePlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
String playerName = player.getName();
|
||||
processing.submitNonCritical(() -> extensionService.updatePlayerValues(playerUUID, playerName, CallEvents.PLAYER_LEAVE));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
|
@ -19,6 +19,7 @@ package com.djrapitops.plan.system.tasks;
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.ShutdownHook;
|
||||
import com.djrapitops.plan.db.tasks.DBCleanTask;
|
||||
import com.djrapitops.plan.extension.ExtensionServerMethodCallerTask;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plan.system.tasks.bukkit.BukkitTPSCountTimer;
|
||||
@ -50,6 +51,7 @@ public class BukkitTaskSystem extends ServerTaskSystem {
|
||||
private final PingCountTimerBukkit pingCountTimer;
|
||||
private final ConfigStoreTask configStoreTask;
|
||||
private final DBCleanTask dbCleanTask;
|
||||
private final ExtensionServerMethodCallerTask extensionServerMethodCallerTask;
|
||||
|
||||
@Inject
|
||||
public BukkitTaskSystem(
|
||||
@ -65,7 +67,8 @@ public class BukkitTaskSystem extends ServerTaskSystem {
|
||||
LogsFolderCleanTask logsFolderCleanTask,
|
||||
PlayersPageRefreshTask playersPageRefreshTask,
|
||||
ConfigStoreTask configStoreTask,
|
||||
DBCleanTask dbCleanTask
|
||||
DBCleanTask dbCleanTask,
|
||||
ExtensionServerMethodCallerTask extensionServerMethodCallerTask
|
||||
) {
|
||||
super(
|
||||
runnableFactory,
|
||||
@ -80,6 +83,7 @@ public class BukkitTaskSystem extends ServerTaskSystem {
|
||||
this.pingCountTimer = pingCountTimer;
|
||||
this.configStoreTask = configStoreTask;
|
||||
this.dbCleanTask = dbCleanTask;
|
||||
this.extensionServerMethodCallerTask = extensionServerMethodCallerTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -88,20 +92,24 @@ public class BukkitTaskSystem extends ServerTaskSystem {
|
||||
try {
|
||||
plugin.registerListener(pingCountTimer);
|
||||
long startDelay = TimeAmount.toTicks(config.get(TimeSettings.PING_SERVER_ENABLE_DELAY), TimeUnit.MILLISECONDS);
|
||||
registerTask("PingCountTimer", pingCountTimer)
|
||||
.runTaskTimer(startDelay, 40L);
|
||||
|
||||
// +40 ticks / 2 seconds so that update check task runs first.
|
||||
long storeDelay = TimeAmount.toTicks(config.get(TimeSettings.CONFIG_UPDATE_INTERVAL), TimeUnit.MILLISECONDS) + 40;
|
||||
registerTask("Config Store Task", configStoreTask).runTaskLaterAsynchronously(storeDelay);
|
||||
|
||||
registerTask("DB Clean Task", dbCleanTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(20, TimeUnit.SECONDS),
|
||||
TimeAmount.toTicks(config.get(TimeSettings.CLEAN_DATABASE_PERIOD), TimeUnit.MILLISECONDS)
|
||||
);
|
||||
registerTask(pingCountTimer).runTaskTimer(startDelay, 40L);
|
||||
} catch (ExceptionInInitializerError | NoClassDefFoundError ignore) {
|
||||
// Running CraftBukkit
|
||||
}
|
||||
|
||||
// +40 ticks / 2 seconds so that update check task runs first.
|
||||
long storeDelay = TimeAmount.toTicks(config.get(TimeSettings.CONFIG_UPDATE_INTERVAL), TimeUnit.MILLISECONDS) + 40;
|
||||
registerTask(configStoreTask).runTaskLaterAsynchronously(storeDelay);
|
||||
|
||||
registerTask(dbCleanTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(20, TimeUnit.SECONDS),
|
||||
TimeAmount.toTicks(config.get(TimeSettings.CLEAN_DATABASE_PERIOD), TimeUnit.MILLISECONDS)
|
||||
);
|
||||
|
||||
long extensionRefreshPeriod = TimeAmount.toTicks(config.get(TimeSettings.EXTENSION_DATA_REFRESH_PERIOD), TimeUnit.MILLISECONDS);
|
||||
registerTask(extensionServerMethodCallerTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(30, TimeUnit.SECONDS), extensionRefreshPeriod
|
||||
);
|
||||
shutdownHook.register();
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@ public class PaperTPSCountTimer extends BukkitTPSCountTimer {
|
||||
try {
|
||||
tps = plugin.getServer().getTPS()[0];
|
||||
} catch (NoSuchMethodError e) {
|
||||
// This method is from Paper
|
||||
return super.getTPS(diff, now, cpuUsage, usedMemory, entityCount, chunksLoaded, playersOnline, freeDiskSpace);
|
||||
}
|
||||
|
||||
|
@ -175,6 +175,7 @@ public class PingCountTimerBukkit extends AbsRunnable implements Listener {
|
||||
|
||||
private int getPing(Player player) {
|
||||
if (PING_METHOD_AVAILABLE) {
|
||||
// This method is from Paper
|
||||
return player.spigot().getPing();
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,8 @@ import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.events.GeoInfoStoreTransaction;
|
||||
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
|
||||
import com.djrapitops.plan.extension.CallEvents;
|
||||
import com.djrapitops.plan.extension.ExtensionServiceImplementation;
|
||||
import com.djrapitops.plan.system.cache.GeolocationCache;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
@ -38,6 +40,7 @@ import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.net.InetAddress;
|
||||
@ -54,6 +57,7 @@ public class PlayerOnlineListener implements Listener {
|
||||
private final Processors processors;
|
||||
private final Processing processing;
|
||||
private final DBSystem dbSystem;
|
||||
private final ExtensionServiceImplementation extensionService;
|
||||
private final GeolocationCache geolocationCache;
|
||||
private final SessionCache sessionCache;
|
||||
private final ServerInfo serverInfo;
|
||||
@ -65,6 +69,7 @@ public class PlayerOnlineListener implements Listener {
|
||||
Processors processors,
|
||||
Processing processing,
|
||||
DBSystem dbSystem,
|
||||
ExtensionServiceImplementation extensionService,
|
||||
GeolocationCache geolocationCache,
|
||||
SessionCache sessionCache,
|
||||
ServerInfo serverInfo,
|
||||
@ -74,18 +79,19 @@ public class PlayerOnlineListener implements Listener {
|
||||
this.processors = processors;
|
||||
this.processing = processing;
|
||||
this.dbSystem = dbSystem;
|
||||
this.extensionService = extensionService;
|
||||
this.geolocationCache = geolocationCache;
|
||||
this.sessionCache = sessionCache;
|
||||
this.serverInfo = serverInfo;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPostLogin(PostLoginEvent event) {
|
||||
try {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
String name = player.getName();
|
||||
String playerName = player.getName();
|
||||
InetAddress address = player.getAddress().getAddress();
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
@ -99,15 +105,24 @@ public class PlayerOnlineListener implements Listener {
|
||||
);
|
||||
}
|
||||
|
||||
database.executeTransaction(new PlayerRegisterTransaction(playerUUID, () -> time, name));
|
||||
database.executeTransaction(new PlayerRegisterTransaction(playerUUID, () -> time, playerName));
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(playerUUID));
|
||||
processing.submitNonCritical(() -> extensionService.updatePlayerValues(playerUUID, playerName, CallEvents.PLAYER_JOIN));
|
||||
ResponseCache.clearResponse(PageId.SERVER.of(serverInfo.getServerUUID()));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.WARN, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void beforeLogout(PlayerDisconnectEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
String playerName = player.getName();
|
||||
processing.submitNonCritical(() -> extensionService.updatePlayerValues(playerUUID, playerName, CallEvents.PLAYER_LEAVE));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onLogout(PlayerDisconnectEvent event) {
|
||||
try {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
@ -121,7 +136,7 @@ public class PlayerOnlineListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onServerSwitch(ServerSwitchEvent event) {
|
||||
try {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
|
@ -18,6 +18,7 @@ package com.djrapitops.plan.system.tasks;
|
||||
|
||||
import com.djrapitops.plan.PlanBungee;
|
||||
import com.djrapitops.plan.db.tasks.DBCleanTask;
|
||||
import com.djrapitops.plan.extension.ExtensionServerMethodCallerTask;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plan.system.tasks.bungee.BungeeTPSCountTimer;
|
||||
@ -47,6 +48,7 @@ public class BungeeTaskSystem extends TaskSystem {
|
||||
private final PlayersPageRefreshTask playersPageRefreshTask;
|
||||
private final NetworkConfigStoreTask networkConfigStoreTask;
|
||||
private final DBCleanTask dbCleanTask;
|
||||
private final ExtensionServerMethodCallerTask extensionServerMethodCallerTask;
|
||||
|
||||
@Inject
|
||||
public BungeeTaskSystem(
|
||||
@ -59,7 +61,8 @@ public class BungeeTaskSystem extends TaskSystem {
|
||||
LogsFolderCleanTask logsFolderCleanTask,
|
||||
PlayersPageRefreshTask playersPageRefreshTask,
|
||||
NetworkConfigStoreTask networkConfigStoreTask,
|
||||
DBCleanTask dbCleanTask
|
||||
DBCleanTask dbCleanTask,
|
||||
ExtensionServerMethodCallerTask extensionServerMethodCallerTask
|
||||
) {
|
||||
super(runnableFactory, bungeeTPSCountTimer);
|
||||
this.plugin = plugin;
|
||||
@ -71,6 +74,7 @@ public class BungeeTaskSystem extends TaskSystem {
|
||||
this.playersPageRefreshTask = playersPageRefreshTask;
|
||||
this.networkConfigStoreTask = networkConfigStoreTask;
|
||||
this.dbCleanTask = dbCleanTask;
|
||||
this.extensionServerMethodCallerTask = extensionServerMethodCallerTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -85,18 +89,23 @@ public class BungeeTaskSystem extends TaskSystem {
|
||||
|
||||
plugin.registerListener(pingCountTimer);
|
||||
long startDelay = TimeAmount.toTicks(config.get(TimeSettings.PING_SERVER_ENABLE_DELAY), TimeUnit.MILLISECONDS);
|
||||
runnableFactory.create("PingCountTimer", pingCountTimer).runTaskTimer(startDelay, PingCountTimerBungee.PING_INTERVAL);
|
||||
registerTask(pingCountTimer).runTaskTimer(startDelay, PingCountTimerBungee.PING_INTERVAL);
|
||||
|
||||
registerTask(playersPageRefreshTask)
|
||||
.runTaskTimerAsynchronously(TimeAmount.toTicks(5L, TimeUnit.MINUTES), TimeAmount.toTicks(5L, TimeUnit.MINUTES));
|
||||
|
||||
// +40 ticks / 2 seconds so that update check task runs first.
|
||||
long storeDelay = TimeAmount.toTicks(config.get(TimeSettings.CONFIG_UPDATE_INTERVAL), TimeUnit.MILLISECONDS) + 40;
|
||||
registerTask("Config Store Task", networkConfigStoreTask).runTaskLaterAsynchronously(storeDelay);
|
||||
registerTask(networkConfigStoreTask).runTaskLaterAsynchronously(storeDelay);
|
||||
|
||||
registerTask("DB Clean Task", dbCleanTask).runTaskTimerAsynchronously(
|
||||
registerTask(dbCleanTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(20, TimeUnit.SECONDS),
|
||||
TimeAmount.toTicks(config.get(TimeSettings.CLEAN_DATABASE_PERIOD), TimeUnit.MILLISECONDS)
|
||||
);
|
||||
|
||||
long extensionRefreshPeriod = TimeAmount.toTicks(config.get(TimeSettings.EXTENSION_DATA_REFRESH_PERIOD), TimeUnit.MILLISECONDS);
|
||||
registerTask(extensionServerMethodCallerTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(30, TimeUnit.SECONDS), extensionRefreshPeriod
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
dependencies {
|
||||
compile "com.djrapitops:AbstractPluginFramework-api:$abstractPluginFrameworkVersion"
|
||||
compile project(path: ":api", configuration: 'shadow')
|
||||
compile project(path: ":extensions", configuration: 'shadow')
|
||||
compile "com.djrapitops:PlanPluginBridge:$planPluginBridgeVersion"
|
||||
compile "org.apache.httpcomponents:httpclient:$httpClientVersion"
|
||||
compile "org.apache.commons:commons-text:$commonsTextVersion"
|
||||
@ -11,6 +13,8 @@ dependencies {
|
||||
compile "org.slf4j:slf4j-api:$slf4jVersion"
|
||||
compile "com.maxmind.geoip2:geoip2:$geoIpVersion"
|
||||
compileOnly "com.google.guava:guava:$guavaVersion"
|
||||
|
||||
testCompile project(path: ":api", configuration: 'shadow')
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
|
@ -95,7 +95,7 @@ public class TableContainer {
|
||||
Serializable value = row[i];
|
||||
Formatter formatter = formatters[i];
|
||||
body.append("<td").append(formatter != null ? " data-order=\"" + value + "\">" : ">");
|
||||
body.append(formatter != null ? formatter.apply(value) : value);
|
||||
body.append(formatter != null ? formatter.apply(value) : (value != null ? value : '-'));
|
||||
}
|
||||
body.append("</td>");
|
||||
} catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
|
||||
|
@ -38,8 +38,11 @@ public class PluginsConfigSection {
|
||||
}
|
||||
|
||||
public boolean hasSection(PluginData dataSource) {
|
||||
return hasSection(dataSource.getSourcePlugin());
|
||||
}
|
||||
|
||||
public boolean hasSection(String pluginName) {
|
||||
ConfigNode section = getPluginsSection();
|
||||
String pluginName = dataSource.getSourcePlugin();
|
||||
return section.getNode(pluginName + ".Enabled").isPresent();
|
||||
}
|
||||
|
||||
@ -49,8 +52,11 @@ public class PluginsConfigSection {
|
||||
}
|
||||
|
||||
public void createSection(PluginData dataSource) throws IOException {
|
||||
createSection(dataSource.getSourcePlugin());
|
||||
}
|
||||
|
||||
public void createSection(String pluginName) throws IOException {
|
||||
ConfigNode section = getPluginsSection();
|
||||
String pluginName = dataSource.getSourcePlugin();
|
||||
|
||||
section.set(pluginName + ".Enabled", true);
|
||||
section.sort();
|
||||
@ -58,9 +64,11 @@ public class PluginsConfigSection {
|
||||
}
|
||||
|
||||
public boolean isEnabled(PluginData dataSource) {
|
||||
ConfigNode section = getPluginsSection();
|
||||
return isEnabled(dataSource.getSourcePlugin());
|
||||
}
|
||||
|
||||
String pluginName = dataSource.getSourcePlugin();
|
||||
public boolean isEnabled(String pluginName) {
|
||||
ConfigNode section = getPluginsSection();
|
||||
return section.getBoolean(pluginName + ".Enabled");
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ import com.djrapitops.plan.utilities.html.graphs.bar.BarGraph;
|
||||
import com.djrapitops.plan.utilities.html.graphs.line.PingGraph;
|
||||
import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie;
|
||||
import com.djrapitops.plan.utilities.html.graphs.stack.StackGraph;
|
||||
import com.djrapitops.plan.utilities.html.pages.AnalysisPluginTabs;
|
||||
import com.djrapitops.plan.utilities.html.structure.Accordions;
|
||||
import com.djrapitops.plan.utilities.html.structure.AnalysisPluginsTabContentCreator;
|
||||
import com.djrapitops.plan.utilities.html.structure.RecentLoginList;
|
||||
@ -488,13 +489,14 @@ public class AnalysisContainer extends DynamicDataContainer {
|
||||
|
||||
private void addPluginSuppliers() {
|
||||
// TODO Refactor into a system that supports running the analysis on Bungee
|
||||
Key<String[]> navAndTabs = new Key<>(new Type<String[]>() {
|
||||
}, "NAV_AND_TABS");
|
||||
Key<String[]> navAndTabs = new Key<>(new Type<String[]>() {}, "NAV_AND_TABS");
|
||||
Key<AnalysisPluginTabs> pluginTabs = new Key<>(AnalysisPluginTabs.class, "PLUGIN_TABS");
|
||||
putCachingSupplier(navAndTabs, () -> pluginsTabContentCreator.createContent(
|
||||
this, getValue(AnalysisKeys.PLAYERS_MUTATOR).orElse(new PlayersMutator(new ArrayList<>()))
|
||||
));
|
||||
putSupplier(AnalysisKeys.PLUGINS_TAB_NAV, () -> getUnsafe(navAndTabs)[0]);
|
||||
putSupplier(AnalysisKeys.PLUGINS_TAB, () -> getUnsafe(navAndTabs)[1]);
|
||||
putCachingSupplier(pluginTabs, () -> new AnalysisPluginTabs(serverContainer.getValue(ServerKeys.EXTENSION_DATA).orElse(new ArrayList<>()), formatters));
|
||||
putSupplier(AnalysisKeys.PLUGINS_TAB_NAV, () -> getUnsafe(pluginTabs).getNav() + getUnsafe(navAndTabs)[0]);
|
||||
putSupplier(AnalysisKeys.PLUGINS_TAB, () -> getUnsafe(pluginTabs).getTabs() + getUnsafe(navAndTabs)[1]);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
|
@ -25,6 +25,7 @@ import com.djrapitops.plan.data.store.Type;
|
||||
import com.djrapitops.plan.data.store.containers.PlayerContainer;
|
||||
import com.djrapitops.plan.data.store.objects.DateObj;
|
||||
import com.djrapitops.plan.data.time.WorldTimes;
|
||||
import com.djrapitops.plan.extension.implementation.results.server.ExtensionServerData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -63,4 +64,5 @@ public class ServerKeys {
|
||||
public static final Key<DateObj<Integer>> ALL_TIME_PEAK_PLAYERS = new Key<>(new Type<DateObj<Integer>>() {}, "all_time_peak_players");
|
||||
public static final Key<DateObj<Integer>> RECENT_PEAK_PLAYERS = new Key<>(new Type<DateObj<Integer>>() {}, "recent_peak_players");
|
||||
public static final Key<Map<String, Integer>> COMMAND_USAGE = new Key<>(new Type<Map<String, Integer>>() {}, "command_usage");
|
||||
public static final Key<List<ExtensionServerData>> EXTENSION_DATA = new Key<>(new Type<List<ExtensionServerData>>() {}, "extension_data");
|
||||
}
|
@ -26,6 +26,7 @@ import com.djrapitops.plan.db.access.transactions.init.CreateIndexTransaction;
|
||||
import com.djrapitops.plan.db.access.transactions.init.CreateTablesTransaction;
|
||||
import com.djrapitops.plan.db.access.transactions.init.OperationCriticalTransaction;
|
||||
import com.djrapitops.plan.db.patches.*;
|
||||
import com.djrapitops.plan.system.DebugChannels;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
@ -219,6 +220,7 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
accessLock.checkAccess(transaction);
|
||||
logger.getDebugLogger().logOn(DebugChannels.SQL, "Executing: " + transaction.getClass().getSimpleName());
|
||||
transaction.executeTransaction(this);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}, getTransactionExecutor()).handle(errorHandler(origin));
|
||||
|
@ -27,6 +27,7 @@ import com.djrapitops.plan.db.access.queries.ServerAggregateQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.TPSQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.WorldTimesQueries;
|
||||
import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionServerDataQuery;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.info.server.Server;
|
||||
|
||||
@ -95,6 +96,8 @@ public class ServerContainerQuery implements Query<ServerContainer> {
|
||||
container.putCachingSupplier(ServerKeys.MOB_KILL_COUNT, () -> SessionsMutator.forContainer(container).toMobKillCount());
|
||||
container.putCachingSupplier(ServerKeys.DEATH_COUNT, () -> SessionsMutator.forContainer(container).toDeathCount());
|
||||
|
||||
container.putCachingSupplier(ServerKeys.EXTENSION_DATA, () -> db.query(new ExtensionServerDataQuery(serverUUID)));
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
@ -141,9 +141,11 @@ public abstract class Transaction {
|
||||
|
||||
protected void executeOther(Transaction transaction) {
|
||||
transaction.db = db;
|
||||
transaction.dbType = dbType;
|
||||
transaction.connection = this.connection;
|
||||
transaction.performOperations();
|
||||
transaction.connection = null;
|
||||
transaction.dbType = null;
|
||||
transaction.db = null;
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,12 @@ public class RemoveEverythingTransaction extends Transaction {
|
||||
clearTable(TPSTable.TABLE_NAME);
|
||||
clearTable(SecurityTable.TABLE_NAME);
|
||||
clearTable(ServerTable.TABLE_NAME);
|
||||
clearTable(ExtensionPlayerValueTable.TABLE_NAME);
|
||||
clearTable(ExtensionServerValueTable.TABLE_NAME);
|
||||
clearTable(ExtensionProviderTable.TABLE_NAME);
|
||||
clearTable(ExtensionTabTable.TABLE_NAME);
|
||||
clearTable(ExtensionPluginTable.TABLE_NAME);
|
||||
clearTable(ExtensionIconTable.TABLE_NAME);
|
||||
}
|
||||
|
||||
private void clearTable(String tableName) {
|
||||
|
@ -27,6 +27,7 @@ import com.djrapitops.plan.db.access.transactions.commands.RemovePlayerTransacti
|
||||
import com.djrapitops.plan.db.sql.tables.PingTable;
|
||||
import com.djrapitops.plan.db.sql.tables.SessionsTable;
|
||||
import com.djrapitops.plan.db.sql.tables.TPSTable;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.RemoveUnsatisfiedConditionalResultsTransaction;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.PluginLang;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
@ -73,6 +74,9 @@ public class CleanTransaction extends Transaction {
|
||||
execute(cleanTPSTable(allTimePeak.orElse(-1)));
|
||||
execute(cleanPingTable());
|
||||
|
||||
// Clean DataExtension data
|
||||
executeOther(new RemoveUnsatisfiedConditionalResultsTransaction());
|
||||
|
||||
int removed = cleanOldPlayers();
|
||||
if (removed > 0) {
|
||||
logger.info(locale.getString(PluginLang.DB_NOTIFY_CLEAN, removed));
|
||||
|
@ -45,5 +45,13 @@ public class CreateTablesTransaction extends OperationCriticalTransaction {
|
||||
execute(WorldTimesTable.createTableSQL(dbType));
|
||||
execute(SecurityTable.createTableSQL(dbType));
|
||||
execute(SettingsTable.createTableSQL(dbType));
|
||||
|
||||
// DataExtension tables
|
||||
execute(ExtensionIconTable.createTableSQL(dbType));
|
||||
execute(ExtensionPluginTable.createTableSQL(dbType));
|
||||
execute(ExtensionTabTable.createTableSQL(dbType));
|
||||
execute(ExtensionProviderTable.createTableSQL(dbType));
|
||||
execute(ExtensionPlayerValueTable.createTableSQL(dbType));
|
||||
execute(ExtensionServerValueTable.createTableSQL(dbType));
|
||||
}
|
||||
}
|
@ -29,7 +29,11 @@ public class Sql {
|
||||
public static final String GROUP_BY = " GROUP BY ";
|
||||
public static final String ORDER_BY = " ORDER BY ";
|
||||
public static final String INNER_JOIN = " INNER JOIN ";
|
||||
public static final String LEFT_JOIN = " LEFT JOIN ";
|
||||
public static final String AND = " AND ";
|
||||
public static final String OR = " OR ";
|
||||
public static final String IS_NULL = " IS NULL";
|
||||
public static final String IS_NOT_NULL = " IS NOT NULL";
|
||||
|
||||
private Sql() {
|
||||
throw new IllegalStateException("Variable Class");
|
||||
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.db.sql.tables;
|
||||
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.sql.parsing.CreateTableParser;
|
||||
import com.djrapitops.plan.db.sql.parsing.Sql;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Table information about 'plan_extension_icons'.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionIconTable {
|
||||
|
||||
public static final String TABLE_NAME = "plan_extension_icons";
|
||||
|
||||
public static final String ID = "id";
|
||||
public static final String ICON_NAME = "name";
|
||||
public static final String FAMILY = "family";
|
||||
public static final String COLOR = "color";
|
||||
|
||||
public static final String STATEMENT_SELECT_ICON_ID = "(" + SELECT + ID +
|
||||
FROM + TABLE_NAME +
|
||||
WHERE + ICON_NAME + "=?" +
|
||||
AND + FAMILY + "=?" +
|
||||
AND + COLOR + "=?)";
|
||||
|
||||
public static void set3IconValuesToStatement(PreparedStatement statement, Icon icon) throws SQLException {
|
||||
set3IconValuesToStatement(statement, 1, icon);
|
||||
}
|
||||
|
||||
public static void set3IconValuesToStatement(PreparedStatement statement, int parameterIndex, Icon icon) throws SQLException {
|
||||
statement.setString(parameterIndex, StringUtils.truncate(icon.getName(), 50));
|
||||
statement.setString(parameterIndex + 1, icon.getFamily().name());
|
||||
statement.setString(parameterIndex + 2, icon.getColor().name());
|
||||
}
|
||||
|
||||
private ExtensionIconTable() {
|
||||
/* Static information class */
|
||||
}
|
||||
|
||||
public static String createTableSQL(DBType dbType) {
|
||||
return CreateTableParser.create(TABLE_NAME, dbType)
|
||||
.column(ID, INT).primaryKey()
|
||||
.column(ICON_NAME, Sql.varchar(50)).notNull().defaultValue("'question'")
|
||||
.column(FAMILY, Sql.varchar(15)).notNull().defaultValue("'" + Family.SOLID.name() + "'")
|
||||
.column(COLOR, Sql.varchar(25)).notNull().defaultValue("'" + Color.NONE.name() + "'")
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.db.sql.tables;
|
||||
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.sql.parsing.CreateTableParser;
|
||||
import com.djrapitops.plan.db.sql.parsing.Sql;
|
||||
|
||||
/**
|
||||
* Table information about 'plan_extension_user_values'.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionPlayerValueTable {
|
||||
|
||||
public static final String TABLE_NAME = "plan_extension_user_values";
|
||||
|
||||
public static final String ID = "id";
|
||||
public static final String PROVIDER_ID = "provider_id";
|
||||
public static final String USER_UUID = "uuid";
|
||||
|
||||
public static final String BOOLEAN_VALUE = "boolean_value";
|
||||
public static final String DOUBLE_VALUE = "double_value";
|
||||
public static final String PERCENTAGE_VALUE = "percentage_value";
|
||||
public static final String LONG_VALUE = "long_value";
|
||||
public static final String STRING_VALUE = "string_value";
|
||||
public static final String GROUP_VALUE = "group_value";
|
||||
|
||||
private ExtensionPlayerValueTable() {
|
||||
/* Static information class */
|
||||
}
|
||||
|
||||
public static String createTableSQL(DBType dbType) {
|
||||
return CreateTableParser.create(TABLE_NAME, dbType)
|
||||
.column(ID, Sql.INT).primaryKey()
|
||||
.column(BOOLEAN_VALUE, Sql.BOOL)
|
||||
.column(DOUBLE_VALUE, Sql.DOUBLE)
|
||||
.column(PERCENTAGE_VALUE, Sql.DOUBLE)
|
||||
.column(LONG_VALUE, Sql.LONG)
|
||||
.column(STRING_VALUE, Sql.varchar(50))
|
||||
.column(GROUP_VALUE, Sql.varchar(50))
|
||||
.column(USER_UUID, Sql.varchar(36)).notNull()
|
||||
.column(PROVIDER_ID, Sql.INT).notNull()
|
||||
.foreignKey(PROVIDER_ID, ExtensionProviderTable.TABLE_NAME, ExtensionProviderTable.ID)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.db.sql.tables;
|
||||
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.sql.parsing.CreateTableParser;
|
||||
import com.djrapitops.plan.db.sql.parsing.Sql;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Table information about 'plan_extension_plugins'.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionPluginTable {
|
||||
|
||||
public static final String TABLE_NAME = "plan_extension_plugins";
|
||||
|
||||
public static final String ID = "id";
|
||||
public static final String PLUGIN_NAME = "name";
|
||||
public static final String LAST_UPDATED = "last_updated";
|
||||
public static final String SERVER_UUID = "server_uuid";
|
||||
public static final String ICON_ID = "icon_id";
|
||||
|
||||
public static final String STATEMENT_SELECT_PLUGIN_ID = "(" + SELECT + ID +
|
||||
FROM + TABLE_NAME +
|
||||
WHERE + PLUGIN_NAME + "=?" +
|
||||
AND + SERVER_UUID + "=?)";
|
||||
|
||||
public static void set2PluginValuesToStatement(PreparedStatement statement, int parameterIndex, String pluginName, UUID serverUUID) throws SQLException {
|
||||
statement.setString(parameterIndex, pluginName);
|
||||
statement.setString(parameterIndex + 1, serverUUID.toString());
|
||||
}
|
||||
|
||||
private ExtensionPluginTable() {
|
||||
/* Static information class */
|
||||
}
|
||||
|
||||
public static String createTableSQL(DBType dbType) {
|
||||
return CreateTableParser.create(TABLE_NAME, dbType)
|
||||
.column(ID, INT).primaryKey()
|
||||
.column(PLUGIN_NAME, Sql.varchar(50)).notNull()
|
||||
.column(LAST_UPDATED, LONG).notNull()
|
||||
.column(SERVER_UUID, Sql.varchar(36)).notNull()
|
||||
.column(ICON_ID, INT).notNull()
|
||||
.foreignKey(ICON_ID, ExtensionIconTable.TABLE_NAME, ExtensionIconTable.ID)
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.db.sql.tables;
|
||||
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.sql.parsing.CreateTableParser;
|
||||
import com.djrapitops.plan.db.sql.parsing.Sql;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Table information about 'plan_extension_providers'.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionProviderTable {
|
||||
|
||||
public static final String TABLE_NAME = "plan_extension_providers";
|
||||
|
||||
public static final String ID = "id";
|
||||
public static final String PROVIDER_NAME = "name";
|
||||
public static final String TEXT = "text"; // Can be null
|
||||
public static final String DESCRIPTION = "description"; // Can be null
|
||||
public static final String PRIORITY = "priority";
|
||||
public static final String GROUPABLE = "groupable"; // default false
|
||||
public static final String CONDITION = "condition_name"; // Can be null, related to @Conditional
|
||||
public static final String PLUGIN_ID = "plugin_id";
|
||||
public static final String ICON_ID = "icon_id";
|
||||
public static final String TAB_ID = "tab_id"; // Can be null, related to @Tab
|
||||
|
||||
public static final String HIDDEN = "hidden"; // default false, related to @BooleanProvider
|
||||
public static final String PROVIDED_CONDITION = "provided_condition"; // Can be null, related to @BooleanProvider
|
||||
public static final String FORMAT_TYPE = "format_type"; // Can be null, related to @NumberProvider
|
||||
public static final String IS_PLAYER_NAME = "player_name"; // default false, related to @StringProvider
|
||||
|
||||
public static final String STATEMENT_SELECT_PROVIDER_ID = "(" + SELECT + ID + FROM + TABLE_NAME +
|
||||
WHERE + PROVIDER_NAME + "=?" +
|
||||
AND + PLUGIN_ID + "=" + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ")";
|
||||
|
||||
public static void set3PluginValuesToStatement(PreparedStatement statement, int parameterIndex, String providerName, String pluginName, UUID serverUUID) throws SQLException {
|
||||
statement.setString(parameterIndex, providerName);
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, parameterIndex + 1, pluginName, serverUUID);
|
||||
}
|
||||
|
||||
private ExtensionProviderTable() {
|
||||
/* Static information class */
|
||||
}
|
||||
|
||||
public static String createTableSQL(DBType dbType) {
|
||||
return CreateTableParser.create(TABLE_NAME, dbType)
|
||||
.column(ID, INT).primaryKey()
|
||||
.column(PROVIDER_NAME, Sql.varchar(50)).notNull()
|
||||
.column(TEXT, Sql.varchar(50)).notNull()
|
||||
.column(DESCRIPTION, Sql.varchar(150))
|
||||
.column(PRIORITY, INT).notNull().defaultValue("0")
|
||||
.column(GROUPABLE, BOOL).notNull().defaultValue(false)
|
||||
.column(CONDITION, Sql.varchar(54)) // 50 + 4 for "not_"
|
||||
.column(PROVIDED_CONDITION, Sql.varchar(50))
|
||||
.column(FORMAT_TYPE, Sql.varchar(25))
|
||||
.column(HIDDEN, BOOL).notNull().defaultValue(false)
|
||||
.column(IS_PLAYER_NAME, BOOL).notNull().defaultValue(false)
|
||||
.column(PLUGIN_ID, INT).notNull()
|
||||
.column(ICON_ID, INT).notNull()
|
||||
.column(TAB_ID, INT)
|
||||
.foreignKey(PLUGIN_ID, ExtensionPluginTable.TABLE_NAME, ExtensionPluginTable.ID)
|
||||
.foreignKey(ICON_ID, ExtensionIconTable.TABLE_NAME, ExtensionIconTable.ID)
|
||||
.foreignKey(TAB_ID, ExtensionTabTable.TABLE_NAME, ExtensionTabTable.ID)
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.db.sql.tables;
|
||||
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.sql.parsing.CreateTableParser;
|
||||
import com.djrapitops.plan.db.sql.parsing.Sql;
|
||||
|
||||
/**
|
||||
* Table information about 'plan_extension_server_values'.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionServerValueTable {
|
||||
|
||||
public static final String TABLE_NAME = "plan_extension_server_values";
|
||||
|
||||
public static final String ID = "id";
|
||||
public static final String PROVIDER_ID = "provider_id";
|
||||
// Server UUID can be figured out by limiting by Providers.
|
||||
|
||||
public static final String BOOLEAN_VALUE = "boolean_value";
|
||||
public static final String DOUBLE_VALUE = "double_value";
|
||||
public static final String PERCENTAGE_VALUE = "percentage_value";
|
||||
public static final String LONG_VALUE = "long_value";
|
||||
public static final String STRING_VALUE = "string_value";
|
||||
public static final String GROUP_VALUE = "group_value";
|
||||
|
||||
private ExtensionServerValueTable() {
|
||||
/* Static information class */
|
||||
}
|
||||
|
||||
public static String createTableSQL(DBType dbType) {
|
||||
return CreateTableParser.create(TABLE_NAME, dbType)
|
||||
.column(ID, Sql.INT).primaryKey()
|
||||
.column(BOOLEAN_VALUE, Sql.BOOL)
|
||||
.column(DOUBLE_VALUE, Sql.DOUBLE)
|
||||
.column(PERCENTAGE_VALUE, Sql.DOUBLE)
|
||||
.column(LONG_VALUE, Sql.LONG)
|
||||
.column(STRING_VALUE, Sql.varchar(50))
|
||||
.column(GROUP_VALUE, Sql.varchar(50))
|
||||
.column(PROVIDER_ID, Sql.INT).notNull()
|
||||
.foreignKey(PROVIDER_ID, ExtensionProviderTable.TABLE_NAME, ExtensionProviderTable.ID)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.db.sql.tables;
|
||||
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.sql.parsing.CreateTableParser;
|
||||
import com.djrapitops.plan.db.sql.parsing.Sql;
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Table information about 'plan_extension_tabs'.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionTabTable {
|
||||
|
||||
public static final String TABLE_NAME = "plan_extension_tabs";
|
||||
|
||||
public static final String ID = "id";
|
||||
public static final String TAB_NAME = "name";
|
||||
public static final String ELEMENT_ORDER = "element_order";
|
||||
public static final String TAB_PRIORITY = "tab_priority";
|
||||
public static final String PLUGIN_ID = "plugin_id";
|
||||
public static final String ICON_ID = "icon_id";
|
||||
|
||||
public static final String STATEMENT_SELECT_TAB_ID = "(" + SELECT + ID +
|
||||
FROM + TABLE_NAME +
|
||||
WHERE + TAB_NAME + "=?" +
|
||||
AND + PLUGIN_ID + "=" + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ")";
|
||||
|
||||
public static void set3TabValuesToStatement(PreparedStatement statement, int parameterIndex, String tabName, String pluginName, UUID serverUUID) throws SQLException {
|
||||
statement.setString(parameterIndex, tabName);
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, parameterIndex + 1, pluginName, serverUUID);
|
||||
}
|
||||
|
||||
private ExtensionTabTable() {
|
||||
/* Static information class */
|
||||
}
|
||||
|
||||
public static String createTableSQL(DBType dbType) {
|
||||
return CreateTableParser.create(TABLE_NAME, dbType)
|
||||
.column(ID, INT).primaryKey()
|
||||
.column(TAB_NAME, Sql.varchar(50)).notNull()
|
||||
.column(ELEMENT_ORDER, Sql.varchar(100)).notNull().defaultValue("'" + ElementOrder.serialize(ElementOrder.values()) + "'")
|
||||
.column(TAB_PRIORITY, INT).notNull()
|
||||
.column(PLUGIN_ID, INT).notNull()
|
||||
.column(ICON_ID, INT).notNull()
|
||||
.foreignKey(PLUGIN_ID, ExtensionPluginTable.TABLE_NAME, ExtensionPluginTable.ID)
|
||||
.foreignKey(ICON_ID, ExtensionIconTable.TABLE_NAME, ExtensionIconTable.ID)
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Task for updating {@link DataExtension} server values periodically.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class ExtensionServerMethodCallerTask extends AbsRunnable {
|
||||
|
||||
private final ExtensionServiceImplementation extensionServiceImplementation;
|
||||
|
||||
@Inject
|
||||
public ExtensionServerMethodCallerTask(ExtensionServiceImplementation extensionServiceImplementation) {
|
||||
this.extensionServiceImplementation = extensionServiceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
extensionServiceImplementation.updateServerValues(CallEvents.SERVER_PERIODICAL);
|
||||
}
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
import com.djrapitops.plan.data.plugin.PluginsConfigSection;
|
||||
import com.djrapitops.plan.extension.implementation.CallerImplementation;
|
||||
import com.djrapitops.plan.extension.implementation.DataProviderExtractor;
|
||||
import com.djrapitops.plan.extension.implementation.ExtensionRegister;
|
||||
import com.djrapitops.plan.extension.implementation.providers.gathering.ProviderValueGatherer;
|
||||
import com.djrapitops.plan.system.DebugChannels;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Implementation for {@link ExtensionService}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class ExtensionServiceImplementation implements ExtensionService {
|
||||
|
||||
private final PlanConfig config;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerInfo serverInfo;
|
||||
private final ExtensionRegister extensionRegister;
|
||||
private final PluginLogger logger;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
private final Map<String, ProviderValueGatherer> extensionGatherers;
|
||||
|
||||
@Inject
|
||||
public ExtensionServiceImplementation(
|
||||
PlanConfig config,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
ExtensionRegister extensionRegister,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.config = config;
|
||||
this.dbSystem = dbSystem;
|
||||
this.serverInfo = serverInfo;
|
||||
this.extensionRegister = extensionRegister;
|
||||
this.logger = logger;
|
||||
this.errorHandler = errorHandler;
|
||||
|
||||
extensionGatherers = new HashMap<>();
|
||||
|
||||
ExtensionService.ExtensionServiceHolder.set(this);
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
extensionRegister.registerBuiltInExtensions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Caller> register(DataExtension extension) {
|
||||
DataProviderExtractor extractor = new DataProviderExtractor(extension);
|
||||
String pluginName = extractor.getPluginName();
|
||||
|
||||
if (shouldNotAllowRegistration(pluginName)) return Optional.empty();
|
||||
|
||||
for (String warning : extractor.getWarnings()) {
|
||||
logger.warn("DataExtension API implementation mistake for " + pluginName + ": " + warning);
|
||||
}
|
||||
|
||||
ProviderValueGatherer gatherer = new ProviderValueGatherer(extension, extractor, dbSystem, serverInfo, logger);
|
||||
gatherer.storeExtensionInformation();
|
||||
extensionGatherers.put(pluginName, gatherer);
|
||||
|
||||
updateServerValues(gatherer, CallEvents.SERVER_EXTENSION_REGISTER);
|
||||
|
||||
logger.getDebugLogger().logOn(DebugChannels.DATA_EXTENSIONS, pluginName + " extension registered.");
|
||||
return Optional.of(new CallerImplementation(gatherer, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(DataExtension extension) {
|
||||
DataProviderExtractor extractor = new DataProviderExtractor(extension);
|
||||
String pluginName = extractor.getPluginName();
|
||||
if (extensionGatherers.remove(pluginName) != null) {
|
||||
logger.getDebugLogger().logOn(DebugChannels.DATA_EXTENSIONS, pluginName + " extension unregistered.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean shouldNotAllowRegistration(String pluginName) {
|
||||
PluginsConfigSection pluginsConfig = config.getPluginsConfigSection();
|
||||
|
||||
if (!pluginsConfig.hasSection(pluginName)) {
|
||||
try {
|
||||
pluginsConfig.createSection(pluginName);
|
||||
} catch (IOException e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
logger.warn("Could not register DataExtension for " + pluginName + " due to " + e.toString());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pluginsConfig.isEnabled(pluginName)) {
|
||||
logger.getDebugLogger().logOn(DebugChannels.DATA_EXTENSIONS, pluginName + " extension disabled in the config.");
|
||||
return true;
|
||||
}
|
||||
return false; // Should register.
|
||||
}
|
||||
|
||||
public void updatePlayerValues(UUID playerUUID, String playerName, CallEvents event) {
|
||||
for (ProviderValueGatherer gatherer : extensionGatherers.values()) {
|
||||
updatePlayerValues(gatherer, playerUUID, playerName, event);
|
||||
}
|
||||
}
|
||||
|
||||
public void updatePlayerValues(ProviderValueGatherer gatherer, UUID playerUUID, String playerName, CallEvents event) {
|
||||
if (!gatherer.canCallEvent(event)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.getDebugLogger().logOn(DebugChannels.DATA_EXTENSIONS, "Gathering values for: " + playerName);
|
||||
|
||||
gatherer.updateValues(playerUUID, playerName);
|
||||
|
||||
logger.getDebugLogger().logOn(DebugChannels.DATA_EXTENSIONS, "Gathering completed: " + playerName);
|
||||
} catch (Exception | NoClassDefFoundError | NoSuchMethodError | NoSuchFieldError e) {
|
||||
logger.warn(gatherer.getPluginName() + " ran into (but failed safely) " + e.getClass().getSimpleName() +
|
||||
" when updating value for '" + playerName +
|
||||
"', (You can disable integration with setting 'Plugins." + gatherer.getPluginName() + ".Enabled')" +
|
||||
" reason: '" + e.getMessage() +
|
||||
"', stack trace to follow:");
|
||||
errorHandler.log(L.WARN, gatherer.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateServerValues(CallEvents event) {
|
||||
for (ProviderValueGatherer gatherer : extensionGatherers.values()) {
|
||||
updateServerValues(gatherer, event);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateServerValues(ProviderValueGatherer gatherer, CallEvents event) {
|
||||
if (!gatherer.canCallEvent(event)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.getDebugLogger().logOn(DebugChannels.DATA_EXTENSIONS, "Gathering values for server");
|
||||
|
||||
gatherer.updateValues();
|
||||
|
||||
logger.getDebugLogger().logOn(DebugChannels.DATA_EXTENSIONS, "Gathering completed for server");
|
||||
} catch (Exception | NoClassDefFoundError | NoSuchMethodError | NoSuchFieldError e) {
|
||||
logger.warn(gatherer.getPluginName() + " ran into (but failed safely) " + e.getClass().getSimpleName() +
|
||||
" when updating value for server" +
|
||||
", (You can disable integration with setting 'Plugins." + gatherer.getPluginName() + ".Enabled')" +
|
||||
" reason: '" + e.getMessage() +
|
||||
"', stack trace to follow:");
|
||||
errorHandler.log(L.WARN, gatherer.getClass(), e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation;
|
||||
|
||||
import com.djrapitops.plan.extension.CallEvents;
|
||||
import com.djrapitops.plan.extension.Caller;
|
||||
import com.djrapitops.plan.extension.ExtensionServiceImplementation;
|
||||
import com.djrapitops.plan.extension.implementation.providers.gathering.ProviderValueGatherer;
|
||||
import com.djrapitops.plugin.utilities.Verify;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Implementation for {@link Caller} interface.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class CallerImplementation implements Caller {
|
||||
|
||||
private final ProviderValueGatherer gatherer;
|
||||
private final ExtensionServiceImplementation extensionServiceImplementation;
|
||||
|
||||
public CallerImplementation(ProviderValueGatherer gatherer, ExtensionServiceImplementation extensionServiceImplementation) {
|
||||
this.gatherer = gatherer;
|
||||
this.extensionServiceImplementation = extensionServiceImplementation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePlayerData(UUID playerUUID, String playerName) throws IllegalArgumentException {
|
||||
Verify.nullCheck(playerUUID, () -> new IllegalArgumentException("'playerUUID' can not be null!"));
|
||||
Verify.nullCheck(playerName, () -> new IllegalArgumentException("'playerName' can not be null!"));
|
||||
extensionServiceImplementation.updatePlayerValues(gatherer, playerUUID, playerName, CallEvents.MANUAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateServerData() {
|
||||
extensionServiceImplementation.updateServerValues(gatherer, CallEvents.MANUAL);
|
||||
}
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation;
|
||||
|
||||
import com.djrapitops.plan.extension.DataExtension;
|
||||
import com.djrapitops.plan.extension.annotation.*;
|
||||
import com.djrapitops.plan.extension.extractor.ExtensionExtractor;
|
||||
import com.djrapitops.plan.extension.extractor.MethodAnnotations;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.providers.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Extracts objects that can be used to obtain data to store in the database.
|
||||
* <p>
|
||||
* Goal of this class is to abstract away DataExtension API annotations so that they will not be needed outside when calling methods.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DataProviderExtractor {
|
||||
|
||||
private ExtensionExtractor extensionExtractor;
|
||||
private DataProviders dataProviders;
|
||||
|
||||
/**
|
||||
* Create a DataProviderExtractor.
|
||||
*
|
||||
* @param extension DataExtension to extract information from.
|
||||
* @throws IllegalArgumentException If something is badly wrong with the specified extension class annotations.
|
||||
*/
|
||||
public DataProviderExtractor(DataExtension extension) {
|
||||
extensionExtractor = new ExtensionExtractor(extension);
|
||||
|
||||
extensionExtractor.extractAnnotationInformation();
|
||||
|
||||
dataProviders = new DataProviders();
|
||||
extractAllDataProviders();
|
||||
}
|
||||
|
||||
public String getPluginName() {
|
||||
return extensionExtractor.getPluginInfo().name();
|
||||
}
|
||||
|
||||
public Icon getPluginIcon() {
|
||||
PluginInfo pluginInfo = extensionExtractor.getPluginInfo();
|
||||
return new Icon(pluginInfo.iconFamily(), pluginInfo.iconName(), pluginInfo.color());
|
||||
}
|
||||
|
||||
public Collection<TabInformation> getPluginTabs() {
|
||||
Map<String, TabInfo> tabInformation = extensionExtractor.getTabInformation()
|
||||
.stream().collect(Collectors.toMap(TabInfo::tab, Function.identity(), (one, two) -> one));
|
||||
|
||||
Map<String, Integer> order = getTabOrder().map(this::orderToMap).orElse(new HashMap<>());
|
||||
|
||||
// Extracts PluginTabs
|
||||
return extensionExtractor.getMethodAnnotations().getAnnotations(Tab.class).stream()
|
||||
.map(Tab::value)
|
||||
.distinct()
|
||||
.map(tabName -> {
|
||||
Optional<TabInfo> tabInfo = Optional.ofNullable(tabInformation.get(tabName));
|
||||
return new TabInformation(
|
||||
tabName,
|
||||
tabInfo.map(info -> new Icon(info.iconFamily(), info.iconName(), Color.NONE)).orElse(null),
|
||||
tabInfo.map(TabInfo::elementOrder).orElse(null),
|
||||
order.getOrDefault(tabName, 100)
|
||||
);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Map<String, Integer> orderToMap(String[] order) {
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
for (int i = 0; i < order.length; i++) {
|
||||
map.put(order[i], i);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public Optional<String[]> getTabOrder() {
|
||||
return extensionExtractor.getTabOrder().map(TabOrder::value);
|
||||
}
|
||||
|
||||
public Collection<String> getInvalidatedMethods() {
|
||||
return extensionExtractor.getInvalidateMethodAnnotations().stream()
|
||||
.map(InvalidateMethod::value)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public DataProviders getDataProviders() {
|
||||
return dataProviders;
|
||||
}
|
||||
|
||||
private void extractAllDataProviders() {
|
||||
PluginInfo pluginInfo = extensionExtractor.getPluginInfo();
|
||||
|
||||
MethodAnnotations methodAnnotations = extensionExtractor.getMethodAnnotations();
|
||||
Map<Method, Tab> tabs = methodAnnotations.getMethodAnnotations(Tab.class);
|
||||
Map<Method, Conditional> conditions = methodAnnotations.getMethodAnnotations(Conditional.class);
|
||||
|
||||
extractDataProviders(pluginInfo, tabs, conditions, BooleanProvider.class, BooleanDataProvider::placeToDataProviders);
|
||||
extractDataProviders(pluginInfo, tabs, conditions, DoubleProvider.class, DoubleDataProvider::placeToDataProviders);
|
||||
extractDataProviders(pluginInfo, tabs, conditions, PercentageProvider.class, PercentageDataProvider::placeToDataProviders);
|
||||
extractDataProviders(pluginInfo, tabs, conditions, NumberProvider.class, NumberDataProvider::placeToDataProviders);
|
||||
extractDataProviders(pluginInfo, tabs, conditions, StringProvider.class, StringDataProvider::placeToDataProviders);
|
||||
}
|
||||
|
||||
private <T extends Annotation> void extractDataProviders(PluginInfo pluginInfo, Map<Method, Tab> tabs, Map<Method, Conditional> conditions, Class<T> ofKind, DataProviderFactory<T> factory) {
|
||||
for (Map.Entry<Method, T> entry : extensionExtractor.getMethodAnnotations().getMethodAnnotations(ofKind).entrySet()) {
|
||||
Method method = entry.getKey();
|
||||
T annotation = entry.getValue();
|
||||
Optional<Conditional> conditional = Optional.ofNullable(conditions.get(method));
|
||||
Optional<Tab> tab = Optional.ofNullable(tabs.get(method));
|
||||
|
||||
factory.placeToDataProviders(
|
||||
dataProviders, method, annotation,
|
||||
conditional.orElse(null),
|
||||
tab.map(Tab::value).orElse(null),
|
||||
pluginInfo.name()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<String> getWarnings() {
|
||||
return extensionExtractor.getWarnings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Functional interface for defining a method that places required DataProvider to DataProviders.
|
||||
*
|
||||
* @param <T> Type of the annotation on the method that is going to be extracted.
|
||||
*/
|
||||
interface DataProviderFactory<T extends Annotation> {
|
||||
void placeToDataProviders(
|
||||
DataProviders dataProviders,
|
||||
Method method, T annotation, Conditional condition, String tab, String pluginName
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation;
|
||||
|
||||
import com.djrapitops.plan.extension.Group;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Utility enum for determining what kind of parameters a provider method used.
|
||||
* <p>
|
||||
* This also allows figuring out where to save method results.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public enum MethodType {
|
||||
|
||||
PLAYER_UUID,
|
||||
PLAYER_NAME,
|
||||
GROUP,
|
||||
SERVER;
|
||||
|
||||
public static MethodType forMethod(Method method) {
|
||||
int parameterCount = method.getParameterCount();
|
||||
if (parameterCount == 0) {
|
||||
return SERVER;
|
||||
}
|
||||
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
Class<?> firstParameter = parameterTypes[0];
|
||||
|
||||
if (UUID.class.equals(firstParameter)) {
|
||||
return PLAYER_UUID;
|
||||
} else if (String.class.equals(firstParameter)) {
|
||||
return PLAYER_NAME;
|
||||
} else if (Group.class.equals(firstParameter)) {
|
||||
return GROUP;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(method.getDeclaringClass() + " method " + method.getName() + " had invalid parameters.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation;
|
||||
|
||||
import com.djrapitops.plan.extension.annotation.Conditional;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionDescriptive;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents the annotation information provided on a method.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ProviderInformation extends ExtensionDescriptive {
|
||||
|
||||
private final String pluginName;
|
||||
private final String tab; // can be null
|
||||
private final Conditional condition; // can be null
|
||||
|
||||
public ProviderInformation(
|
||||
String pluginName, String name, String text, String description, Icon icon, int priority, String tab, Conditional condition
|
||||
) {
|
||||
super(name, text, description, icon, priority);
|
||||
this.pluginName = pluginName;
|
||||
this.tab = tab;
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
public String getPluginName() {
|
||||
return StringUtils.truncate(pluginName, 50);
|
||||
}
|
||||
|
||||
public Optional<String> getTab() {
|
||||
return tab == null || tab.isEmpty() ? Optional.empty() : Optional.of(StringUtils.truncate(tab, 50));
|
||||
}
|
||||
|
||||
public Optional<String> getCondition() {
|
||||
return condition == null || condition.value().isEmpty() ? Optional.empty() : Optional.of((condition.negated() ? "not_" : "") + StringUtils.truncate(condition.value(), 50));
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation;
|
||||
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plugin.utilities.ArrayUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents a tab of {@link com.djrapitops.plan.extension.DataExtension} defined by {@link com.djrapitops.plan.extension.annotation.Tab} and
|
||||
* {@link com.djrapitops.plan.extension.annotation.TabInfo} annotations.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class TabInformation {
|
||||
|
||||
private final String tabName;
|
||||
private final Icon icon; // can be null
|
||||
private ElementOrder[] elementOrder; // can be null / miss values
|
||||
private int tabPriority;
|
||||
|
||||
public TabInformation(String tabName, Icon icon, ElementOrder[] elementOrder, int tabPriority) {
|
||||
this.tabName = tabName;
|
||||
this.icon = icon;
|
||||
this.elementOrder = elementOrder;
|
||||
this.tabPriority = tabPriority;
|
||||
}
|
||||
|
||||
public String getTabName() {
|
||||
return StringUtils.truncate(tabName, 50);
|
||||
}
|
||||
|
||||
public static Icon defaultIcon() {
|
||||
return new Icon(Family.SOLID, "circle", Color.NONE);
|
||||
}
|
||||
|
||||
public Icon getTabIcon() {
|
||||
return icon != null ? icon : defaultIcon();
|
||||
}
|
||||
|
||||
public int getTabPriority() {
|
||||
return tabPriority;
|
||||
}
|
||||
|
||||
public Optional<ElementOrder[]> getTabElementOrder() {
|
||||
if (elementOrder == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
ElementOrder[] possibleValues = ElementOrder.values();
|
||||
if (elementOrder.length < possibleValues.length) {
|
||||
addMissingElements(possibleValues);
|
||||
}
|
||||
|
||||
return Optional.of(elementOrder);
|
||||
}
|
||||
|
||||
private void addMissingElements(ElementOrder[] possibleValues) {
|
||||
for (ElementOrder possibleValue : possibleValues) {
|
||||
if (Arrays.binarySearch(elementOrder, possibleValue) < 0) {
|
||||
elementOrder = ArrayUtil.merge(elementOrder, new ElementOrder[]{possibleValue});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers;
|
||||
|
||||
import com.djrapitops.plan.extension.annotation.BooleanProvider;
|
||||
import com.djrapitops.plan.extension.annotation.Conditional;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents a DataExtension API method annotated with {@link BooleanProvider} annotation.
|
||||
* <p>
|
||||
* Used to obtain data to place in the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class BooleanDataProvider extends DataProvider<Boolean> {
|
||||
|
||||
private final String providedCondition;
|
||||
private final boolean hidden;
|
||||
|
||||
private BooleanDataProvider(ProviderInformation providerInformation, MethodWrapper<Boolean> method, String providedCondition, boolean hidden) {
|
||||
super(providerInformation, method);
|
||||
|
||||
this.providedCondition = providedCondition;
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
public static void placeToDataProviders(
|
||||
DataProviders dataProviders, Method method, BooleanProvider annotation,
|
||||
Conditional condition, String tab, String pluginName
|
||||
) {
|
||||
MethodWrapper<Boolean> methodWrapper = new MethodWrapper<>(method, Boolean.class);
|
||||
Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.iconColor());
|
||||
|
||||
ProviderInformation providerInformation = new ProviderInformation(
|
||||
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), tab, condition
|
||||
);
|
||||
|
||||
dataProviders.put(new BooleanDataProvider(providerInformation, methodWrapper, annotation.conditionName(), annotation.hidden()));
|
||||
}
|
||||
|
||||
public static Optional<String> getProvidedCondition(DataProvider<Boolean> provider) {
|
||||
if (provider instanceof BooleanDataProvider) {
|
||||
return ((BooleanDataProvider) provider).getProvidedCondition();
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<String> getProvidedCondition() {
|
||||
return providedCondition == null || providedCondition.isEmpty() ? Optional.empty() : Optional.of(StringUtils.truncate(providedCondition, 50));
|
||||
}
|
||||
|
||||
public static boolean isHidden(DataProvider<Boolean> provider) {
|
||||
return provider instanceof BooleanDataProvider && ((BooleanDataProvider) provider).isHidden();
|
||||
}
|
||||
|
||||
public boolean isHidden() {
|
||||
return hidden;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers;
|
||||
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
|
||||
/**
|
||||
* Abstract representation of all values a Provider annotation provides.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public abstract class DataProvider<T> {
|
||||
|
||||
private final ProviderInformation providerInformation;
|
||||
private final MethodWrapper<T> method;
|
||||
|
||||
public DataProvider(ProviderInformation providerInformation, MethodWrapper<T> method) {
|
||||
this.providerInformation = providerInformation;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public MethodWrapper<T> getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public ProviderInformation getProviderInformation() {
|
||||
return providerInformation;
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers;
|
||||
|
||||
import com.djrapitops.plan.extension.implementation.MethodType;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Group class for handling multiple different types of {@link DataProvider}s.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DataProviders {
|
||||
|
||||
private Map<MethodType, Map<Class, List<DataProvider>>> byMethodType;
|
||||
|
||||
public DataProviders() {
|
||||
byMethodType = new EnumMap<>(MethodType.class);
|
||||
}
|
||||
|
||||
public <T> void put(DataProvider<T> provider) {
|
||||
MethodWrapper<T> method = provider.getMethod();
|
||||
|
||||
MethodType methodType = method.getMethodType();
|
||||
Class<T> resultType = method.getResultType();
|
||||
|
||||
Map<Class, List<DataProvider>> byParameterType = byMethodType.getOrDefault(methodType, new HashMap<>());
|
||||
List<DataProvider> dataProviders = byParameterType.getOrDefault(resultType, new ArrayList<>());
|
||||
|
||||
dataProviders.add(provider);
|
||||
|
||||
byParameterType.put(resultType, dataProviders);
|
||||
byMethodType.put(methodType, byParameterType);
|
||||
}
|
||||
|
||||
public <T> List<DataProvider<T>> getPlayerMethodsByType(Class<T> returnType) {
|
||||
Map<Class, List<DataProvider>> providersAcceptingUUID = byMethodType.getOrDefault(MethodType.PLAYER_UUID, new HashMap<>());
|
||||
Map<Class, List<DataProvider>> providersAcceptingName = byMethodType.getOrDefault(MethodType.PLAYER_NAME, new HashMap<>());
|
||||
|
||||
List<DataProvider<T>> byReturnType = new ArrayList<>();
|
||||
for (DataProvider dataProvider : providersAcceptingUUID.getOrDefault(returnType, Collections.emptyList())) {
|
||||
byReturnType.add((DataProvider<T>) dataProvider);
|
||||
}
|
||||
for (DataProvider dataProvider : providersAcceptingName.getOrDefault(returnType, Collections.emptyList())) {
|
||||
byReturnType.add((DataProvider<T>) dataProvider);
|
||||
}
|
||||
return byReturnType;
|
||||
}
|
||||
|
||||
public <T> List<DataProvider<T>> getServerMethodsByType(Class<T> returnType) {
|
||||
List<DataProvider<T>> byReturnType = new ArrayList<>();
|
||||
for (DataProvider dataProvider : byMethodType.getOrDefault(MethodType.SERVER, new HashMap<>()).getOrDefault(returnType, Collections.emptyList())) {
|
||||
byReturnType.add((DataProvider<T>) dataProvider);
|
||||
}
|
||||
return byReturnType;
|
||||
}
|
||||
|
||||
public <T> List<DataProvider<T>> getGroupMethodsByType(Class<T> returnType) {
|
||||
List<DataProvider<T>> byReturnType = new ArrayList<>();
|
||||
for (DataProvider dataProvider : byMethodType.getOrDefault(MethodType.GROUP, new HashMap<>()).getOrDefault(returnType, Collections.emptyList())) {
|
||||
byReturnType.add((DataProvider<T>) dataProvider);
|
||||
}
|
||||
return byReturnType;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers;
|
||||
|
||||
import com.djrapitops.plan.extension.annotation.Conditional;
|
||||
import com.djrapitops.plan.extension.annotation.DoubleProvider;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Represents a DataExtension API method annotated with {@link DoubleProvider} annotation.
|
||||
* <p>
|
||||
* Used to obtain data to place in the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DoubleDataProvider extends DataProvider<Double> {
|
||||
|
||||
private DoubleDataProvider(ProviderInformation providerInformation, MethodWrapper<Double> methodWrapper) {
|
||||
super(providerInformation, methodWrapper);
|
||||
}
|
||||
|
||||
public static void placeToDataProviders(
|
||||
DataProviders dataProviders, Method method, DoubleProvider annotation,
|
||||
Conditional condition, String tab, String pluginName
|
||||
) {
|
||||
MethodWrapper<Double> methodWrapper = new MethodWrapper<>(method, Double.class);
|
||||
Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.iconColor());
|
||||
|
||||
ProviderInformation providerInformation = new ProviderInformation(
|
||||
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), tab, condition
|
||||
);
|
||||
|
||||
dataProviders.put(new DoubleDataProvider(providerInformation, methodWrapper));
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers;
|
||||
|
||||
import com.djrapitops.plan.extension.DataExtension;
|
||||
import com.djrapitops.plan.extension.Group;
|
||||
import com.djrapitops.plan.extension.implementation.MethodType;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Wrap a Method so that it is easier to call.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class MethodWrapper<T> {
|
||||
|
||||
private final Method method;
|
||||
private final Class<T> resultType;
|
||||
private MethodType methodType;
|
||||
|
||||
public MethodWrapper(Method method, Class<T> resultType) {
|
||||
this.method = method;
|
||||
this.resultType = resultType;
|
||||
methodType = MethodType.forMethod(this.method);
|
||||
}
|
||||
|
||||
public T callMethod(DataExtension extension, UUID playerUUID, String playerName) throws InvocationTargetException, IllegalAccessException {
|
||||
if (methodType != MethodType.PLAYER_NAME && methodType != MethodType.PLAYER_UUID) {
|
||||
throw new IllegalStateException(method.getDeclaringClass() + " method " + method.getName() + " is not GROUP method.");
|
||||
}
|
||||
return callMethod(extension, playerUUID, playerName, null);
|
||||
}
|
||||
|
||||
public T callMethod(DataExtension extension, Group group) throws InvocationTargetException, IllegalAccessException {
|
||||
if (methodType != MethodType.GROUP) {
|
||||
throw new IllegalStateException(method.getDeclaringClass() + " method " + method.getName() + " is not GROUP method.");
|
||||
}
|
||||
return callMethod(extension, null, null, group);
|
||||
}
|
||||
|
||||
public T callMethod(DataExtension extension) throws InvocationTargetException, IllegalAccessException {
|
||||
if (methodType != MethodType.SERVER) {
|
||||
throw new IllegalStateException(method.getDeclaringClass() + " method " + method.getName() + " is not SERVER method.");
|
||||
}
|
||||
return callMethod(extension, null, null, null);
|
||||
}
|
||||
|
||||
public T callMethod(DataExtension extension, UUID playerUUID, String playerName, Group group) throws InvocationTargetException, IllegalAccessException {
|
||||
switch (methodType) {
|
||||
case SERVER:
|
||||
return resultType.cast(method.invoke(extension));
|
||||
case PLAYER_UUID:
|
||||
return resultType.cast(method.invoke(extension, playerUUID));
|
||||
case PLAYER_NAME:
|
||||
return resultType.cast(method.invoke(extension, playerName));
|
||||
case GROUP:
|
||||
return resultType.cast(method.invoke(extension, group));
|
||||
default:
|
||||
throw new IllegalArgumentException(method.getDeclaringClass() + " method " + method.getName() + " had invalid parameters.");
|
||||
}
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return method.getName();
|
||||
}
|
||||
|
||||
public MethodType getMethodType() {
|
||||
return methodType;
|
||||
}
|
||||
|
||||
public Class<T> getResultType() {
|
||||
return resultType;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers;
|
||||
|
||||
import com.djrapitops.plan.extension.FormatType;
|
||||
import com.djrapitops.plan.extension.annotation.Conditional;
|
||||
import com.djrapitops.plan.extension.annotation.NumberProvider;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Represents a DataExtension API method annotated with {@link NumberProvider} annotation.
|
||||
* <p>
|
||||
* Used to obtain data to place in the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class NumberDataProvider extends DataProvider<Long> {
|
||||
|
||||
private final FormatType formatType;
|
||||
|
||||
private NumberDataProvider(ProviderInformation providerInformation, MethodWrapper<Long> methodWrapper, FormatType formatType) {
|
||||
super(providerInformation, methodWrapper);
|
||||
this.formatType = formatType;
|
||||
}
|
||||
|
||||
public static void placeToDataProviders(
|
||||
DataProviders dataProviders, Method method, NumberProvider annotation,
|
||||
Conditional condition, String tab, String pluginName
|
||||
) {
|
||||
MethodWrapper<Long> methodWrapper = new MethodWrapper<>(method, Long.class);
|
||||
Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.iconColor());
|
||||
|
||||
ProviderInformation providerInformation = new ProviderInformation(
|
||||
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), tab, condition
|
||||
);
|
||||
|
||||
dataProviders.put(new NumberDataProvider(providerInformation, methodWrapper, annotation.format()));
|
||||
}
|
||||
|
||||
public static FormatType getFormatType(DataProvider<Long> provider) {
|
||||
if (provider instanceof NumberDataProvider) {
|
||||
return ((NumberDataProvider) provider).getFormatType();
|
||||
}
|
||||
return FormatType.NONE;
|
||||
}
|
||||
|
||||
public FormatType getFormatType() {
|
||||
return formatType;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers;
|
||||
|
||||
import com.djrapitops.plan.extension.annotation.Conditional;
|
||||
import com.djrapitops.plan.extension.annotation.PercentageProvider;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Represents a DataExtension API method annotated with {@link PercentageProvider} annotation.
|
||||
* <p>
|
||||
* Used to obtain data to place in the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PercentageDataProvider extends DataProvider<Double> {
|
||||
|
||||
private PercentageDataProvider(ProviderInformation providerInformation, MethodWrapper<Double> methodWrapper) {
|
||||
super(providerInformation, methodWrapper);
|
||||
}
|
||||
|
||||
public static void placeToDataProviders(
|
||||
DataProviders dataProviders, Method method, PercentageProvider annotation,
|
||||
Conditional condition, String tab, String pluginName
|
||||
) {
|
||||
MethodWrapper<Double> methodWrapper = new MethodWrapper<>(method, Double.class);
|
||||
Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.iconColor());
|
||||
|
||||
ProviderInformation providerInformation = new ProviderInformation(
|
||||
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), tab, condition
|
||||
);
|
||||
|
||||
dataProviders.put(new PercentageDataProvider(providerInformation, methodWrapper));
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers;
|
||||
|
||||
import com.djrapitops.plan.extension.annotation.Conditional;
|
||||
import com.djrapitops.plan.extension.annotation.StringProvider;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Represents a DataExtension API method annotated with {@link StringProvider} annotation.
|
||||
* <p>
|
||||
* Used to obtain data to place in the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class StringDataProvider extends DataProvider<String> {
|
||||
|
||||
private final boolean playerName;
|
||||
|
||||
private StringDataProvider(ProviderInformation providerInformation, MethodWrapper<String> methodWrapper, boolean playerName) {
|
||||
super(providerInformation, methodWrapper);
|
||||
this.playerName = playerName;
|
||||
}
|
||||
|
||||
public static void placeToDataProviders(
|
||||
DataProviders dataProviders, Method method, StringProvider annotation,
|
||||
Conditional condition, String tab, String pluginName
|
||||
) {
|
||||
MethodWrapper<String> methodWrapper = new MethodWrapper<>(method, String.class);
|
||||
Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.iconColor());
|
||||
|
||||
ProviderInformation providerInformation = new ProviderInformation(
|
||||
pluginName, method.getName(), annotation.text(), annotation.description(), providerIcon, annotation.priority(), tab, condition
|
||||
);
|
||||
|
||||
boolean playerName = annotation.playerName();
|
||||
|
||||
dataProviders.put(new StringDataProvider(providerInformation, methodWrapper, playerName));
|
||||
}
|
||||
|
||||
public static boolean isPlayerName(DataProvider<String> provider) {
|
||||
if (provider instanceof StringDataProvider) {
|
||||
return ((StringDataProvider) provider).isPlayerName();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers.gathering;
|
||||
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.extension.DataExtension;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
import com.djrapitops.plan.extension.implementation.providers.BooleanDataProvider;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProvider;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProviders;
|
||||
import com.djrapitops.plan.extension.implementation.providers.MethodWrapper;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.StoreIconTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.providers.StoreBooleanProviderTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.StorePlayerBooleanResultTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.StoreServerBooleanResultTransaction;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Gathers BooleanProvider method data.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
class BooleanProviderValueGatherer {
|
||||
|
||||
private final String pluginName;
|
||||
private final DataExtension extension;
|
||||
private final UUID serverUUID;
|
||||
|
||||
private final Database database;
|
||||
private final DataProviders dataProviders;
|
||||
private final PluginLogger logger;
|
||||
|
||||
BooleanProviderValueGatherer(
|
||||
String pluginName, DataExtension extension,
|
||||
UUID serverUUID, Database database,
|
||||
DataProviders dataProviders,
|
||||
PluginLogger logger
|
||||
) {
|
||||
this.pluginName = pluginName;
|
||||
this.extension = extension;
|
||||
this.serverUUID = serverUUID;
|
||||
this.database = database;
|
||||
this.dataProviders = dataProviders;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
Conditions gatherBooleanDataOfPlayer(UUID playerUUID, String playerName) {
|
||||
Conditions conditions = new Conditions();
|
||||
|
||||
List<DataProvider<Boolean>> unsatisifiedProviders = new ArrayList<>(dataProviders.getPlayerMethodsByType(Boolean.class));
|
||||
Set<DataProvider<Boolean>> satisfied;
|
||||
|
||||
// Method parameters abstracted away so that same method can be used for all parameter types
|
||||
// Same with Method result store transaction creation
|
||||
Function<MethodWrapper<Boolean>, Callable<Boolean>> methodCaller = method -> () -> method.callMethod(extension, playerUUID, playerName);
|
||||
BiFunction<MethodWrapper<Boolean>, Boolean, Transaction> storeTrancationCreator = (method, result) -> new StorePlayerBooleanResultTransaction(pluginName, serverUUID, method.getMethodName(), playerUUID, result);
|
||||
|
||||
do {
|
||||
// Loop through all unsatisfied providers to see if more conditions are satisfied
|
||||
satisfied = attemptToSatisfyMoreConditionsAndStoreResults(methodCaller, storeTrancationCreator, conditions, unsatisifiedProviders);
|
||||
// Remove now satisfied Providers so that they are not called again
|
||||
unsatisifiedProviders.removeAll(satisfied);
|
||||
// If no new conditions could be satisfied, stop looping.
|
||||
} while (!satisfied.isEmpty());
|
||||
|
||||
return conditions;
|
||||
}
|
||||
|
||||
Conditions gatherBooleanDataOfServer() {
|
||||
Conditions conditions = new Conditions();
|
||||
|
||||
List<DataProvider<Boolean>> unsatisifiedProviders = new ArrayList<>(dataProviders.getServerMethodsByType(Boolean.class));
|
||||
Set<DataProvider<Boolean>> satisfied;
|
||||
|
||||
// Method parameters abstracted away so that same method can be used for all parameter types
|
||||
// Same with Method result store transaction creation
|
||||
Function<MethodWrapper<Boolean>, Callable<Boolean>> methodCaller = method -> () -> method.callMethod(extension);
|
||||
BiFunction<MethodWrapper<Boolean>, Boolean, Transaction> storeTransactionCreator = (method, result) -> new StoreServerBooleanResultTransaction(pluginName, serverUUID, method.getMethodName(), result);
|
||||
|
||||
do {
|
||||
// Loop through all unsatisfied providers to see if more conditions are satisfied
|
||||
satisfied = attemptToSatisfyMoreConditionsAndStoreResults(methodCaller, storeTransactionCreator, conditions, unsatisifiedProviders);
|
||||
// Remove now satisfied Providers so that they are not called again
|
||||
unsatisifiedProviders.removeAll(satisfied);
|
||||
// If no new conditions could be satisfied, stop looping.
|
||||
} while (!satisfied.isEmpty());
|
||||
|
||||
return conditions;
|
||||
}
|
||||
|
||||
private Set<DataProvider<Boolean>> attemptToSatisfyMoreConditionsAndStoreResults(
|
||||
Function<MethodWrapper<Boolean>, Callable<Boolean>> methodCaller,
|
||||
BiFunction<MethodWrapper<Boolean>, Boolean, Transaction> storeTransactionCreator,
|
||||
Conditions conditions, List<DataProvider<Boolean>> unsatisifiedProviders
|
||||
) {
|
||||
Set<DataProvider<Boolean>> satisfied = new HashSet<>();
|
||||
for (DataProvider<Boolean> booleanProvider : unsatisifiedProviders) {
|
||||
ProviderInformation providerInformation = booleanProvider.getProviderInformation();
|
||||
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent() && conditions.isNotFulfilled(condition.get())) {
|
||||
// Condition required by the BooleanProvider is not satisfied
|
||||
continue;
|
||||
}
|
||||
|
||||
Optional<String> providedCondition = BooleanDataProvider.getProvidedCondition(booleanProvider);
|
||||
boolean hidden = BooleanDataProvider.isHidden(booleanProvider);
|
||||
|
||||
MethodWrapper<Boolean> method = booleanProvider.getMethod();
|
||||
Boolean result = getMethodResult(
|
||||
methodCaller.apply(method),
|
||||
throwable -> pluginName + " has invalid implementation, method " + method.getMethodName() + " threw exception: " + throwable.toString()
|
||||
);
|
||||
if (result == null) {
|
||||
// Error during method call
|
||||
satisfied.add(booleanProvider); // Prevents further attempts to call this provider for this player.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (providedCondition.isPresent()) {
|
||||
if (result) {
|
||||
// The condition was fulfilled (true) for this player.
|
||||
conditions.conditionFulfilled(providedCondition.get());
|
||||
} else {
|
||||
// The negated condition was fulfilled (false) for this player.
|
||||
conditions.conditionFulfilled("not_" + providedCondition.get());
|
||||
}
|
||||
}
|
||||
|
||||
satisfied.add(booleanProvider); // Prevents further attempts to call this provider for this player.
|
||||
database.executeTransaction(new StoreIconTransaction(providerInformation.getIcon()));
|
||||
database.executeTransaction(new StoreBooleanProviderTransaction(booleanProvider, providedCondition.orElse(null), hidden, serverUUID));
|
||||
database.executeTransaction(storeTransactionCreator.apply(method, result));
|
||||
}
|
||||
return satisfied;
|
||||
}
|
||||
|
||||
private <T> T getMethodResult(Callable<T> callable, Function<Throwable, String> errorMsg) {
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception | NoSuchFieldError | NoSuchMethodError e) {
|
||||
logger.warn(errorMsg.apply(e));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers.gathering;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility object for managing conditions.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class Conditions {
|
||||
|
||||
private final Set<String> fulfilledConditions;
|
||||
|
||||
public Conditions() {
|
||||
this.fulfilledConditions = new HashSet<>();
|
||||
}
|
||||
|
||||
public boolean isNotFulfilled(String condition) {
|
||||
return !fulfilledConditions.contains(condition);
|
||||
}
|
||||
|
||||
public void conditionFulfilled(String condition) {
|
||||
fulfilledConditions.add(condition);
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers.gathering;
|
||||
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.extension.DataExtension;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProvider;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProviders;
|
||||
import com.djrapitops.plan.extension.implementation.providers.MethodWrapper;
|
||||
import com.djrapitops.plan.extension.implementation.providers.PercentageDataProvider;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.StoreIconTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.providers.StoreDoubleProviderTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.StorePlayerDoubleResultTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.StorePlayerPercentageResultTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.StoreServerDoubleResultTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.StoreServerPercentageResultTransaction;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Gathers DoubleProvider and PercentageProvider method data.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
class DoubleAndPercentageProviderValueGatherer {
|
||||
|
||||
private final String pluginName;
|
||||
private final DataExtension extension;
|
||||
private final UUID serverUUID;
|
||||
|
||||
private final Database database;
|
||||
private final DataProviders dataProviders;
|
||||
private final PluginLogger logger;
|
||||
|
||||
DoubleAndPercentageProviderValueGatherer(
|
||||
String pluginName, DataExtension extension,
|
||||
UUID serverUUID, Database database,
|
||||
DataProviders dataProviders,
|
||||
PluginLogger logger
|
||||
) {
|
||||
this.pluginName = pluginName;
|
||||
this.extension = extension;
|
||||
this.serverUUID = serverUUID;
|
||||
this.database = database;
|
||||
this.dataProviders = dataProviders;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
void gatherDoubleDataOfPlayer(UUID playerUUID, String playerName, Conditions conditions) {
|
||||
// Method parameters abstracted away so that same method can be used for all parameter types
|
||||
// Same with Method result store transaction creation
|
||||
Function<MethodWrapper<Double>, Callable<Double>> methodCaller = method -> () -> method.callMethod(extension, playerUUID, playerName);
|
||||
BiFunction<MethodWrapper<Double>, Double, Transaction> percStoreTransactionCreator = (method, result) -> new StorePlayerPercentageResultTransaction(pluginName, serverUUID, method.getMethodName(), playerUUID, result);
|
||||
BiFunction<MethodWrapper<Double>, Double, Transaction> doubleStoreTransactionCreator = (method, result) -> new StorePlayerDoubleResultTransaction(pluginName, serverUUID, method.getMethodName(), playerUUID, result);
|
||||
|
||||
for (DataProvider<Double> doubleProvider : dataProviders.getPlayerMethodsByType(Double.class)) {
|
||||
gatherDoubleDataOfProvider(methodCaller, percStoreTransactionCreator, doubleStoreTransactionCreator, conditions, doubleProvider);
|
||||
}
|
||||
}
|
||||
|
||||
void gatherDoubleDataOfServer(Conditions conditions) {
|
||||
// Method parameters abstracted away so that same method can be used for all parameter types
|
||||
// Same with Method result store transaction creation
|
||||
Function<MethodWrapper<Double>, Callable<Double>> methodCaller = method -> () -> method.callMethod(extension);
|
||||
BiFunction<MethodWrapper<Double>, Double, Transaction> percStoreTransactionCreator = (method, result) -> new StoreServerPercentageResultTransaction(pluginName, serverUUID, method.getMethodName(), result);
|
||||
BiFunction<MethodWrapper<Double>, Double, Transaction> doubleStoreTransactionCreator = (method, result) -> new StoreServerDoubleResultTransaction(pluginName, serverUUID, method.getMethodName(), result);
|
||||
|
||||
for (DataProvider<Double> doubleProvider : dataProviders.getServerMethodsByType(Double.class)) {
|
||||
gatherDoubleDataOfProvider(methodCaller, percStoreTransactionCreator, doubleStoreTransactionCreator, conditions, doubleProvider);
|
||||
}
|
||||
}
|
||||
|
||||
private void gatherDoubleDataOfProvider(
|
||||
Function<MethodWrapper<Double>, Callable<Double>> methodCaller,
|
||||
BiFunction<MethodWrapper<Double>, Double, Transaction> percStoreTransactionCreator,
|
||||
BiFunction<MethodWrapper<Double>, Double, Transaction> doubleStoreTransactionCreator,
|
||||
Conditions conditions, DataProvider<Double> doubleProvider
|
||||
|
||||
) {
|
||||
ProviderInformation providerInformation = doubleProvider.getProviderInformation();
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent() && conditions.isNotFulfilled(condition.get())) {
|
||||
return;
|
||||
}
|
||||
|
||||
MethodWrapper<Double> method = doubleProvider.getMethod();
|
||||
Double result = getMethodResult(
|
||||
methodCaller.apply(method),
|
||||
throwable -> pluginName + " has invalid implementation, method " + method.getMethodName() + " threw exception: " + throwable.toString()
|
||||
);
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
database.executeTransaction(new StoreIconTransaction(providerInformation.getIcon()));
|
||||
database.executeTransaction(new StoreDoubleProviderTransaction(doubleProvider, serverUUID));
|
||||
|
||||
if (doubleProvider instanceof PercentageDataProvider) {
|
||||
database.executeTransaction(percStoreTransactionCreator.apply(method, result));
|
||||
} else {
|
||||
database.executeTransaction(doubleStoreTransactionCreator.apply(method, result));
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T getMethodResult(Callable<T> callable, Function<Throwable, String> errorMsg) {
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception | NoSuchFieldError | NoSuchMethodError e) {
|
||||
logger.warn(errorMsg.apply(e));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers.gathering;
|
||||
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.extension.DataExtension;
|
||||
import com.djrapitops.plan.extension.FormatType;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProvider;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProviders;
|
||||
import com.djrapitops.plan.extension.implementation.providers.MethodWrapper;
|
||||
import com.djrapitops.plan.extension.implementation.providers.NumberDataProvider;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.StoreIconTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.providers.StoreNumberProviderTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.StorePlayerNumberResultTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.StoreServerNumberResultTransaction;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Gathers NumberProvider method data.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
class NumberProviderValueGatherer {
|
||||
|
||||
private final String pluginName;
|
||||
private final DataExtension extension;
|
||||
private final UUID serverUUID;
|
||||
|
||||
private final Database database;
|
||||
private final DataProviders dataProviders;
|
||||
private final PluginLogger logger;
|
||||
|
||||
NumberProviderValueGatherer(
|
||||
String pluginName, DataExtension extension,
|
||||
UUID serverUUID, Database database,
|
||||
DataProviders dataProviders,
|
||||
PluginLogger logger
|
||||
) {
|
||||
this.pluginName = pluginName;
|
||||
this.extension = extension;
|
||||
this.serverUUID = serverUUID;
|
||||
this.database = database;
|
||||
this.dataProviders = dataProviders;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
void gatherNumberDataOfPlayer(UUID playerUUID, String playerName, Conditions conditions) {
|
||||
// Method parameters abstracted away so that same method can be used for all parameter types
|
||||
// Same with Method result store transaction creation
|
||||
Function<MethodWrapper<Long>, Callable<Long>> methodCaller = method -> () -> method.callMethod(extension, playerUUID, playerName);
|
||||
BiFunction<MethodWrapper<Long>, Long, Transaction> storeTransactionCreator = (method, result) -> new StorePlayerNumberResultTransaction(pluginName, serverUUID, method.getMethodName(), playerUUID, result);
|
||||
|
||||
for (DataProvider<Long> numberProvider : dataProviders.getPlayerMethodsByType(Long.class)) {
|
||||
gatherNumberDataOfProvider(methodCaller, storeTransactionCreator, conditions, numberProvider);
|
||||
}
|
||||
}
|
||||
|
||||
void gatherNumberDataOfServer(Conditions conditions) {
|
||||
// Method parameters abstracted away so that same method can be used for all parameter types
|
||||
// Same with Method result store transaction creation
|
||||
Function<MethodWrapper<Long>, Callable<Long>> methodCaller = method -> () -> method.callMethod(extension);
|
||||
BiFunction<MethodWrapper<Long>, Long, Transaction> storeTransactionCreator = (method, result) -> new StoreServerNumberResultTransaction(pluginName, serverUUID, method.getMethodName(), result);
|
||||
|
||||
for (DataProvider<Long> numberProvider : dataProviders.getServerMethodsByType(Long.class)) {
|
||||
gatherNumberDataOfProvider(methodCaller, storeTransactionCreator, conditions, numberProvider);
|
||||
}
|
||||
}
|
||||
|
||||
private void gatherNumberDataOfProvider(
|
||||
Function<MethodWrapper<Long>, Callable<Long>> methodCaller,
|
||||
BiFunction<MethodWrapper<Long>, Long, Transaction> storeTransactionCreator,
|
||||
Conditions conditions, DataProvider<Long> numberProvider
|
||||
) {
|
||||
ProviderInformation providerInformation = numberProvider.getProviderInformation();
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent() && conditions.isNotFulfilled(condition.get())) {
|
||||
return;
|
||||
}
|
||||
|
||||
MethodWrapper<Long> method = numberProvider.getMethod();
|
||||
Long result = getMethodResult(
|
||||
methodCaller.apply(method),
|
||||
throwable -> pluginName + " has invalid implementation, method " + method.getMethodName() + " threw exception: " + throwable.toString()
|
||||
);
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FormatType formatType = NumberDataProvider.getFormatType(numberProvider);
|
||||
|
||||
database.executeTransaction(new StoreIconTransaction(providerInformation.getIcon()));
|
||||
database.executeTransaction(new StoreNumberProviderTransaction(numberProvider, formatType, serverUUID));
|
||||
database.executeTransaction(storeTransactionCreator.apply(method, result));
|
||||
}
|
||||
|
||||
private <T> T getMethodResult(Callable<T> callable, Function<Throwable, String> errorMsg) {
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception | NoSuchFieldError | NoSuchMethodError e) {
|
||||
logger.warn(errorMsg.apply(e));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers.gathering;
|
||||
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.extension.CallEvents;
|
||||
import com.djrapitops.plan.extension.DataExtension;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.DataProviderExtractor;
|
||||
import com.djrapitops.plan.extension.implementation.TabInformation;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.StoreIconTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.StorePluginTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.StoreTabInformationTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.RemoveInvalidResultsTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Object that can be called to place data about players to the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ProviderValueGatherer {
|
||||
|
||||
private final CallEvents[] callEvents;
|
||||
private final DataProviderExtractor extractor;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerInfo serverInfo;
|
||||
private BooleanProviderValueGatherer booleanGatherer;
|
||||
private NumberProviderValueGatherer numberGatherer;
|
||||
private DoubleAndPercentageProviderValueGatherer doubleAndPercentageGatherer;
|
||||
private StringProviderValueGatherer stringGatherer;
|
||||
|
||||
public ProviderValueGatherer(
|
||||
DataExtension extension,
|
||||
DataProviderExtractor extractor,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
PluginLogger logger
|
||||
) {
|
||||
this.callEvents = extension.callExtensionMethodsOn();
|
||||
this.extractor = extractor;
|
||||
this.dbSystem = dbSystem;
|
||||
this.serverInfo = serverInfo;
|
||||
|
||||
booleanGatherer = new BooleanProviderValueGatherer(
|
||||
extractor.getPluginName(), extension,
|
||||
serverInfo.getServerUUID(), dbSystem.getDatabase(),
|
||||
extractor.getDataProviders(), logger
|
||||
);
|
||||
numberGatherer = new NumberProviderValueGatherer(
|
||||
extractor.getPluginName(), extension,
|
||||
serverInfo.getServerUUID(), dbSystem.getDatabase(),
|
||||
extractor.getDataProviders(), logger
|
||||
);
|
||||
doubleAndPercentageGatherer = new DoubleAndPercentageProviderValueGatherer(
|
||||
extractor.getPluginName(), extension,
|
||||
serverInfo.getServerUUID(), dbSystem.getDatabase(),
|
||||
extractor.getDataProviders(), logger
|
||||
);
|
||||
stringGatherer = new StringProviderValueGatherer(
|
||||
extractor.getPluginName(), extension,
|
||||
serverInfo.getServerUUID(), dbSystem.getDatabase(),
|
||||
extractor.getDataProviders(), logger
|
||||
);
|
||||
}
|
||||
|
||||
public boolean canCallEvent(CallEvents event) {
|
||||
if (event == CallEvents.MANUAL) {
|
||||
return true;
|
||||
}
|
||||
for (CallEvents accepted : callEvents) {
|
||||
if (event == accepted) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getPluginName() {
|
||||
return extractor.getPluginName();
|
||||
}
|
||||
|
||||
public void storeExtensionInformation() {
|
||||
String pluginName = extractor.getPluginName();
|
||||
Icon pluginIcon = extractor.getPluginIcon();
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
UUID serverUUID = serverInfo.getServerUUID();
|
||||
|
||||
Database database = dbSystem.getDatabase();
|
||||
database.executeTransaction(new StoreIconTransaction(pluginIcon));
|
||||
database.executeTransaction(new StorePluginTransaction(pluginName, time, serverUUID, pluginIcon));
|
||||
for (TabInformation tab : extractor.getPluginTabs()) {
|
||||
database.executeTransaction(new StoreIconTransaction(tab.getTabIcon()));
|
||||
database.executeTransaction(new StoreTabInformationTransaction(pluginName, serverUUID, tab));
|
||||
}
|
||||
|
||||
database.executeTransaction(new RemoveInvalidResultsTransaction(pluginName, serverUUID, extractor.getInvalidatedMethods()));
|
||||
}
|
||||
|
||||
public void updateValues(UUID playerUUID, String playerName) {
|
||||
Conditions conditions = booleanGatherer.gatherBooleanDataOfPlayer(playerUUID, playerName);
|
||||
numberGatherer.gatherNumberDataOfPlayer(playerUUID, playerName, conditions);
|
||||
doubleAndPercentageGatherer.gatherDoubleDataOfPlayer(playerUUID, playerName, conditions);
|
||||
stringGatherer.gatherStringDataOfPlayer(playerUUID, playerName, conditions);
|
||||
}
|
||||
|
||||
public void updateValues() {
|
||||
Conditions conditions = booleanGatherer.gatherBooleanDataOfServer();
|
||||
numberGatherer.gatherNumberDataOfServer(conditions);
|
||||
doubleAndPercentageGatherer.gatherDoubleDataOfServer(conditions);
|
||||
stringGatherer.gatherStringDataOfServer(conditions);
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.providers.gathering;
|
||||
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.extension.DataExtension;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProvider;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProviders;
|
||||
import com.djrapitops.plan.extension.implementation.providers.MethodWrapper;
|
||||
import com.djrapitops.plan.extension.implementation.providers.StringDataProvider;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.StoreIconTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.providers.StoreStringProviderTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.StorePlayerStringResultTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.StoreServerStringResultTransaction;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Gathers StringProvider method data.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
class StringProviderValueGatherer {
|
||||
|
||||
private final String pluginName;
|
||||
private final DataExtension extension;
|
||||
private final UUID serverUUID;
|
||||
|
||||
private final Database database;
|
||||
private final DataProviders dataProviders;
|
||||
private final PluginLogger logger;
|
||||
|
||||
StringProviderValueGatherer(
|
||||
String pluginName, DataExtension extension,
|
||||
UUID serverUUID, Database database,
|
||||
DataProviders dataProviders,
|
||||
PluginLogger logger
|
||||
) {
|
||||
this.pluginName = pluginName;
|
||||
this.extension = extension;
|
||||
this.serverUUID = serverUUID;
|
||||
this.database = database;
|
||||
this.dataProviders = dataProviders;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
void gatherStringDataOfPlayer(UUID playerUUID, String playerName, Conditions conditions) {
|
||||
// Method parameters abstracted away so that same method can be used for all parameter types
|
||||
// Same with Method result store transaction creation
|
||||
Function<MethodWrapper<String>, Callable<String>> methodCaller = method -> () -> method.callMethod(extension, playerUUID, playerName);
|
||||
BiFunction<MethodWrapper<String>, String, Transaction> storeTransactionCreator = (method, result) -> new StorePlayerStringResultTransaction(pluginName, serverUUID, method.getMethodName(), playerUUID, result);
|
||||
|
||||
for (DataProvider<String> stringProvider : dataProviders.getPlayerMethodsByType(String.class)) {
|
||||
gatherStringDataOfProvider(methodCaller, storeTransactionCreator, conditions, stringProvider);
|
||||
}
|
||||
}
|
||||
|
||||
void gatherStringDataOfServer(Conditions conditions) {
|
||||
// Method parameters abstracted away so that same method can be used for all parameter types
|
||||
// Same with Method result store transaction creation
|
||||
Function<MethodWrapper<String>, Callable<String>> methodCaller = method -> () -> method.callMethod(extension);
|
||||
BiFunction<MethodWrapper<String>, String, Transaction> storeTransactionCreator = (method, result) -> new StoreServerStringResultTransaction(pluginName, serverUUID, method.getMethodName(), result);
|
||||
|
||||
for (DataProvider<String> stringProvider : dataProviders.getServerMethodsByType(String.class)) {
|
||||
gatherStringDataOfProvider(methodCaller, storeTransactionCreator, conditions, stringProvider);
|
||||
}
|
||||
}
|
||||
|
||||
private void gatherStringDataOfProvider(
|
||||
Function<MethodWrapper<String>, Callable<String>> methodCaller,
|
||||
BiFunction<MethodWrapper<String>, String, Transaction> storeTransactionCreator,
|
||||
Conditions conditions,
|
||||
DataProvider<String> stringProvider
|
||||
) {
|
||||
ProviderInformation providerInformation = stringProvider.getProviderInformation();
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent() && conditions.isNotFulfilled(condition.get())) {
|
||||
return;
|
||||
}
|
||||
|
||||
MethodWrapper<String> method = stringProvider.getMethod();
|
||||
String result = getMethodResult(
|
||||
methodCaller.apply(method),
|
||||
throwable -> pluginName + " has invalid implementation, method " + method.getMethodName() + " threw exception: " + throwable.toString()
|
||||
);
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
result = StringUtils.truncate(result, 50);
|
||||
|
||||
database.executeTransaction(new StoreIconTransaction(providerInformation.getIcon()));
|
||||
database.executeTransaction(new StoreStringProviderTransaction(stringProvider, StringDataProvider.isPlayerName(stringProvider), serverUUID));
|
||||
database.executeTransaction(storeTransactionCreator.apply(method, result));
|
||||
}
|
||||
|
||||
private <T> T getMethodResult(Callable<T> callable, Function<Throwable, String> errorMsg) {
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception | NoSuchFieldError | NoSuchMethodError e) {
|
||||
logger.warn(errorMsg.apply(e));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.results;
|
||||
|
||||
/**
|
||||
* Represents boolean data returned by a BooleanProvider method.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionBooleanData implements ExtensionData {
|
||||
|
||||
private ExtensionDescriptive descriptive;
|
||||
private boolean value;
|
||||
|
||||
public ExtensionBooleanData(ExtensionDescriptive descriptive, boolean value) {
|
||||
this.descriptive = descriptive;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ExtensionDescriptive getDescriptive() {
|
||||
return descriptive;
|
||||
}
|
||||
|
||||
public String getFormattedValue() {
|
||||
return value ? "Yes" : "No";
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.results;
|
||||
|
||||
/**
|
||||
* Represents a data-point given by a Provider method of a DataExtension.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface ExtensionData {
|
||||
|
||||
/**
|
||||
* Get Descriptive information about the data point.
|
||||
*
|
||||
* @return a {@link ExtensionDescriptive}.
|
||||
*/
|
||||
ExtensionDescriptive getDescriptive();
|
||||
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.results;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Describes information about an extension value given by a Provider method.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionDescriptive implements Comparable<ExtensionDescriptive> {
|
||||
|
||||
private final String name;
|
||||
private final String text;
|
||||
private final String description; // can be null
|
||||
private final Icon icon;
|
||||
private final int priority;
|
||||
|
||||
public ExtensionDescriptive(String name, String text, String description, Icon icon, int priority) {
|
||||
this.name = name;
|
||||
this.text = text;
|
||||
this.description = description;
|
||||
this.icon = icon;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return StringUtils.truncate(name, 50);
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return StringUtils.truncate(text, 50);
|
||||
}
|
||||
|
||||
public Optional<String> getDescription() {
|
||||
return description == null || description.isEmpty() ? Optional.empty() : Optional.of(StringUtils.truncate(description, 150));
|
||||
}
|
||||
|
||||
public Icon getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ExtensionDescriptive other) {
|
||||
return Integer.compare(other.priority, this.priority); // Higher is first
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof ExtensionDescriptive)) return false;
|
||||
ExtensionDescriptive that = (ExtensionDescriptive) o;
|
||||
return priority == that.priority &&
|
||||
name.equals(that.name) &&
|
||||
text.equals(that.text) &&
|
||||
Objects.equals(description, that.description) &&
|
||||
icon.equals(that.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, text, description, icon, priority);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.results;
|
||||
|
||||
import com.djrapitops.plan.utilities.formatting.Formatter;
|
||||
|
||||
/**
|
||||
* Represents double data returned by a DoubleProvider or PercentageProvider method.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionDoubleData implements ExtensionData {
|
||||
|
||||
private ExtensionDescriptive descriptive;
|
||||
private double value;
|
||||
|
||||
public ExtensionDoubleData(ExtensionDescriptive descriptive, double value) {
|
||||
this.descriptive = descriptive;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ExtensionDescriptive getDescriptive() {
|
||||
return descriptive;
|
||||
}
|
||||
|
||||
public String getFormattedValue(Formatter<Double> formatter) {
|
||||
return formatter.apply(value);
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.results;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
|
||||
/**
|
||||
* Information about a DataExtension stored in the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionInformation {
|
||||
|
||||
private final int id;
|
||||
private final String pluginName;
|
||||
private final Icon icon;
|
||||
|
||||
public ExtensionInformation(int id, String pluginName, Icon icon) {
|
||||
this.id = id;
|
||||
this.pluginName = pluginName;
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getPluginName() {
|
||||
return pluginName;
|
||||
}
|
||||
|
||||
public Icon getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return '{' + "id=" + id + ", pluginName='" + pluginName + '\'' + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.results;
|
||||
|
||||
import com.djrapitops.plan.extension.FormatType;
|
||||
import com.djrapitops.plan.utilities.formatting.Formatter;
|
||||
|
||||
/**
|
||||
* Represents double data returned by a DoubleProvider or PercentageProvider method.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionNumberData implements ExtensionData {
|
||||
|
||||
private final ExtensionDescriptive descriptive;
|
||||
private final FormatType formatType;
|
||||
private final long value;
|
||||
|
||||
public ExtensionNumberData(ExtensionDescriptive descriptive, FormatType formatType, long value) {
|
||||
this.descriptive = descriptive;
|
||||
this.formatType = formatType;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ExtensionDescriptive getDescriptive() {
|
||||
return descriptive;
|
||||
}
|
||||
|
||||
public FormatType getFormatType() {
|
||||
return formatType;
|
||||
}
|
||||
|
||||
public String getFormattedValue(Formatter<Long> formatter) {
|
||||
return formatter.apply(value);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.results;
|
||||
|
||||
import com.djrapitops.plan.api.PlanAPI;
|
||||
import com.djrapitops.plan.utilities.html.Html;
|
||||
|
||||
/**
|
||||
* Represents double data returned by a DoubleProvider or PercentageProvider method.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionStringData implements ExtensionData {
|
||||
|
||||
private final ExtensionDescriptive descriptive;
|
||||
private final boolean playerName;
|
||||
private final String value;
|
||||
|
||||
public ExtensionStringData(ExtensionDescriptive descriptive, boolean playerName, String value) {
|
||||
this.descriptive = descriptive;
|
||||
this.playerName = playerName;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ExtensionDescriptive getDescriptive() {
|
||||
return descriptive;
|
||||
}
|
||||
|
||||
public String getFormattedValue() {
|
||||
String withColors = Html.swapColorCodesToSpan(value);
|
||||
return !playerName ? withColors : Html.LINK.parse(PlanAPI.getInstance().getPlayerInspectPageLink(value), withColors);
|
||||
}
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.results;
|
||||
|
||||
import com.djrapitops.plan.extension.implementation.TabInformation;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Represents data on an extension tab.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionTabData implements Comparable<ExtensionTabData> {
|
||||
|
||||
private final TabInformation tabInformation; // Can be null in case where no tab was defined for provider.
|
||||
|
||||
private final Map<String, ExtensionBooleanData> booleanData;
|
||||
private final Map<String, ExtensionDoubleData> doubleData;
|
||||
private final Map<String, ExtensionDoubleData> percentageData;
|
||||
private final Map<String, ExtensionNumberData> numberData;
|
||||
private final Map<String, ExtensionStringData> stringData;
|
||||
|
||||
private List<String> order;
|
||||
|
||||
// Table and Graph data will be added later.
|
||||
|
||||
public ExtensionTabData(TabInformation tabInformation) {
|
||||
this.tabInformation = tabInformation;
|
||||
|
||||
booleanData = new HashMap<>();
|
||||
doubleData = new HashMap<>();
|
||||
percentageData = new HashMap<>();
|
||||
numberData = new HashMap<>();
|
||||
stringData = new HashMap<>();
|
||||
}
|
||||
|
||||
public TabInformation getTabInformation() {
|
||||
return tabInformation;
|
||||
}
|
||||
|
||||
public List<String> getValueOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
public Optional<ExtensionBooleanData> getBoolean(String providerName) {
|
||||
return Optional.ofNullable(booleanData.get(providerName));
|
||||
}
|
||||
|
||||
public Optional<ExtensionDoubleData> getDouble(String providerName) {
|
||||
return Optional.ofNullable(doubleData.get(providerName));
|
||||
}
|
||||
|
||||
public Optional<ExtensionDoubleData> getPercentage(String providerName) {
|
||||
return Optional.ofNullable(percentageData.get(providerName));
|
||||
}
|
||||
|
||||
public Optional<ExtensionNumberData> getNumber(String providerName) {
|
||||
return Optional.ofNullable(numberData.get(providerName));
|
||||
}
|
||||
|
||||
public Optional<ExtensionStringData> getString(String providerName) {
|
||||
return Optional.ofNullable(stringData.get(providerName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ExtensionTabData other) {
|
||||
return Integer.compare(this.tabInformation.getTabPriority(), other.tabInformation.getTabPriority()); // Lower is first
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof ExtensionTabData)) return false;
|
||||
ExtensionTabData that = (ExtensionTabData) o;
|
||||
return tabInformation.equals(that.tabInformation) &&
|
||||
order.equals(that.order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(tabInformation, order);
|
||||
}
|
||||
|
||||
public void combine(ExtensionTabData other) {
|
||||
this.booleanData.putAll(other.booleanData);
|
||||
this.doubleData.putAll(other.doubleData);
|
||||
this.percentageData.putAll(other.percentageData);
|
||||
this.numberData.putAll(other.numberData);
|
||||
this.stringData.putAll(other.stringData);
|
||||
}
|
||||
|
||||
public static class Factory {
|
||||
|
||||
private final ExtensionTabData data;
|
||||
|
||||
public Factory(TabInformation tabInformation) {
|
||||
data = new ExtensionTabData(tabInformation);
|
||||
}
|
||||
|
||||
public Factory putBooleanData(ExtensionBooleanData extensionBooleanData) {
|
||||
data.booleanData.put(extensionBooleanData.getDescriptive().getName(), extensionBooleanData);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Factory putDoubleData(ExtensionDoubleData extensionDoubleData) {
|
||||
data.doubleData.put(extensionDoubleData.getDescriptive().getName(), extensionDoubleData);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Factory putPercentageData(ExtensionDoubleData extensionDoubleData) {
|
||||
data.percentageData.put(extensionDoubleData.getDescriptive().getName(), extensionDoubleData);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Factory putNumberData(ExtensionNumberData extensionNumberData) {
|
||||
data.numberData.put(extensionNumberData.getDescriptive().getName(), extensionNumberData);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Factory putStringData(ExtensionStringData extensionStringData) {
|
||||
data.stringData.put(extensionStringData.getDescriptive().getName(), extensionStringData);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void createOrderingList() {
|
||||
List<ExtensionDescriptive> descriptives = new ArrayList<>();
|
||||
data.booleanData.values().stream().map(ExtensionData::getDescriptive).forEach(descriptives::add);
|
||||
data.doubleData.values().stream().map(ExtensionData::getDescriptive).forEach(descriptives::add);
|
||||
data.percentageData.values().stream().map(ExtensionData::getDescriptive).forEach(descriptives::add);
|
||||
data.numberData.values().stream().map(ExtensionData::getDescriptive).forEach(descriptives::add);
|
||||
data.stringData.values().stream().map(ExtensionData::getDescriptive).forEach(descriptives::add);
|
||||
|
||||
data.order = descriptives.stream().sorted()
|
||||
.map(ExtensionDescriptive::getName)
|
||||
.distinct()// Method names are usually different, but in case someone had same method name with different parameters.
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public ExtensionTabData build() {
|
||||
createOrderingList();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ExtensionTabData{" +
|
||||
"available=" + order +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.results.player;
|
||||
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionInformation;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionTabData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents data of a single extension about a player.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionPlayerData implements Comparable<ExtensionPlayerData> {
|
||||
|
||||
private final int pluginID;
|
||||
|
||||
private ExtensionInformation extensionInformation;
|
||||
|
||||
private List<ExtensionTabData> tabs;
|
||||
|
||||
private ExtensionPlayerData(int pluginID) {
|
||||
this.pluginID = pluginID;
|
||||
|
||||
tabs = new ArrayList<>();
|
||||
}
|
||||
|
||||
public int getPluginID() {
|
||||
return pluginID;
|
||||
}
|
||||
|
||||
public ExtensionInformation getExtensionInformation() {
|
||||
return extensionInformation;
|
||||
}
|
||||
|
||||
public boolean hasOnlyGenericTab() {
|
||||
return tabs.size() == 1 && tabs.get(0).getTabInformation().getTabName().isEmpty();
|
||||
}
|
||||
|
||||
public List<ExtensionTabData> getTabs() {
|
||||
return tabs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ExtensionPlayerData o) {
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(this.extensionInformation.getPluginName(), o.extensionInformation.getPluginName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof ExtensionPlayerData)) return false;
|
||||
ExtensionPlayerData that = (ExtensionPlayerData) o;
|
||||
return pluginID == that.pluginID &&
|
||||
extensionInformation.equals(that.extensionInformation) &&
|
||||
tabs.equals(that.tabs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(pluginID, extensionInformation, tabs);
|
||||
}
|
||||
|
||||
public static class Factory {
|
||||
|
||||
private final ExtensionPlayerData data;
|
||||
|
||||
public Factory(int pluginId) {
|
||||
data = new ExtensionPlayerData(pluginId);
|
||||
}
|
||||
|
||||
public Factory setInformation(ExtensionInformation information) {
|
||||
if (information.getId() != data.pluginID) {
|
||||
throw new IllegalArgumentException("ID mismatch, wanted id: " + data.pluginID + " but got " + information);
|
||||
}
|
||||
data.extensionInformation = information;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Factory addTab(ExtensionTabData tab) {
|
||||
data.tabs.add(tab);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExtensionPlayerData build() {
|
||||
Collections.sort(data.tabs);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.results.server;
|
||||
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionInformation;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionTabData;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents data of a single extension about a server.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionServerData implements Comparable<ExtensionServerData> {
|
||||
|
||||
private final int pluginID;
|
||||
|
||||
private ExtensionInformation extensionInformation;
|
||||
|
||||
private Map<String, ExtensionTabData> tabs;
|
||||
|
||||
private ExtensionServerData(int pluginID) {
|
||||
this.pluginID = pluginID;
|
||||
|
||||
tabs = new HashMap<>();
|
||||
}
|
||||
|
||||
public int getPluginID() {
|
||||
return pluginID;
|
||||
}
|
||||
|
||||
public ExtensionInformation getExtensionInformation() {
|
||||
return extensionInformation;
|
||||
}
|
||||
|
||||
public boolean hasOnlyGenericTab() {
|
||||
return tabs.size() == 1 && tabs.containsKey("");
|
||||
}
|
||||
|
||||
public List<ExtensionTabData> getTabs() {
|
||||
List<ExtensionTabData> tabList = new ArrayList<>(tabs.values());
|
||||
Collections.sort(tabList);
|
||||
return tabList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ExtensionServerData o) {
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(this.extensionInformation.getPluginName(), o.extensionInformation.getPluginName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof ExtensionServerData)) return false;
|
||||
ExtensionServerData that = (ExtensionServerData) o;
|
||||
return pluginID == that.pluginID &&
|
||||
Objects.equals(extensionInformation, that.extensionInformation) &&
|
||||
Objects.equals(tabs, that.tabs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(pluginID, extensionInformation, tabs);
|
||||
}
|
||||
|
||||
public static class Factory {
|
||||
|
||||
private final ExtensionServerData data;
|
||||
|
||||
public Factory(int pluginId) {
|
||||
data = new ExtensionServerData(pluginId);
|
||||
}
|
||||
|
||||
public Factory combine(Factory with) {
|
||||
if (with != null) {
|
||||
for (ExtensionTabData tab : with.build().getTabs()) {
|
||||
Optional<ExtensionTabData> found = getTab(tab.getTabInformation().getTabName());
|
||||
if (found.isPresent()) {
|
||||
found.get().combine(tab);
|
||||
} else {
|
||||
addTab(tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Factory setInformation(ExtensionInformation information) {
|
||||
if (information.getId() != data.pluginID) {
|
||||
throw new IllegalArgumentException("ID mismatch, wanted id: " + data.pluginID + " but got " + information);
|
||||
}
|
||||
data.extensionInformation = information;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Factory addTab(ExtensionTabData tab) {
|
||||
data.tabs.put(tab.getTabInformation().getTabName(), tab);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Optional<ExtensionTabData> getTab(String tabName) {
|
||||
return Optional.ofNullable(data.tabs.get(tabName));
|
||||
}
|
||||
|
||||
public ExtensionServerData build() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.queries;
|
||||
|
||||
import com.djrapitops.plan.db.SQLDB;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.QueryStatement;
|
||||
import com.djrapitops.plan.db.sql.tables.*;
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.TabInformation;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionDescriptive;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionDoubleData;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionTabData;
|
||||
import com.djrapitops.plan.extension.implementation.results.server.ExtensionServerData;
|
||||
|
||||
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;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Query aggregated boolean values from player value table.
|
||||
* <p>
|
||||
* Returns Map: PluginID - ExtensionServerData.Factory.
|
||||
* <p>
|
||||
* How it is done:
|
||||
* - Combines three queries, one that selects true boolean count, one that selects boolean value count and one that selects provider information.
|
||||
* - Data query is sorted into a multi-map: PluginID - Tab Name - Tab Data
|
||||
* - (Tab Name can be empty.)
|
||||
* - Multi-map is sorted into ExtensionPlayerData objects by PluginID, one per ID
|
||||
* <p>
|
||||
* There are multiple data extraction methods to make extracting the value query easier.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionAggregateBooleansQuery implements Query<Map<Integer, ExtensionServerData.Factory>> {
|
||||
|
||||
private final UUID serverUUID;
|
||||
|
||||
public ExtensionAggregateBooleansQuery(UUID serverUUID) {
|
||||
this.serverUUID = serverUUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, ExtensionServerData.Factory> executeQuery(SQLDB db) {
|
||||
String selectTrueBooleans = SELECT +
|
||||
ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
",COUNT(1) as positive" +
|
||||
FROM + ExtensionPlayerValueTable.TABLE_NAME +
|
||||
WHERE + ExtensionPlayerValueTable.BOOLEAN_VALUE + "=?" +
|
||||
GROUP_BY + ExtensionPlayerValueTable.PROVIDER_ID;
|
||||
|
||||
String selectBooleanCount = SELECT +
|
||||
ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
",COUNT(1) as total" +
|
||||
FROM + ExtensionPlayerValueTable.TABLE_NAME +
|
||||
WHERE + ExtensionPlayerValueTable.BOOLEAN_VALUE + IS_NOT_NULL +
|
||||
GROUP_BY + ExtensionPlayerValueTable.PROVIDER_ID;
|
||||
|
||||
String sql = SELECT +
|
||||
"b1.total as total," +
|
||||
"b2.positive as positive," +
|
||||
"p1." + ExtensionProviderTable.PLUGIN_ID + " as plugin_id," +
|
||||
"p1." + ExtensionProviderTable.PROVIDER_NAME + " as provider_name," +
|
||||
"p1." + ExtensionProviderTable.TEXT + " as text," +
|
||||
"p1." + ExtensionProviderTable.DESCRIPTION + " as description," +
|
||||
"p1." + ExtensionProviderTable.PRIORITY + " as provider_priority," +
|
||||
"p1." + ExtensionProviderTable.IS_PLAYER_NAME + " as is_player_name," +
|
||||
"t1." + ExtensionTabTable.TAB_NAME + " as tab_name," +
|
||||
"t1." + ExtensionTabTable.TAB_PRIORITY + " as tab_priority," +
|
||||
"t1." + ExtensionTabTable.ELEMENT_ORDER + " as element_order," +
|
||||
"i1." + ExtensionIconTable.ICON_NAME + " as provider_icon_name," +
|
||||
"i1." + ExtensionIconTable.FAMILY + " as provider_icon_family," +
|
||||
"i1." + ExtensionIconTable.COLOR + " as provider_icon_color," +
|
||||
"i2." + ExtensionIconTable.ICON_NAME + " as tab_icon_name," +
|
||||
"i2." + ExtensionIconTable.FAMILY + " as tab_icon_family," +
|
||||
"i2." + ExtensionIconTable.COLOR + " as tab_icon_color" +
|
||||
FROM + '(' + selectBooleanCount + ") b1" +
|
||||
INNER_JOIN + ExtensionProviderTable.TABLE_NAME + " p1 on p1." + ExtensionProviderTable.ID + "=b1." + ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
INNER_JOIN + ExtensionPluginTable.TABLE_NAME + " e1 on p1." + ExtensionProviderTable.PLUGIN_ID + "=e1." + ExtensionPluginTable.ID +
|
||||
LEFT_JOIN + '(' + selectTrueBooleans + ") b2 on b2." + ExtensionPlayerValueTable.PROVIDER_ID + "=b1." + ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
LEFT_JOIN + ExtensionTabTable.TABLE_NAME + " t1 on t1." + ExtensionTabTable.ID + "=p1." + ExtensionProviderTable.TAB_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i1 on i1." + ExtensionIconTable.ID + "=p1." + ExtensionProviderTable.ICON_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i2 on i2." + ExtensionIconTable.ID + "=p1." + ExtensionTabTable.ICON_ID +
|
||||
WHERE + ExtensionPluginTable.SERVER_UUID + "=?" +
|
||||
AND + "p1." + ExtensionProviderTable.HIDDEN + "=?";
|
||||
|
||||
return db.query(new QueryStatement<Map<Integer, ExtensionServerData.Factory>>(sql, 1000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setBoolean(1, true); // selectTrueBooleans parameter
|
||||
statement.setString(2, serverUUID.toString());
|
||||
statement.setBoolean(3, false); // Don't select hidden values
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, ExtensionServerData.Factory> processResults(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = extractTabDataByPluginID(set);
|
||||
return ExtensionServerDataQuery.flatMapToServerData(tabDataByPluginID);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Map<Integer, Map<String, ExtensionTabData.Factory>> extractTabDataByPluginID(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = new HashMap<>();
|
||||
|
||||
while (set.next()) {
|
||||
int pluginID = set.getInt("plugin_id");
|
||||
Map<String, ExtensionTabData.Factory> tabData = tabDataByPluginID.getOrDefault(pluginID, new HashMap<>());
|
||||
|
||||
String tabName = Optional.ofNullable(set.getString("tab_name")).orElse("");
|
||||
ExtensionTabData.Factory inMap = tabData.get(tabName);
|
||||
ExtensionTabData.Factory extensionTab = inMap != null ? inMap : extractTab(tabName, set, tabData);
|
||||
|
||||
ExtensionDescriptive extensionDescriptive = extractDescriptive(set);
|
||||
extractAndPutDataTo(extensionTab, extensionDescriptive, set);
|
||||
|
||||
tabData.put(tabName, extensionTab);
|
||||
tabDataByPluginID.put(pluginID, tabData);
|
||||
}
|
||||
return tabDataByPluginID;
|
||||
}
|
||||
|
||||
private void extractAndPutDataTo(ExtensionTabData.Factory extensionTab, ExtensionDescriptive descriptive, ResultSet set) throws SQLException {
|
||||
double percentageValue = percentage(set.getInt("positive"), set.getInt("total"));
|
||||
extensionTab.putPercentageData(new ExtensionDoubleData(descriptive, percentageValue));
|
||||
}
|
||||
|
||||
private double percentage(double first, double second) {
|
||||
if (first == 0.0 || second == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
return first / second;
|
||||
}
|
||||
|
||||
private ExtensionDescriptive extractDescriptive(ResultSet set) throws SQLException {
|
||||
String name = set.getString("provider_name") + "_aggregate";
|
||||
String text = set.getString(ExtensionProviderTable.TEXT) + " / Players";
|
||||
String description = set.getString(ExtensionProviderTable.DESCRIPTION);
|
||||
int priority = set.getInt("provider_priority");
|
||||
|
||||
String iconName = set.getString("provider_icon_name");
|
||||
Family family = Family.getByName(set.getString("provider_icon_family")).orElse(Family.SOLID);
|
||||
Color color = Color.getByName(set.getString("provider_icon_color")).orElse(Color.NONE);
|
||||
Icon icon = new Icon(family, iconName, color);
|
||||
|
||||
return new ExtensionDescriptive(name, text, description, icon, priority);
|
||||
}
|
||||
|
||||
private ExtensionTabData.Factory extractTab(String tabName, ResultSet set, Map<String, ExtensionTabData.Factory> tabData) throws SQLException {
|
||||
Optional<Integer> tabPriority = Optional.of(set.getInt("tab_priority"));
|
||||
if (set.wasNull()) {
|
||||
tabPriority = Optional.empty();
|
||||
}
|
||||
Optional<ElementOrder[]> elementOrder = Optional.ofNullable(set.getString(ExtensionTabTable.ELEMENT_ORDER)).map(ElementOrder::deserialize);
|
||||
|
||||
Icon tabIcon = extractTabIcon(set);
|
||||
|
||||
return tabData.getOrDefault(tabName, new ExtensionTabData.Factory(new TabInformation(
|
||||
tabName,
|
||||
tabIcon,
|
||||
elementOrder.orElse(ElementOrder.values()),
|
||||
tabPriority.orElse(100)
|
||||
)));
|
||||
}
|
||||
|
||||
private Icon extractTabIcon(ResultSet set) throws SQLException {
|
||||
Optional<String> iconName = Optional.ofNullable(set.getString("tab_icon_name"));
|
||||
if (iconName.isPresent()) {
|
||||
Family iconFamily = Family.getByName(set.getString("tab_icon_family")).orElse(Family.SOLID);
|
||||
Color iconColor = Color.getByName(set.getString("tab_icon_color")).orElse(Color.NONE);
|
||||
return new Icon(iconFamily, iconName.get(), iconColor);
|
||||
} else {
|
||||
return TabInformation.defaultIcon();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.queries;
|
||||
|
||||
import com.djrapitops.plan.db.SQLDB;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.QueryStatement;
|
||||
import com.djrapitops.plan.db.sql.tables.*;
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.TabInformation;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionDescriptive;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionDoubleData;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionTabData;
|
||||
import com.djrapitops.plan.extension.implementation.results.server.ExtensionServerData;
|
||||
|
||||
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;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Query aggregated boolean values from player value table.
|
||||
* <p>
|
||||
* Returns Map: PluginID - ExtensionServerData.Factory.
|
||||
* <p>
|
||||
* How it is done:
|
||||
* - Combines three queries, one that selects true boolean count, one that selects boolean value count and one that selects provider information.
|
||||
* - Data query is sorted into a multi-map: PluginID - Tab Name - Tab Data
|
||||
* - (Tab Name can be empty.)
|
||||
* - Multi-map is sorted into ExtensionPlayerData objects by PluginID, one per ID
|
||||
* <p>
|
||||
* There are multiple data extraction methods to make extracting the value query easier.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionAggregateDoublesQuery implements Query<Map<Integer, ExtensionServerData.Factory>> {
|
||||
|
||||
private final UUID serverUUID;
|
||||
|
||||
public ExtensionAggregateDoublesQuery(UUID serverUUID) {
|
||||
this.serverUUID = serverUUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, ExtensionServerData.Factory> executeQuery(SQLDB db) {
|
||||
String selectDoubleAverage = SELECT +
|
||||
ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
",AVG(" + ExtensionPlayerValueTable.DOUBLE_VALUE + ") as average" +
|
||||
FROM + ExtensionPlayerValueTable.TABLE_NAME +
|
||||
WHERE + ExtensionPlayerValueTable.DOUBLE_VALUE + IS_NOT_NULL +
|
||||
GROUP_BY + ExtensionPlayerValueTable.PROVIDER_ID;
|
||||
|
||||
String selectDoubleTotal = SELECT +
|
||||
ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
",SUM(" + ExtensionPlayerValueTable.DOUBLE_VALUE + ") as total" +
|
||||
FROM + ExtensionPlayerValueTable.TABLE_NAME +
|
||||
WHERE + ExtensionPlayerValueTable.DOUBLE_VALUE + IS_NOT_NULL +
|
||||
GROUP_BY + ExtensionPlayerValueTable.PROVIDER_ID;
|
||||
|
||||
String sql = SELECT +
|
||||
"b1.total as total," +
|
||||
"b2.average as average," +
|
||||
"p1." + ExtensionProviderTable.PLUGIN_ID + " as plugin_id," +
|
||||
"p1." + ExtensionProviderTable.PROVIDER_NAME + " as provider_name," +
|
||||
"p1." + ExtensionProviderTable.TEXT + " as text," +
|
||||
"p1." + ExtensionProviderTable.DESCRIPTION + " as description," +
|
||||
"p1." + ExtensionProviderTable.PRIORITY + " as provider_priority," +
|
||||
"p1." + ExtensionProviderTable.IS_PLAYER_NAME + " as is_player_name," +
|
||||
"t1." + ExtensionTabTable.TAB_NAME + " as tab_name," +
|
||||
"t1." + ExtensionTabTable.TAB_PRIORITY + " as tab_priority," +
|
||||
"t1." + ExtensionTabTable.ELEMENT_ORDER + " as element_order," +
|
||||
"i1." + ExtensionIconTable.ICON_NAME + " as provider_icon_name," +
|
||||
"i1." + ExtensionIconTable.FAMILY + " as provider_icon_family," +
|
||||
"i1." + ExtensionIconTable.COLOR + " as provider_icon_color," +
|
||||
"i2." + ExtensionIconTable.ICON_NAME + " as tab_icon_name," +
|
||||
"i2." + ExtensionIconTable.FAMILY + " as tab_icon_family," +
|
||||
"i2." + ExtensionIconTable.COLOR + " as tab_icon_color" +
|
||||
FROM + '(' + selectDoubleTotal + ") b1" +
|
||||
INNER_JOIN + ExtensionProviderTable.TABLE_NAME + " p1 on p1." + ExtensionProviderTable.ID + "=b1." + ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
INNER_JOIN + ExtensionPluginTable.TABLE_NAME + " e1 on p1." + ExtensionProviderTable.PLUGIN_ID + "=e1." + ExtensionPluginTable.ID +
|
||||
LEFT_JOIN + '(' + selectDoubleAverage + ") b2 on b2." + ExtensionPlayerValueTable.PROVIDER_ID + "=b1." + ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
LEFT_JOIN + ExtensionTabTable.TABLE_NAME + " t1 on t1." + ExtensionTabTable.ID + "=p1." + ExtensionProviderTable.TAB_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i1 on i1." + ExtensionIconTable.ID + "=p1." + ExtensionProviderTable.ICON_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i2 on i2." + ExtensionIconTable.ID + "=p1." + ExtensionTabTable.ICON_ID +
|
||||
WHERE + ExtensionPluginTable.SERVER_UUID + "=?" +
|
||||
AND + "p1." + ExtensionProviderTable.HIDDEN + "=?";
|
||||
|
||||
return db.query(new QueryStatement<Map<Integer, ExtensionServerData.Factory>>(sql, 1000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
statement.setBoolean(2, false); // Don't select hidden values
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, ExtensionServerData.Factory> processResults(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = extractTabDataByPluginID(set);
|
||||
return ExtensionServerDataQuery.flatMapToServerData(tabDataByPluginID);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Map<Integer, Map<String, ExtensionTabData.Factory>> extractTabDataByPluginID(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = new HashMap<>();
|
||||
|
||||
while (set.next()) {
|
||||
int pluginID = set.getInt("plugin_id");
|
||||
Map<String, ExtensionTabData.Factory> tabData = tabDataByPluginID.getOrDefault(pluginID, new HashMap<>());
|
||||
|
||||
String tabName = Optional.ofNullable(set.getString("tab_name")).orElse("");
|
||||
ExtensionTabData.Factory inMap = tabData.get(tabName);
|
||||
ExtensionTabData.Factory extensionTab = inMap != null ? inMap : extractTab(tabName, set, tabData);
|
||||
|
||||
ExtensionDescriptive extensionDescriptive = extractDescriptive(set);
|
||||
extractAndPutDataTo(extensionTab, extensionDescriptive, set);
|
||||
|
||||
tabData.put(tabName, extensionTab);
|
||||
tabDataByPluginID.put(pluginID, tabData);
|
||||
}
|
||||
return tabDataByPluginID;
|
||||
}
|
||||
|
||||
private void extractAndPutDataTo(ExtensionTabData.Factory extensionTab, ExtensionDescriptive descriptive, ResultSet set) throws SQLException {
|
||||
extensionTab.putDoubleData(new ExtensionDoubleData(modifiedDescriptive(descriptive, "_avg", "Average "), set.getDouble("average")));
|
||||
extensionTab.putDoubleData(new ExtensionDoubleData(modifiedDescriptive(descriptive, "_total", "Total "), set.getDouble("total")));
|
||||
}
|
||||
|
||||
private ExtensionDescriptive modifiedDescriptive(ExtensionDescriptive descriptive, String appendToName, String appendToText) {
|
||||
return new ExtensionDescriptive(descriptive.getName() + appendToName, appendToText + descriptive.getText(), descriptive.getDescription().orElse(null), descriptive.getIcon(), descriptive.getPriority());
|
||||
}
|
||||
|
||||
private ExtensionDescriptive extractDescriptive(ResultSet set) throws SQLException {
|
||||
String name = set.getString("provider_name");
|
||||
String text = set.getString(ExtensionProviderTable.TEXT);
|
||||
String description = set.getString(ExtensionProviderTable.DESCRIPTION);
|
||||
int priority = set.getInt("provider_priority");
|
||||
|
||||
String iconName = set.getString("provider_icon_name");
|
||||
Family family = Family.getByName(set.getString("provider_icon_family")).orElse(Family.SOLID);
|
||||
Color color = Color.getByName(set.getString("provider_icon_color")).orElse(Color.NONE);
|
||||
Icon icon = new Icon(family, iconName, color);
|
||||
|
||||
return new ExtensionDescriptive(name, text, description, icon, priority);
|
||||
}
|
||||
|
||||
private ExtensionTabData.Factory extractTab(String tabName, ResultSet set, Map<String, ExtensionTabData.Factory> tabData) throws SQLException {
|
||||
Optional<Integer> tabPriority = Optional.of(set.getInt("tab_priority"));
|
||||
if (set.wasNull()) {
|
||||
tabPriority = Optional.empty();
|
||||
}
|
||||
Optional<ElementOrder[]> elementOrder = Optional.ofNullable(set.getString(ExtensionTabTable.ELEMENT_ORDER)).map(ElementOrder::deserialize);
|
||||
|
||||
Icon tabIcon = extractTabIcon(set);
|
||||
|
||||
return tabData.getOrDefault(tabName, new ExtensionTabData.Factory(new TabInformation(
|
||||
tabName,
|
||||
tabIcon,
|
||||
elementOrder.orElse(ElementOrder.values()),
|
||||
tabPriority.orElse(100)
|
||||
)));
|
||||
}
|
||||
|
||||
private Icon extractTabIcon(ResultSet set) throws SQLException {
|
||||
Optional<String> iconName = Optional.ofNullable(set.getString("tab_icon_name"));
|
||||
if (iconName.isPresent()) {
|
||||
Family iconFamily = Family.getByName(set.getString("tab_icon_family")).orElse(Family.SOLID);
|
||||
Color iconColor = Color.getByName(set.getString("tab_icon_color")).orElse(Color.NONE);
|
||||
return new Icon(iconFamily, iconName.get(), iconColor);
|
||||
} else {
|
||||
return TabInformation.defaultIcon();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.queries;
|
||||
|
||||
import com.djrapitops.plan.db.SQLDB;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.QueryStatement;
|
||||
import com.djrapitops.plan.db.sql.tables.*;
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
import com.djrapitops.plan.extension.FormatType;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.TabInformation;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionDescriptive;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionNumberData;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionTabData;
|
||||
import com.djrapitops.plan.extension.implementation.results.server.ExtensionServerData;
|
||||
|
||||
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;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Query aggregated boolean values from player value table.
|
||||
* <p>
|
||||
* Returns Map: PluginID - ExtensionServerData.Factory.
|
||||
* <p>
|
||||
* How it is done:
|
||||
* - Combines three queries, one that selects true boolean count, one that selects boolean value count and one that selects provider information.
|
||||
* - Data query is sorted into a multi-map: PluginID - Tab Name - Tab Data
|
||||
* - (Tab Name can be empty.)
|
||||
* - Multi-map is sorted into ExtensionPlayerData objects by PluginID, one per ID
|
||||
* <p>
|
||||
* There are multiple data extraction methods to make extracting the value query easier.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionAggregateNumbersQuery implements Query<Map<Integer, ExtensionServerData.Factory>> {
|
||||
|
||||
private final UUID serverUUID;
|
||||
|
||||
public ExtensionAggregateNumbersQuery(UUID serverUUID) {
|
||||
this.serverUUID = serverUUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, ExtensionServerData.Factory> executeQuery(SQLDB db) {
|
||||
String selectNumberAverage = SELECT +
|
||||
ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
",AVG(" + ExtensionPlayerValueTable.LONG_VALUE + ") as average" +
|
||||
FROM + ExtensionPlayerValueTable.TABLE_NAME +
|
||||
WHERE + ExtensionPlayerValueTable.LONG_VALUE + IS_NOT_NULL +
|
||||
GROUP_BY + ExtensionPlayerValueTable.PROVIDER_ID;
|
||||
|
||||
String selectNumberTotal = SELECT +
|
||||
ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
",SUM(" + ExtensionPlayerValueTable.LONG_VALUE + ") as total" +
|
||||
FROM + ExtensionPlayerValueTable.TABLE_NAME +
|
||||
WHERE + ExtensionPlayerValueTable.LONG_VALUE + IS_NOT_NULL +
|
||||
GROUP_BY + ExtensionPlayerValueTable.PROVIDER_ID;
|
||||
|
||||
String sql = SELECT +
|
||||
"b1.total as total," +
|
||||
"b2.average as average," +
|
||||
"p1." + ExtensionProviderTable.PLUGIN_ID + " as plugin_id," +
|
||||
"p1." + ExtensionProviderTable.PROVIDER_NAME + " as provider_name," +
|
||||
"p1." + ExtensionProviderTable.TEXT + " as text," +
|
||||
"p1." + ExtensionProviderTable.DESCRIPTION + " as description," +
|
||||
"p1." + ExtensionProviderTable.PRIORITY + " as provider_priority," +
|
||||
"p1." + ExtensionProviderTable.FORMAT_TYPE + " as format_type," +
|
||||
"p1." + ExtensionProviderTable.IS_PLAYER_NAME + " as is_player_name," +
|
||||
"t1." + ExtensionTabTable.TAB_NAME + " as tab_name," +
|
||||
"t1." + ExtensionTabTable.TAB_PRIORITY + " as tab_priority," +
|
||||
"t1." + ExtensionTabTable.ELEMENT_ORDER + " as element_order," +
|
||||
"i1." + ExtensionIconTable.ICON_NAME + " as provider_icon_name," +
|
||||
"i1." + ExtensionIconTable.FAMILY + " as provider_icon_family," +
|
||||
"i1." + ExtensionIconTable.COLOR + " as provider_icon_color," +
|
||||
"i2." + ExtensionIconTable.ICON_NAME + " as tab_icon_name," +
|
||||
"i2." + ExtensionIconTable.FAMILY + " as tab_icon_family," +
|
||||
"i2." + ExtensionIconTable.COLOR + " as tab_icon_color" +
|
||||
FROM + '(' + selectNumberTotal + ") b1" +
|
||||
INNER_JOIN + ExtensionProviderTable.TABLE_NAME + " p1 on p1." + ExtensionProviderTable.ID + "=b1." + ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
INNER_JOIN + ExtensionPluginTable.TABLE_NAME + " e1 on p1." + ExtensionProviderTable.PLUGIN_ID + "=e1." + ExtensionPluginTable.ID +
|
||||
LEFT_JOIN + '(' + selectNumberAverage + ") b2 on b2." + ExtensionPlayerValueTable.PROVIDER_ID + "=b1." + ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
LEFT_JOIN + ExtensionTabTable.TABLE_NAME + " t1 on t1." + ExtensionTabTable.ID + "=p1." + ExtensionProviderTable.TAB_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i1 on i1." + ExtensionIconTable.ID + "=p1." + ExtensionProviderTable.ICON_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i2 on i2." + ExtensionIconTable.ID + "=p1." + ExtensionTabTable.ICON_ID +
|
||||
WHERE + ExtensionPluginTable.SERVER_UUID + "=?" +
|
||||
AND + "p1." + ExtensionProviderTable.HIDDEN + "=?" +
|
||||
AND + "p1." + ExtensionProviderTable.FORMAT_TYPE + "!=?" +
|
||||
AND + "p1." + ExtensionProviderTable.FORMAT_TYPE + "!=?";
|
||||
|
||||
return db.query(new QueryStatement<Map<Integer, ExtensionServerData.Factory>>(sql, 1000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
statement.setBoolean(2, false); // Don't select hidden values
|
||||
statement.setString(3, FormatType.DATE_YEAR.name());
|
||||
statement.setString(4, FormatType.DATE_SECOND.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, ExtensionServerData.Factory> processResults(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = extractTabDataByPluginID(set);
|
||||
return ExtensionServerDataQuery.flatMapToServerData(tabDataByPluginID);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Map<Integer, Map<String, ExtensionTabData.Factory>> extractTabDataByPluginID(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = new HashMap<>();
|
||||
|
||||
while (set.next()) {
|
||||
int pluginID = set.getInt("plugin_id");
|
||||
Map<String, ExtensionTabData.Factory> tabData = tabDataByPluginID.getOrDefault(pluginID, new HashMap<>());
|
||||
|
||||
String tabName = Optional.ofNullable(set.getString("tab_name")).orElse("");
|
||||
ExtensionTabData.Factory inMap = tabData.get(tabName);
|
||||
ExtensionTabData.Factory extensionTab = inMap != null ? inMap : extractTab(tabName, set, tabData);
|
||||
|
||||
ExtensionDescriptive extensionDescriptive = extractDescriptive(set);
|
||||
extractAndPutDataTo(extensionTab, extensionDescriptive, set);
|
||||
|
||||
tabData.put(tabName, extensionTab);
|
||||
tabDataByPluginID.put(pluginID, tabData);
|
||||
}
|
||||
return tabDataByPluginID;
|
||||
}
|
||||
|
||||
private void extractAndPutDataTo(ExtensionTabData.Factory extensionTab, ExtensionDescriptive descriptive, ResultSet set) throws SQLException {
|
||||
FormatType formatType = FormatType.getByName(set.getString(ExtensionProviderTable.FORMAT_TYPE)).orElse(FormatType.NONE);
|
||||
extensionTab.putNumberData(new ExtensionNumberData(modifiedDescriptive(descriptive, "_avg", "Average "), formatType, set.getLong("average")));
|
||||
extensionTab.putNumberData(new ExtensionNumberData(modifiedDescriptive(descriptive, "_total", "Total "), formatType, set.getLong("total")));
|
||||
}
|
||||
|
||||
private ExtensionDescriptive modifiedDescriptive(ExtensionDescriptive descriptive, String appendToName, String appendToText) {
|
||||
return new ExtensionDescriptive(descriptive.getName() + appendToName, appendToText + descriptive.getText(), descriptive.getDescription().orElse(null), descriptive.getIcon(), descriptive.getPriority());
|
||||
}
|
||||
|
||||
private ExtensionDescriptive extractDescriptive(ResultSet set) throws SQLException {
|
||||
String name = set.getString("provider_name");
|
||||
String text = set.getString(ExtensionProviderTable.TEXT);
|
||||
String description = set.getString(ExtensionProviderTable.DESCRIPTION);
|
||||
int priority = set.getInt("provider_priority");
|
||||
|
||||
String iconName = set.getString("provider_icon_name");
|
||||
Family family = Family.getByName(set.getString("provider_icon_family")).orElse(Family.SOLID);
|
||||
Color color = Color.getByName(set.getString("provider_icon_color")).orElse(Color.NONE);
|
||||
Icon icon = new Icon(family, iconName, color);
|
||||
|
||||
return new ExtensionDescriptive(name, text, description, icon, priority);
|
||||
}
|
||||
|
||||
private ExtensionTabData.Factory extractTab(String tabName, ResultSet set, Map<String, ExtensionTabData.Factory> tabData) throws SQLException {
|
||||
Optional<Integer> tabPriority = Optional.of(set.getInt("tab_priority"));
|
||||
if (set.wasNull()) {
|
||||
tabPriority = Optional.empty();
|
||||
}
|
||||
Optional<ElementOrder[]> elementOrder = Optional.ofNullable(set.getString(ExtensionTabTable.ELEMENT_ORDER)).map(ElementOrder::deserialize);
|
||||
|
||||
Icon tabIcon = extractTabIcon(set);
|
||||
|
||||
return tabData.getOrDefault(tabName, new ExtensionTabData.Factory(new TabInformation(
|
||||
tabName,
|
||||
tabIcon,
|
||||
elementOrder.orElse(ElementOrder.values()),
|
||||
tabPriority.orElse(100)
|
||||
)));
|
||||
}
|
||||
|
||||
private Icon extractTabIcon(ResultSet set) throws SQLException {
|
||||
Optional<String> iconName = Optional.ofNullable(set.getString("tab_icon_name"));
|
||||
if (iconName.isPresent()) {
|
||||
Family iconFamily = Family.getByName(set.getString("tab_icon_family")).orElse(Family.SOLID);
|
||||
Color iconColor = Color.getByName(set.getString("tab_icon_color")).orElse(Color.NONE);
|
||||
return new Icon(iconFamily, iconName.get(), iconColor);
|
||||
} else {
|
||||
return TabInformation.defaultIcon();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.queries;
|
||||
|
||||
import com.djrapitops.plan.db.SQLDB;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.QueryStatement;
|
||||
import com.djrapitops.plan.db.sql.tables.*;
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.TabInformation;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionDescriptive;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionDoubleData;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionTabData;
|
||||
import com.djrapitops.plan.extension.implementation.results.server.ExtensionServerData;
|
||||
|
||||
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;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Query aggregated boolean values from player value table.
|
||||
* <p>
|
||||
* Returns Map: PluginID - ExtensionServerData.Factory.
|
||||
* <p>
|
||||
* How it is done:
|
||||
* - Combines three queries, one that selects true boolean count, one that selects boolean value count and one that selects provider information.
|
||||
* - Data query is sorted into a multi-map: PluginID - Tab Name - Tab Data
|
||||
* - (Tab Name can be empty.)
|
||||
* - Multi-map is sorted into ExtensionPlayerData objects by PluginID, one per ID
|
||||
* <p>
|
||||
* There are multiple data extraction methods to make extracting the value query easier.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionAggregatePercentagesQuery implements Query<Map<Integer, ExtensionServerData.Factory>> {
|
||||
|
||||
private final UUID serverUUID;
|
||||
|
||||
public ExtensionAggregatePercentagesQuery(UUID serverUUID) {
|
||||
this.serverUUID = serverUUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, ExtensionServerData.Factory> executeQuery(SQLDB db) {
|
||||
String selectPercentageAverage = SELECT +
|
||||
ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
",AVG(" + ExtensionPlayerValueTable.PERCENTAGE_VALUE + ") as average" +
|
||||
FROM + ExtensionPlayerValueTable.TABLE_NAME +
|
||||
WHERE + ExtensionPlayerValueTable.PERCENTAGE_VALUE + IS_NOT_NULL +
|
||||
GROUP_BY + ExtensionPlayerValueTable.PROVIDER_ID;
|
||||
|
||||
String sql = SELECT +
|
||||
"b1.average as average," +
|
||||
"p1." + ExtensionProviderTable.PLUGIN_ID + " as plugin_id," +
|
||||
"p1." + ExtensionProviderTable.PROVIDER_NAME + " as provider_name," +
|
||||
"p1." + ExtensionProviderTable.TEXT + " as text," +
|
||||
"p1." + ExtensionProviderTable.DESCRIPTION + " as description," +
|
||||
"p1." + ExtensionProviderTable.PRIORITY + " as provider_priority," +
|
||||
"p1." + ExtensionProviderTable.IS_PLAYER_NAME + " as is_player_name," +
|
||||
"t1." + ExtensionTabTable.TAB_NAME + " as tab_name," +
|
||||
"t1." + ExtensionTabTable.TAB_PRIORITY + " as tab_priority," +
|
||||
"t1." + ExtensionTabTable.ELEMENT_ORDER + " as element_order," +
|
||||
"i1." + ExtensionIconTable.ICON_NAME + " as provider_icon_name," +
|
||||
"i1." + ExtensionIconTable.FAMILY + " as provider_icon_family," +
|
||||
"i1." + ExtensionIconTable.COLOR + " as provider_icon_color," +
|
||||
"i2." + ExtensionIconTable.ICON_NAME + " as tab_icon_name," +
|
||||
"i2." + ExtensionIconTable.FAMILY + " as tab_icon_family," +
|
||||
"i2." + ExtensionIconTable.COLOR + " as tab_icon_color" +
|
||||
FROM + '(' + selectPercentageAverage + ") b1" +
|
||||
INNER_JOIN + ExtensionProviderTable.TABLE_NAME + " p1 on p1." + ExtensionProviderTable.ID + "=b1." + ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
INNER_JOIN + ExtensionPluginTable.TABLE_NAME + " e1 on p1." + ExtensionProviderTable.PLUGIN_ID + "=e1." + ExtensionPluginTable.ID +
|
||||
LEFT_JOIN + ExtensionTabTable.TABLE_NAME + " t1 on t1." + ExtensionTabTable.ID + "=p1." + ExtensionProviderTable.TAB_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i1 on i1." + ExtensionIconTable.ID + "=p1." + ExtensionProviderTable.ICON_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i2 on i2." + ExtensionIconTable.ID + "=p1." + ExtensionTabTable.ICON_ID +
|
||||
WHERE + ExtensionPluginTable.SERVER_UUID + "=?" +
|
||||
AND + "p1." + ExtensionProviderTable.HIDDEN + "=?";
|
||||
|
||||
return db.query(new QueryStatement<Map<Integer, ExtensionServerData.Factory>>(sql, 1000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
statement.setBoolean(2, false); // Don't select hidden values
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, ExtensionServerData.Factory> processResults(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = extractTabDataByPluginID(set);
|
||||
return ExtensionServerDataQuery.flatMapToServerData(tabDataByPluginID);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Map<Integer, Map<String, ExtensionTabData.Factory>> extractTabDataByPluginID(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = new HashMap<>();
|
||||
|
||||
while (set.next()) {
|
||||
int pluginID = set.getInt("plugin_id");
|
||||
Map<String, ExtensionTabData.Factory> tabData = tabDataByPluginID.getOrDefault(pluginID, new HashMap<>());
|
||||
|
||||
String tabName = Optional.ofNullable(set.getString("tab_name")).orElse("");
|
||||
ExtensionTabData.Factory inMap = tabData.get(tabName);
|
||||
ExtensionTabData.Factory extensionTab = inMap != null ? inMap : extractTab(tabName, set, tabData);
|
||||
|
||||
ExtensionDescriptive extensionDescriptive = extractDescriptive(set);
|
||||
extractAndPutDataTo(extensionTab, extensionDescriptive, set);
|
||||
|
||||
tabData.put(tabName, extensionTab);
|
||||
tabDataByPluginID.put(pluginID, tabData);
|
||||
}
|
||||
return tabDataByPluginID;
|
||||
}
|
||||
|
||||
private void extractAndPutDataTo(ExtensionTabData.Factory extensionTab, ExtensionDescriptive descriptive, ResultSet set) throws SQLException {
|
||||
extensionTab.putPercentageData(new ExtensionDoubleData(modifiedDescriptive(descriptive, "_avg", "Average "), set.getDouble("average")));
|
||||
}
|
||||
|
||||
private ExtensionDescriptive modifiedDescriptive(ExtensionDescriptive descriptive, String appendToName, String appendToText) {
|
||||
return new ExtensionDescriptive(descriptive.getName() + appendToName, appendToText + descriptive.getText(), descriptive.getDescription().orElse(null), descriptive.getIcon(), descriptive.getPriority());
|
||||
}
|
||||
|
||||
private ExtensionDescriptive extractDescriptive(ResultSet set) throws SQLException {
|
||||
String name = set.getString("provider_name");
|
||||
String text = set.getString(ExtensionProviderTable.TEXT);
|
||||
String description = set.getString(ExtensionProviderTable.DESCRIPTION);
|
||||
int priority = set.getInt("provider_priority");
|
||||
|
||||
String iconName = set.getString("provider_icon_name");
|
||||
Family family = Family.getByName(set.getString("provider_icon_family")).orElse(Family.SOLID);
|
||||
Color color = Color.getByName(set.getString("provider_icon_color")).orElse(Color.NONE);
|
||||
Icon icon = new Icon(family, iconName, color);
|
||||
|
||||
return new ExtensionDescriptive(name, text, description, icon, priority);
|
||||
}
|
||||
|
||||
private ExtensionTabData.Factory extractTab(String tabName, ResultSet set, Map<String, ExtensionTabData.Factory> tabData) throws SQLException {
|
||||
Optional<Integer> tabPriority = Optional.of(set.getInt("tab_priority"));
|
||||
if (set.wasNull()) {
|
||||
tabPriority = Optional.empty();
|
||||
}
|
||||
Optional<ElementOrder[]> elementOrder = Optional.ofNullable(set.getString(ExtensionTabTable.ELEMENT_ORDER)).map(ElementOrder::deserialize);
|
||||
|
||||
Icon tabIcon = extractTabIcon(set);
|
||||
|
||||
return tabData.getOrDefault(tabName, new ExtensionTabData.Factory(new TabInformation(
|
||||
tabName,
|
||||
tabIcon,
|
||||
elementOrder.orElse(ElementOrder.values()),
|
||||
tabPriority.orElse(100)
|
||||
)));
|
||||
}
|
||||
|
||||
private Icon extractTabIcon(ResultSet set) throws SQLException {
|
||||
Optional<String> iconName = Optional.ofNullable(set.getString("tab_icon_name"));
|
||||
if (iconName.isPresent()) {
|
||||
Family iconFamily = Family.getByName(set.getString("tab_icon_family")).orElse(Family.SOLID);
|
||||
Color iconColor = Color.getByName(set.getString("tab_icon_color")).orElse(Color.NONE);
|
||||
return new Icon(iconFamily, iconName.get(), iconColor);
|
||||
} else {
|
||||
return TabInformation.defaultIcon();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.queries;
|
||||
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.QueryAllStatement;
|
||||
import com.djrapitops.plan.db.access.QueryStatement;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionIconTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionPluginTable;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.results.ExtensionInformation;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Queries for information about DataExtensions stored in the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionInformationQueries {
|
||||
|
||||
private ExtensionInformationQueries() {
|
||||
/* Static method class */
|
||||
}
|
||||
|
||||
public static Query<List<ExtensionInformation>> extensionsOfServer(UUID serverUUID) {
|
||||
String sql = SELECT +
|
||||
ExtensionPluginTable.TABLE_NAME + '.' + ExtensionPluginTable.ID + " as id," +
|
||||
ExtensionPluginTable.TABLE_NAME + '.' + ExtensionPluginTable.PLUGIN_NAME + " as plugin_name," +
|
||||
ExtensionIconTable.TABLE_NAME + '.' + ExtensionIconTable.ICON_NAME + " as icon_name," +
|
||||
ExtensionIconTable.COLOR + ',' +
|
||||
ExtensionIconTable.FAMILY +
|
||||
FROM + ExtensionPluginTable.TABLE_NAME +
|
||||
INNER_JOIN + ExtensionIconTable.TABLE_NAME + " on " +
|
||||
ExtensionPluginTable.ICON_ID + "=" + ExtensionIconTable.TABLE_NAME + '.' + ExtensionIconTable.ID +
|
||||
WHERE + ExtensionPluginTable.SERVER_UUID + "=?";
|
||||
|
||||
return new QueryStatement<List<ExtensionInformation>>(sql, 100) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExtensionInformation> processResults(ResultSet set) throws SQLException {
|
||||
List<ExtensionInformation> information = new ArrayList<>();
|
||||
while (set.next()) {
|
||||
information.add(extractExtensionInformationFromQuery(set));
|
||||
}
|
||||
return information;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static ExtensionInformation extractExtensionInformationFromQuery(ResultSet set) throws SQLException {
|
||||
int id = set.getInt("id");
|
||||
String pluginName = set.getString("plugin_name");
|
||||
|
||||
String iconName = set.getString("icon_name");
|
||||
Family iconFamily = Family.getByName(set.getString(ExtensionIconTable.FAMILY)).orElse(Family.SOLID);
|
||||
Color color = Color.getByName(set.getString(ExtensionIconTable.COLOR)).orElse(Color.NONE);
|
||||
Icon icon = new Icon(iconFamily, iconName, color);
|
||||
|
||||
return new ExtensionInformation(id, pluginName, icon);
|
||||
}
|
||||
|
||||
public static Query<Map<UUID, List<ExtensionInformation>>> allExtensions() {
|
||||
String sql = SELECT +
|
||||
ExtensionPluginTable.TABLE_NAME + '.' + ExtensionPluginTable.ID + " as id," +
|
||||
ExtensionPluginTable.TABLE_NAME + '.' + ExtensionPluginTable.PLUGIN_NAME + " as plugin_name," +
|
||||
ExtensionPluginTable.SERVER_UUID + ',' +
|
||||
ExtensionIconTable.TABLE_NAME + '.' + ExtensionIconTable.ICON_NAME + " as icon_name," +
|
||||
ExtensionIconTable.COLOR + ',' +
|
||||
ExtensionIconTable.FAMILY +
|
||||
FROM + ExtensionPluginTable.TABLE_NAME +
|
||||
INNER_JOIN + ExtensionIconTable.TABLE_NAME + " on " +
|
||||
ExtensionPluginTable.ICON_ID + "=" + ExtensionIconTable.TABLE_NAME + '.' + ExtensionIconTable.ID;
|
||||
|
||||
return new QueryAllStatement<Map<UUID, List<ExtensionInformation>>>(sql, 100) {
|
||||
@Override
|
||||
public Map<UUID, List<ExtensionInformation>> processResults(ResultSet set) throws SQLException {
|
||||
Map<UUID, List<ExtensionInformation>> byServerUUID = new HashMap<>();
|
||||
while (set.next()) {
|
||||
UUID serverUUID = UUID.fromString(set.getString(ExtensionPluginTable.SERVER_UUID));
|
||||
List<ExtensionInformation> information = byServerUUID.getOrDefault(serverUUID, new ArrayList<>());
|
||||
information.add(extractExtensionInformationFromQuery(set));
|
||||
byServerUUID.put(serverUUID, information);
|
||||
}
|
||||
return byServerUUID;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.queries;
|
||||
|
||||
import com.djrapitops.plan.db.SQLDB;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.QueryStatement;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionIconTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionPlayerValueTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionProviderTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionTabTable;
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
import com.djrapitops.plan.extension.FormatType;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.TabInformation;
|
||||
import com.djrapitops.plan.extension.implementation.results.*;
|
||||
import com.djrapitops.plan.extension.implementation.results.player.ExtensionPlayerData;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Query all ExtensionPlayerData by Server UUIDs.
|
||||
* <p>
|
||||
* Returns Map: Server UUID - List of ExtensionPlayerData.
|
||||
* <p>
|
||||
* How it is done:
|
||||
* - Two queries are run, one that fetches all extensions and one that fetches all data of the player.
|
||||
* - Data query is sorted into a multi-map: PluginID - Tab Name - Tab Data
|
||||
* - (Tab Name can be empty.)
|
||||
* - Multi-map is sorted into ExtensionPlayerData objects by PluginID, one per ID
|
||||
* - This map is sorted into final Map: Server UUID - List of ExtensionPlayerData at the highest level.
|
||||
* <p>
|
||||
* There are multiple data extraction methods to make extracting the value query easier.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionPlayerDataQuery implements Query<Map<UUID, List<ExtensionPlayerData>>> {
|
||||
|
||||
private final UUID playerUUID;
|
||||
|
||||
public ExtensionPlayerDataQuery(UUID playerUUID) {
|
||||
this.playerUUID = playerUUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, List<ExtensionPlayerData>> executeQuery(SQLDB db) {
|
||||
Map<UUID, List<ExtensionInformation>> extensionsByServerUUID = db.query(ExtensionInformationQueries.allExtensions());
|
||||
Map<Integer, ExtensionPlayerData.Factory> extensionDataByPluginID = db.query(fetchIncompletePlayerDataByPluginID());
|
||||
|
||||
return flatMapByServerUUID(extensionsByServerUUID, extensionDataByPluginID);
|
||||
}
|
||||
|
||||
private Map<UUID, List<ExtensionPlayerData>> flatMapByServerUUID(Map<UUID, List<ExtensionInformation>> extensionsByServerUUID, Map<Integer, ExtensionPlayerData.Factory> extensionDataByPluginID) {
|
||||
Map<UUID, List<ExtensionPlayerData>> extensionDataByServerUUID = new HashMap<>();
|
||||
|
||||
for (Map.Entry<UUID, List<ExtensionInformation>> entry : extensionsByServerUUID.entrySet()) {
|
||||
UUID serverUUID = entry.getKey();
|
||||
for (ExtensionInformation extensionInformation : entry.getValue()) {
|
||||
ExtensionPlayerData.Factory data = extensionDataByPluginID.get(extensionInformation.getId());
|
||||
if (data == null) {
|
||||
continue;
|
||||
}
|
||||
List<ExtensionPlayerData> list = extensionDataByServerUUID.getOrDefault(serverUUID, new ArrayList<>());
|
||||
list.add(data.setInformation(extensionInformation).build());
|
||||
extensionDataByServerUUID.put(serverUUID, list);
|
||||
}
|
||||
}
|
||||
return extensionDataByServerUUID;
|
||||
}
|
||||
|
||||
private Query<Map<Integer, ExtensionPlayerData.Factory>> fetchIncompletePlayerDataByPluginID() {
|
||||
String sql = SELECT +
|
||||
"v1." + ExtensionPlayerValueTable.BOOLEAN_VALUE + " as boolean_value," +
|
||||
"v1." + ExtensionPlayerValueTable.DOUBLE_VALUE + " as double_value," +
|
||||
"v1." + ExtensionPlayerValueTable.PERCENTAGE_VALUE + " as percentage_value," +
|
||||
"v1." + ExtensionPlayerValueTable.LONG_VALUE + " as long_value," +
|
||||
"v1." + ExtensionPlayerValueTable.STRING_VALUE + " as string_value," +
|
||||
"p1." + ExtensionProviderTable.PLUGIN_ID + " as plugin_id," +
|
||||
"p1." + ExtensionProviderTable.PROVIDER_NAME + " as provider_name," +
|
||||
"p1." + ExtensionProviderTable.TEXT + " as text," +
|
||||
"p1." + ExtensionProviderTable.DESCRIPTION + " as description," +
|
||||
"p1." + ExtensionProviderTable.PRIORITY + " as provider_priority," +
|
||||
"p1." + ExtensionProviderTable.FORMAT_TYPE + " as format_type," +
|
||||
"p1." + ExtensionProviderTable.IS_PLAYER_NAME + " as is_player_name," +
|
||||
"t1." + ExtensionTabTable.TAB_NAME + " as tab_name," +
|
||||
"t1." + ExtensionTabTable.TAB_PRIORITY + " as tab_priority," +
|
||||
"t1." + ExtensionTabTable.ELEMENT_ORDER + " as element_order," +
|
||||
"i1." + ExtensionIconTable.ICON_NAME + " as provider_icon_name," +
|
||||
"i1." + ExtensionIconTable.FAMILY + " as provider_icon_family," +
|
||||
"i1." + ExtensionIconTable.COLOR + " as provider_icon_color," +
|
||||
"i2." + ExtensionIconTable.ICON_NAME + " as tab_icon_name," +
|
||||
"i2." + ExtensionIconTable.FAMILY + " as tab_icon_family," +
|
||||
"i2." + ExtensionIconTable.COLOR + " as tab_icon_color" +
|
||||
FROM + ExtensionPlayerValueTable.TABLE_NAME + " v1" +
|
||||
INNER_JOIN + ExtensionProviderTable.TABLE_NAME + " p1 on p1." + ExtensionProviderTable.ID + "=v1." + ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
LEFT_JOIN + ExtensionTabTable.TABLE_NAME + " t1 on t1." + ExtensionTabTable.ID + "=p1." + ExtensionProviderTable.TAB_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i1 on i1." + ExtensionIconTable.ID + "=p1." + ExtensionProviderTable.ICON_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i2 on i2." + ExtensionIconTable.ID + "=p1." + ExtensionTabTable.ICON_ID +
|
||||
WHERE + ExtensionPlayerValueTable.USER_UUID + "=?" +
|
||||
AND + "p1." + ExtensionProviderTable.HIDDEN + "=?";
|
||||
|
||||
return new QueryStatement<Map<Integer, ExtensionPlayerData.Factory>>(sql, 1000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
statement.setBoolean(2, false); // Don't select hidden values
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, ExtensionPlayerData.Factory> processResults(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = extractTabDataByPluginID(set);
|
||||
return flatMapToPlayerData(tabDataByPluginID);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Map<Integer, ExtensionPlayerData.Factory> flatMapToPlayerData(Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID) {
|
||||
Map<Integer, ExtensionPlayerData.Factory> dataByPluginID = new HashMap<>();
|
||||
for (Map.Entry<Integer, Map<String, ExtensionTabData.Factory>> entry : tabDataByPluginID.entrySet()) {
|
||||
Integer pluginID = entry.getKey();
|
||||
ExtensionPlayerData.Factory data = dataByPluginID.getOrDefault(pluginID, new ExtensionPlayerData.Factory(pluginID));
|
||||
for (ExtensionTabData.Factory tabData : entry.getValue().values()) {
|
||||
data.addTab(tabData.build());
|
||||
}
|
||||
dataByPluginID.put(pluginID, data);
|
||||
}
|
||||
return dataByPluginID;
|
||||
}
|
||||
|
||||
private Map<Integer, Map<String, ExtensionTabData.Factory>> extractTabDataByPluginID(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = new HashMap<>();
|
||||
|
||||
while (set.next()) {
|
||||
int pluginID = set.getInt("plugin_id");
|
||||
Map<String, ExtensionTabData.Factory> tabData = tabDataByPluginID.getOrDefault(pluginID, new HashMap<>());
|
||||
|
||||
String tabName = Optional.ofNullable(set.getString("tab_name")).orElse("");
|
||||
ExtensionTabData.Factory inMap = tabData.get(tabName);
|
||||
ExtensionTabData.Factory extensionTab = inMap != null ? inMap : extractTab(tabName, set, tabData);
|
||||
|
||||
ExtensionDescriptive extensionDescriptive = extractDescriptive(set);
|
||||
extractAndPutDataTo(extensionTab, extensionDescriptive, set);
|
||||
|
||||
tabData.put(tabName, extensionTab);
|
||||
tabDataByPluginID.put(pluginID, tabData);
|
||||
}
|
||||
return tabDataByPluginID;
|
||||
}
|
||||
|
||||
private void extractAndPutDataTo(ExtensionTabData.Factory extensionTab, ExtensionDescriptive descriptive, ResultSet set) throws SQLException {
|
||||
boolean booleanValue = set.getBoolean(ExtensionPlayerValueTable.BOOLEAN_VALUE);
|
||||
if (!set.wasNull()) {
|
||||
extensionTab.putBooleanData(new ExtensionBooleanData(descriptive, booleanValue));
|
||||
return;
|
||||
}
|
||||
|
||||
double doubleValue = set.getDouble(ExtensionPlayerValueTable.DOUBLE_VALUE);
|
||||
if (!set.wasNull()) {
|
||||
extensionTab.putDoubleData(new ExtensionDoubleData(descriptive, doubleValue));
|
||||
return;
|
||||
}
|
||||
|
||||
double percentageValue = set.getDouble(ExtensionPlayerValueTable.PERCENTAGE_VALUE);
|
||||
if (!set.wasNull()) {
|
||||
extensionTab.putPercentageData(new ExtensionDoubleData(descriptive, percentageValue));
|
||||
return;
|
||||
}
|
||||
|
||||
long numberValue = set.getLong(ExtensionPlayerValueTable.LONG_VALUE);
|
||||
if (!set.wasNull()) {
|
||||
FormatType formatType = FormatType.getByName(set.getString(ExtensionProviderTable.FORMAT_TYPE)).orElse(FormatType.NONE);
|
||||
extensionTab.putNumberData(new ExtensionNumberData(descriptive, formatType, numberValue));
|
||||
return;
|
||||
}
|
||||
|
||||
String stringValue = set.getString(ExtensionPlayerValueTable.STRING_VALUE);
|
||||
if (stringValue != null) {
|
||||
boolean isPlayerName = set.getBoolean("is_player_name");
|
||||
extensionTab.putStringData(new ExtensionStringData(descriptive, isPlayerName, stringValue));
|
||||
}
|
||||
}
|
||||
|
||||
private ExtensionDescriptive extractDescriptive(ResultSet set) throws SQLException {
|
||||
String name = set.getString("provider_name");
|
||||
String text = set.getString(ExtensionProviderTable.TEXT);
|
||||
String description = set.getString(ExtensionProviderTable.DESCRIPTION);
|
||||
int priority = set.getInt("provider_priority");
|
||||
|
||||
String iconName = set.getString("provider_icon_name");
|
||||
Family family = Family.getByName(set.getString("provider_icon_family")).orElse(Family.SOLID);
|
||||
Color color = Color.getByName(set.getString("provider_icon_color")).orElse(Color.NONE);
|
||||
Icon icon = new Icon(family, iconName, color);
|
||||
|
||||
return new ExtensionDescriptive(name, text, description, icon, priority);
|
||||
}
|
||||
|
||||
private ExtensionTabData.Factory extractTab(String tabName, ResultSet set, Map<String, ExtensionTabData.Factory> tabData) throws SQLException {
|
||||
Optional<Integer> tabPriority = Optional.of(set.getInt("tab_priority"));
|
||||
if (set.wasNull()) {
|
||||
tabPriority = Optional.empty();
|
||||
}
|
||||
Optional<ElementOrder[]> elementOrder = Optional.ofNullable(set.getString(ExtensionTabTable.ELEMENT_ORDER)).map(ElementOrder::deserialize);
|
||||
|
||||
Icon tabIcon = extractTabIcon(set);
|
||||
|
||||
return tabData.getOrDefault(tabName, new ExtensionTabData.Factory(new TabInformation(
|
||||
tabName,
|
||||
tabIcon,
|
||||
elementOrder.orElse(ElementOrder.values()),
|
||||
tabPriority.orElse(100)
|
||||
)));
|
||||
}
|
||||
|
||||
private Icon extractTabIcon(ResultSet set) throws SQLException {
|
||||
Optional<String> iconName = Optional.ofNullable(set.getString("tab_icon_name"));
|
||||
if (iconName.isPresent()) {
|
||||
Family iconFamily = Family.getByName(set.getString("tab_icon_family")).orElse(Family.SOLID);
|
||||
Color iconColor = Color.getByName(set.getString("tab_icon_color")).orElse(Color.NONE);
|
||||
return new Icon(iconFamily, iconName.get(), iconColor);
|
||||
} else {
|
||||
return TabInformation.defaultIcon();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.queries;
|
||||
|
||||
import com.djrapitops.plan.db.SQLDB;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.QueryStatement;
|
||||
import com.djrapitops.plan.db.sql.tables.*;
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
import com.djrapitops.plan.extension.FormatType;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Family;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.implementation.TabInformation;
|
||||
import com.djrapitops.plan.extension.implementation.results.*;
|
||||
import com.djrapitops.plan.extension.implementation.results.server.ExtensionServerData;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Query ExtensionServerData of a server.
|
||||
* <p>
|
||||
* Returns List of ExtensionServerData.
|
||||
* <p>
|
||||
* How it is done:
|
||||
* - Two queries are run, one that fetches all extensions and one that fetches all data of the player.
|
||||
* - Data query is sorted into a multi-map: PluginID - Tab Name - Tab Data
|
||||
* - (Tab Name can be empty.)
|
||||
* - Multi-map is sorted into ExtensionServerData objects by PluginID, one per ID
|
||||
* - This map is combined with similar maps that contain aggregated player values
|
||||
* - This map is sorted into List of ExtensionPlayerData at the highest level.
|
||||
* <p>
|
||||
* There are multiple data extraction methods to make extracting the value query easier.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionServerDataQuery implements Query<List<ExtensionServerData>> {
|
||||
|
||||
private final UUID serverUUID;
|
||||
|
||||
public ExtensionServerDataQuery(UUID serverUUID) {
|
||||
this.serverUUID = serverUUID;
|
||||
}
|
||||
|
||||
static Map<Integer, ExtensionServerData.Factory> flatMapToServerData(Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID) {
|
||||
Map<Integer, ExtensionServerData.Factory> dataByPluginID = new HashMap<>();
|
||||
for (Map.Entry<Integer, Map<String, ExtensionTabData.Factory>> entry : tabDataByPluginID.entrySet()) {
|
||||
Integer pluginID = entry.getKey();
|
||||
ExtensionServerData.Factory data = dataByPluginID.getOrDefault(pluginID, new ExtensionServerData.Factory(pluginID));
|
||||
for (ExtensionTabData.Factory tabData : entry.getValue().values()) {
|
||||
data.addTab(tabData.build());
|
||||
}
|
||||
dataByPluginID.put(pluginID, data);
|
||||
}
|
||||
return dataByPluginID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExtensionServerData> executeQuery(SQLDB db) {
|
||||
List<ExtensionInformation> extensionsOfServer = db.query(ExtensionInformationQueries.extensionsOfServer(serverUUID));
|
||||
Map<Integer, ExtensionServerData.Factory> extensionDataByPluginID = db.query(fetchIncompleteServerDataByPluginID());
|
||||
|
||||
combine(extensionDataByPluginID, db.query(new ExtensionAggregateBooleansQuery(serverUUID)));
|
||||
combine(extensionDataByPluginID, db.query(new ExtensionAggregateDoublesQuery(serverUUID)));
|
||||
combine(extensionDataByPluginID, db.query(new ExtensionAggregateNumbersQuery(serverUUID)));
|
||||
combine(extensionDataByPluginID, db.query(new ExtensionAggregatePercentagesQuery(serverUUID)));
|
||||
|
||||
return combineWithExtensionInfo(extensionsOfServer, extensionDataByPluginID);
|
||||
}
|
||||
|
||||
private void combine(
|
||||
Map<Integer, ExtensionServerData.Factory> extensionDataByPluginID,
|
||||
Map<Integer, ExtensionServerData.Factory> aggregates
|
||||
) {
|
||||
for (Map.Entry<Integer, ExtensionServerData.Factory> entry : aggregates.entrySet()) {
|
||||
Integer pluginID = entry.getKey();
|
||||
ExtensionServerData.Factory data = entry.getValue();
|
||||
|
||||
ExtensionServerData.Factory found = extensionDataByPluginID.get(pluginID);
|
||||
if (found == null) {
|
||||
extensionDataByPluginID.put(pluginID, data);
|
||||
} else {
|
||||
found.combine(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<ExtensionServerData> combineWithExtensionInfo(
|
||||
List<ExtensionInformation> extensionsOfServer,
|
||||
Map<Integer, ExtensionServerData.Factory> extensionDataByPluginID
|
||||
) {
|
||||
List<ExtensionServerData> extensionServerData = new ArrayList<>();
|
||||
|
||||
for (ExtensionInformation extensionInformation : extensionsOfServer) {
|
||||
ExtensionServerData.Factory data = extensionDataByPluginID.get(extensionInformation.getId());
|
||||
if (data == null) {
|
||||
continue;
|
||||
}
|
||||
extensionServerData.add(data.setInformation(extensionInformation).build());
|
||||
}
|
||||
return extensionServerData;
|
||||
}
|
||||
|
||||
private Query<Map<Integer, ExtensionServerData.Factory>> fetchIncompleteServerDataByPluginID() {
|
||||
String sql = SELECT +
|
||||
"v1." + ExtensionServerValueTable.BOOLEAN_VALUE + " as boolean_value," +
|
||||
"v1." + ExtensionServerValueTable.DOUBLE_VALUE + " as double_value," +
|
||||
"v1." + ExtensionServerValueTable.PERCENTAGE_VALUE + " as percentage_value," +
|
||||
"v1." + ExtensionServerValueTable.LONG_VALUE + " as long_value," +
|
||||
"v1." + ExtensionServerValueTable.STRING_VALUE + " as string_value," +
|
||||
"p1." + ExtensionProviderTable.PLUGIN_ID + " as plugin_id," +
|
||||
"p1." + ExtensionProviderTable.PROVIDER_NAME + " as provider_name," +
|
||||
"p1." + ExtensionProviderTable.TEXT + " as text," +
|
||||
"p1." + ExtensionProviderTable.DESCRIPTION + " as description," +
|
||||
"p1." + ExtensionProviderTable.PRIORITY + " as provider_priority," +
|
||||
"p1." + ExtensionProviderTable.FORMAT_TYPE + " as format_type," +
|
||||
"p1." + ExtensionProviderTable.IS_PLAYER_NAME + " as is_player_name," +
|
||||
"t1." + ExtensionTabTable.TAB_NAME + " as tab_name," +
|
||||
"t1." + ExtensionTabTable.TAB_PRIORITY + " as tab_priority," +
|
||||
"t1." + ExtensionTabTable.ELEMENT_ORDER + " as element_order," +
|
||||
"i1." + ExtensionIconTable.ICON_NAME + " as provider_icon_name," +
|
||||
"i1." + ExtensionIconTable.FAMILY + " as provider_icon_family," +
|
||||
"i1." + ExtensionIconTable.COLOR + " as provider_icon_color," +
|
||||
"i2." + ExtensionIconTable.ICON_NAME + " as tab_icon_name," +
|
||||
"i2." + ExtensionIconTable.FAMILY + " as tab_icon_family," +
|
||||
"i2." + ExtensionIconTable.COLOR + " as tab_icon_color" +
|
||||
FROM + ExtensionServerValueTable.TABLE_NAME + " v1" +
|
||||
INNER_JOIN + ExtensionProviderTable.TABLE_NAME + " p1 on p1." + ExtensionProviderTable.ID + "=v1." + ExtensionServerValueTable.PROVIDER_ID +
|
||||
INNER_JOIN + ExtensionPluginTable.TABLE_NAME + " e1 on p1." + ExtensionProviderTable.PLUGIN_ID + "=e1." + ExtensionPluginTable.ID +
|
||||
LEFT_JOIN + ExtensionTabTable.TABLE_NAME + " t1 on t1." + ExtensionTabTable.ID + "=p1." + ExtensionProviderTable.TAB_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i1 on i1." + ExtensionIconTable.ID + "=p1." + ExtensionProviderTable.ICON_ID +
|
||||
LEFT_JOIN + ExtensionIconTable.TABLE_NAME + " i2 on i2." + ExtensionIconTable.ID + "=p1." + ExtensionTabTable.ICON_ID +
|
||||
WHERE + ExtensionPluginTable.SERVER_UUID + "=?" +
|
||||
AND + "p1." + ExtensionProviderTable.HIDDEN + "=?";
|
||||
|
||||
return new QueryStatement<Map<Integer, ExtensionServerData.Factory>>(sql, 1000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
statement.setBoolean(2, false); // Don't select hidden values
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, ExtensionServerData.Factory> processResults(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = extractTabDataByPluginID(set);
|
||||
return flatMapToServerData(tabDataByPluginID);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Map<Integer, Map<String, ExtensionTabData.Factory>> extractTabDataByPluginID(ResultSet set) throws SQLException {
|
||||
Map<Integer, Map<String, ExtensionTabData.Factory>> tabDataByPluginID = new HashMap<>();
|
||||
|
||||
while (set.next()) {
|
||||
int pluginID = set.getInt("plugin_id");
|
||||
Map<String, ExtensionTabData.Factory> tabData = tabDataByPluginID.getOrDefault(pluginID, new HashMap<>());
|
||||
|
||||
String tabName = Optional.ofNullable(set.getString("tab_name")).orElse("");
|
||||
ExtensionTabData.Factory inMap = tabData.get(tabName);
|
||||
ExtensionTabData.Factory extensionTab = inMap != null ? inMap : extractTab(tabName, set, tabData);
|
||||
|
||||
ExtensionDescriptive extensionDescriptive = extractDescriptive(set);
|
||||
extractAndPutDataTo(extensionTab, extensionDescriptive, set);
|
||||
|
||||
tabData.put(tabName, extensionTab);
|
||||
tabDataByPluginID.put(pluginID, tabData);
|
||||
}
|
||||
return tabDataByPluginID;
|
||||
}
|
||||
|
||||
private void extractAndPutDataTo(ExtensionTabData.Factory extensionTab, ExtensionDescriptive descriptive, ResultSet set) throws SQLException {
|
||||
boolean booleanValue = set.getBoolean(ExtensionServerValueTable.BOOLEAN_VALUE);
|
||||
if (!set.wasNull()) {
|
||||
extensionTab.putBooleanData(new ExtensionBooleanData(descriptive, booleanValue));
|
||||
return;
|
||||
}
|
||||
|
||||
double doubleValue = set.getDouble(ExtensionServerValueTable.DOUBLE_VALUE);
|
||||
if (!set.wasNull()) {
|
||||
extensionTab.putDoubleData(new ExtensionDoubleData(descriptive, doubleValue));
|
||||
return;
|
||||
}
|
||||
|
||||
double percentageValue = set.getDouble(ExtensionServerValueTable.PERCENTAGE_VALUE);
|
||||
if (!set.wasNull()) {
|
||||
extensionTab.putPercentageData(new ExtensionDoubleData(descriptive, percentageValue));
|
||||
return;
|
||||
}
|
||||
|
||||
long numberValue = set.getLong(ExtensionServerValueTable.LONG_VALUE);
|
||||
if (!set.wasNull()) {
|
||||
FormatType formatType = FormatType.getByName(set.getString(ExtensionProviderTable.FORMAT_TYPE)).orElse(FormatType.NONE);
|
||||
extensionTab.putNumberData(new ExtensionNumberData(descriptive, formatType, numberValue));
|
||||
return;
|
||||
}
|
||||
|
||||
String stringValue = set.getString(ExtensionServerValueTable.STRING_VALUE);
|
||||
if (stringValue != null) {
|
||||
boolean isPlayerName = set.getBoolean("is_player_name");
|
||||
extensionTab.putStringData(new ExtensionStringData(descriptive, isPlayerName, stringValue));
|
||||
}
|
||||
}
|
||||
|
||||
private ExtensionDescriptive extractDescriptive(ResultSet set) throws SQLException {
|
||||
String name = set.getString("provider_name");
|
||||
String text = set.getString(ExtensionProviderTable.TEXT);
|
||||
String description = set.getString(ExtensionProviderTable.DESCRIPTION);
|
||||
int priority = set.getInt("provider_priority");
|
||||
|
||||
String iconName = set.getString("provider_icon_name");
|
||||
Family family = Family.getByName(set.getString("provider_icon_family")).orElse(Family.SOLID);
|
||||
Color color = Color.getByName(set.getString("provider_icon_color")).orElse(Color.NONE);
|
||||
Icon icon = new Icon(family, iconName, color);
|
||||
|
||||
return new ExtensionDescriptive(name, text, description, icon, priority);
|
||||
}
|
||||
|
||||
private ExtensionTabData.Factory extractTab(String tabName, ResultSet set, Map<String, ExtensionTabData.Factory> tabData) throws SQLException {
|
||||
Optional<Integer> tabPriority = Optional.of(set.getInt("tab_priority"));
|
||||
if (set.wasNull()) {
|
||||
tabPriority = Optional.empty();
|
||||
}
|
||||
Optional<ElementOrder[]> elementOrder = Optional.ofNullable(set.getString(ExtensionTabTable.ELEMENT_ORDER)).map(ElementOrder::deserialize);
|
||||
|
||||
Icon tabIcon = extractTabIcon(set);
|
||||
|
||||
return tabData.getOrDefault(tabName, new ExtensionTabData.Factory(new TabInformation(
|
||||
tabName,
|
||||
tabIcon,
|
||||
elementOrder.orElse(ElementOrder.values()),
|
||||
tabPriority.orElse(100)
|
||||
)));
|
||||
}
|
||||
|
||||
private Icon extractTabIcon(ResultSet set) throws SQLException {
|
||||
Optional<String> iconName = Optional.ofNullable(set.getString("tab_icon_name"));
|
||||
if (iconName.isPresent()) {
|
||||
Family iconFamily = Family.getByName(set.getString("tab_icon_family")).orElse(Family.SOLID);
|
||||
Color iconColor = Color.getByName(set.getString("tab_icon_color")).orElse(Color.NONE);
|
||||
return new Icon(iconFamily, iconName.get(), iconColor);
|
||||
} else {
|
||||
return TabInformation.defaultIcon();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.transactions;
|
||||
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.access.HasMoreThanZeroQueryStatement;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionIconTable;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Transaction to store an Icon to the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class StoreIconTransaction extends Transaction {
|
||||
|
||||
private final Icon icon;
|
||||
|
||||
public StoreIconTransaction(Icon icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
if (!query(isIconStored())) {
|
||||
execute(insertIcon());
|
||||
}
|
||||
}
|
||||
|
||||
private Executable insertIcon() {
|
||||
String sql = "INSERT INTO " + ExtensionIconTable.TABLE_NAME + "(" +
|
||||
ExtensionIconTable.ICON_NAME + "," +
|
||||
ExtensionIconTable.FAMILY + "," +
|
||||
ExtensionIconTable.COLOR +
|
||||
") VALUES (?,?,?)";
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, icon);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Query<Boolean> isIconStored() {
|
||||
String sql = SELECT + "COUNT(1) as c" +
|
||||
FROM + ExtensionIconTable.TABLE_NAME +
|
||||
WHERE + ExtensionIconTable.ICON_NAME + "=?" +
|
||||
AND + ExtensionIconTable.FAMILY + "=?" +
|
||||
AND + ExtensionIconTable.COLOR + "=?";
|
||||
return new HasMoreThanZeroQueryStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, icon);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.transactions;
|
||||
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionIconTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionPluginTable;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.AND;
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
|
||||
|
||||
/**
|
||||
* Transaction to update command usage information in the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class StorePluginTransaction extends Transaction {
|
||||
|
||||
private final String pluginName;
|
||||
private final long time;
|
||||
private final UUID serverUUID;
|
||||
private final Icon icon;
|
||||
|
||||
public StorePluginTransaction(String pluginName, long time, UUID serverUUID, Icon icon) {
|
||||
this.pluginName = pluginName;
|
||||
this.time = time;
|
||||
this.serverUUID = serverUUID;
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(storePlugin());
|
||||
}
|
||||
|
||||
private Executable storePlugin() {
|
||||
return connection -> {
|
||||
if (!updatePlugin().execute(connection)) {
|
||||
return insertPlugin().execute(connection);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private Executable updatePlugin() {
|
||||
String sql = "UPDATE " + ExtensionPluginTable.TABLE_NAME +
|
||||
" SET " +
|
||||
ExtensionPluginTable.LAST_UPDATED + "=?," +
|
||||
ExtensionPluginTable.ICON_ID + "=" + ExtensionIconTable.STATEMENT_SELECT_ICON_ID +
|
||||
WHERE + ExtensionPluginTable.PLUGIN_NAME + "=?" +
|
||||
AND + ExtensionPluginTable.SERVER_UUID + "=?";
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setLong(1, time);
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 2, icon);
|
||||
statement.setString(5, pluginName);
|
||||
statement.setString(6, serverUUID.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Executable insertPlugin() {
|
||||
String sql = "INSERT INTO " + ExtensionPluginTable.TABLE_NAME + "(" +
|
||||
ExtensionPluginTable.PLUGIN_NAME + "," +
|
||||
ExtensionPluginTable.LAST_UPDATED + "," +
|
||||
ExtensionPluginTable.SERVER_UUID + "," +
|
||||
ExtensionPluginTable.ICON_ID +
|
||||
") VALUES (?,?,?," + ExtensionIconTable.STATEMENT_SELECT_ICON_ID + ")";
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, pluginName);
|
||||
statement.setLong(2, time);
|
||||
statement.setString(3, serverUUID.toString());
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 4, icon);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.transactions;
|
||||
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionIconTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionPluginTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionTabTable;
|
||||
import com.djrapitops.plan.extension.ElementOrder;
|
||||
import com.djrapitops.plan.extension.implementation.TabInformation;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.AND;
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
|
||||
|
||||
/**
|
||||
* Transaction for storing {@link TabInformation}s.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class StoreTabInformationTransaction extends Transaction {
|
||||
|
||||
private final String pluginName;
|
||||
private final UUID serverUUID;
|
||||
private final TabInformation tabInformation;
|
||||
|
||||
public StoreTabInformationTransaction(String pluginName, UUID serverUUID, TabInformation tabInformation) {
|
||||
this.pluginName = pluginName;
|
||||
this.serverUUID = serverUUID;
|
||||
this.tabInformation = tabInformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(storeTab());
|
||||
}
|
||||
|
||||
private Executable storeTab() {
|
||||
return connection -> {
|
||||
if (!updateTab().execute(connection)) {
|
||||
return insertTab().execute(connection);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private Executable updateTab() {
|
||||
String sql = "UPDATE " + ExtensionTabTable.TABLE_NAME +
|
||||
" SET " +
|
||||
ExtensionTabTable.TAB_PRIORITY + "=?," +
|
||||
ExtensionTabTable.ELEMENT_ORDER + "=?," +
|
||||
ExtensionTabTable.ICON_ID + "=" + ExtensionIconTable.STATEMENT_SELECT_ICON_ID + "," +
|
||||
WHERE + ExtensionTabTable.PLUGIN_ID + "=" + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID +
|
||||
AND + ExtensionTabTable.TAB_NAME + "=?";
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setInt(1, tabInformation.getTabPriority());
|
||||
statement.setString(2, tabInformation.getTabElementOrder().map(ElementOrder::serialize).orElse(null));
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 3, tabInformation.getTabIcon());
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, 6, pluginName, serverUUID);
|
||||
statement.setString(8, tabInformation.getTabName());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Executable insertTab() {
|
||||
String sql = "INSERT INTO " + ExtensionTabTable.TABLE_NAME + "(" +
|
||||
ExtensionTabTable.TAB_NAME + "," +
|
||||
ExtensionTabTable.ELEMENT_ORDER + "," +
|
||||
ExtensionTabTable.TAB_PRIORITY + "," +
|
||||
ExtensionTabTable.ICON_ID +
|
||||
ExtensionTabTable.PLUGIN_ID +
|
||||
") VALUES (?,?,?," + ExtensionIconTable.STATEMENT_SELECT_ICON_ID + "," + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ")";
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, tabInformation.getTabName());
|
||||
statement.setString(2, tabInformation.getTabElementOrder().map(ElementOrder::serialize).orElse(null));
|
||||
statement.setInt(3, tabInformation.getTabPriority());
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 4, tabInformation.getTabIcon());
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, 7, pluginName, serverUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.transactions.providers;
|
||||
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionIconTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionPluginTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionTabTable;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProvider;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.AND;
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
|
||||
import static com.djrapitops.plan.db.sql.tables.ExtensionProviderTable.*;
|
||||
|
||||
/**
|
||||
* Transaction to store information about a {@link com.djrapitops.plan.extension.implementation.providers.BooleanDataProvider}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class StoreBooleanProviderTransaction extends Transaction {
|
||||
|
||||
private final String providedCondition;
|
||||
private final boolean hidden;
|
||||
private final UUID serverUUID;
|
||||
private final ProviderInformation providerInformation;
|
||||
|
||||
public StoreBooleanProviderTransaction(DataProvider<Boolean> booleanProvider, String providedCondition, boolean hidden, UUID serverUUID) {
|
||||
this.providedCondition = providedCondition;
|
||||
this.hidden = hidden;
|
||||
this.serverUUID = serverUUID;
|
||||
this.providerInformation = booleanProvider.getProviderInformation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(storeProvider());
|
||||
}
|
||||
|
||||
private Executable storeProvider() {
|
||||
return connection -> {
|
||||
if (!updateProvider().execute(connection)) {
|
||||
return insertProvider().execute(connection);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private Executable updateProvider() {
|
||||
String sql = "UPDATE " + TABLE_NAME +
|
||||
" SET " +
|
||||
TEXT + "=?," +
|
||||
DESCRIPTION + "=?," +
|
||||
PRIORITY + "=?," +
|
||||
CONDITION + "=?," +
|
||||
PROVIDED_CONDITION + "=?," +
|
||||
TAB_ID + '=' + ExtensionTabTable.STATEMENT_SELECT_TAB_ID + ',' +
|
||||
ICON_ID + '=' + ExtensionIconTable.STATEMENT_SELECT_ICON_ID + ',' +
|
||||
HIDDEN + "=?" +
|
||||
WHERE + PLUGIN_ID + '=' + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID +
|
||||
AND + PROVIDER_NAME + "=?";
|
||||
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, providerInformation.getText());
|
||||
Optional<String> description = providerInformation.getDescription();
|
||||
if (description.isPresent()) {
|
||||
statement.setString(2, description.get());
|
||||
} else {
|
||||
statement.setNull(2, Types.VARCHAR);
|
||||
}
|
||||
statement.setInt(3, providerInformation.getPriority());
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent()) {
|
||||
statement.setString(4, condition.get());
|
||||
} else {
|
||||
statement.setNull(4, Types.VARCHAR);
|
||||
}
|
||||
if (providedCondition != null) {
|
||||
statement.setString(5, providedCondition);
|
||||
} else {
|
||||
statement.setNull(5, Types.VARCHAR);
|
||||
}
|
||||
ExtensionTabTable.set3TabValuesToStatement(statement, 6, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 9, providerInformation.getIcon());
|
||||
statement.setBoolean(12, hidden);
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, 13, providerInformation.getPluginName(), serverUUID);
|
||||
statement.setString(15, providerInformation.getName());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Executable insertProvider() {
|
||||
String sql = "INSERT INTO " + TABLE_NAME + '(' +
|
||||
PROVIDER_NAME + ',' +
|
||||
TEXT + ',' +
|
||||
DESCRIPTION + ',' +
|
||||
PRIORITY + ',' +
|
||||
CONDITION + ',' +
|
||||
PROVIDED_CONDITION + ',' +
|
||||
HIDDEN + ',' +
|
||||
TAB_ID + ',' +
|
||||
ICON_ID + ',' +
|
||||
PLUGIN_ID +
|
||||
") VALUES (?,?,?,?,?,?,?," +
|
||||
ExtensionTabTable.STATEMENT_SELECT_TAB_ID + ',' +
|
||||
ExtensionIconTable.STATEMENT_SELECT_ICON_ID + ',' +
|
||||
ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ')';
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, providerInformation.getName());
|
||||
statement.setString(2, providerInformation.getText());
|
||||
Optional<String> description = providerInformation.getDescription();
|
||||
if (description.isPresent()) {
|
||||
statement.setString(3, description.get());
|
||||
} else {
|
||||
statement.setNull(3, Types.VARCHAR);
|
||||
}
|
||||
statement.setInt(4, providerInformation.getPriority());
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent()) {
|
||||
statement.setString(5, condition.get());
|
||||
} else {
|
||||
statement.setNull(5, Types.VARCHAR);
|
||||
}
|
||||
if (providedCondition != null) {
|
||||
statement.setString(6, providedCondition);
|
||||
} else {
|
||||
statement.setNull(6, Types.VARCHAR);
|
||||
}
|
||||
statement.setBoolean(7, hidden);
|
||||
ExtensionTabTable.set3TabValuesToStatement(statement, 8, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 11, providerInformation.getIcon());
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, 14, providerInformation.getPluginName(), serverUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.transactions.providers;
|
||||
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionIconTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionPluginTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionTabTable;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProvider;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.AND;
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
|
||||
import static com.djrapitops.plan.db.sql.tables.ExtensionProviderTable.*;
|
||||
|
||||
/**
|
||||
* Transaction to store information about a dobule {@link DataProvider}.
|
||||
* <p>
|
||||
* Includes:
|
||||
* {@link com.djrapitops.plan.extension.implementation.providers.DoubleDataProvider}.
|
||||
* {@link com.djrapitops.plan.extension.implementation.providers.PercentageDataProvider}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class StoreDoubleProviderTransaction extends Transaction {
|
||||
|
||||
private final UUID serverUUID;
|
||||
private final ProviderInformation providerInformation;
|
||||
|
||||
public StoreDoubleProviderTransaction(DataProvider<Double> provider, UUID serverUUID) {
|
||||
this.serverUUID = serverUUID;
|
||||
this.providerInformation = provider.getProviderInformation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(storeProvider());
|
||||
}
|
||||
|
||||
private Executable storeProvider() {
|
||||
return connection -> {
|
||||
if (!updateProvider().execute(connection)) {
|
||||
return insertProvider().execute(connection);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private Executable updateProvider() {
|
||||
String sql = "UPDATE " + TABLE_NAME +
|
||||
" SET " +
|
||||
TEXT + "=?," +
|
||||
DESCRIPTION + "=?," +
|
||||
PRIORITY + "=?," +
|
||||
CONDITION + "=?," +
|
||||
TAB_ID + "=" + ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
|
||||
ICON_ID + "=" + ExtensionIconTable.STATEMENT_SELECT_ICON_ID +
|
||||
WHERE + PLUGIN_ID + "=" + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID +
|
||||
AND + PROVIDER_NAME + "=?";
|
||||
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, providerInformation.getText());
|
||||
Optional<String> description = providerInformation.getDescription();
|
||||
if (description.isPresent()) {
|
||||
statement.setString(2, description.get());
|
||||
} else {
|
||||
statement.setNull(2, Types.VARCHAR);
|
||||
}
|
||||
statement.setInt(3, providerInformation.getPriority());
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent()) {
|
||||
statement.setString(4, condition.get());
|
||||
} else {
|
||||
statement.setNull(4, Types.VARCHAR);
|
||||
}
|
||||
ExtensionTabTable.set3TabValuesToStatement(statement, 5, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 8, providerInformation.getIcon());
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, 11, providerInformation.getPluginName(), serverUUID);
|
||||
statement.setString(13, providerInformation.getName());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Executable insertProvider() {
|
||||
String sql = "INSERT INTO " + TABLE_NAME + "(" +
|
||||
PROVIDER_NAME + "," +
|
||||
TEXT + "," +
|
||||
DESCRIPTION + "," +
|
||||
PRIORITY + "," +
|
||||
CONDITION + "," +
|
||||
TAB_ID + "," +
|
||||
ICON_ID + "," +
|
||||
PLUGIN_ID +
|
||||
") VALUES (?,?,?,?,?," +
|
||||
ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
|
||||
ExtensionIconTable.STATEMENT_SELECT_ICON_ID + "," +
|
||||
ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ")";
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, providerInformation.getName());
|
||||
statement.setString(2, providerInformation.getText());
|
||||
Optional<String> description = providerInformation.getDescription();
|
||||
if (description.isPresent()) {
|
||||
statement.setString(3, description.get());
|
||||
} else {
|
||||
statement.setNull(3, Types.VARCHAR);
|
||||
}
|
||||
statement.setInt(4, providerInformation.getPriority());
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent()) {
|
||||
statement.setString(5, condition.get());
|
||||
} else {
|
||||
statement.setNull(5, Types.VARCHAR);
|
||||
}
|
||||
ExtensionTabTable.set3TabValuesToStatement(statement, 6, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 9, providerInformation.getIcon());
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, 12, providerInformation.getPluginName(), serverUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.transactions.providers;
|
||||
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionIconTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionPluginTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionTabTable;
|
||||
import com.djrapitops.plan.extension.FormatType;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProvider;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.AND;
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
|
||||
import static com.djrapitops.plan.db.sql.tables.ExtensionProviderTable.*;
|
||||
|
||||
/**
|
||||
* Transaction to store information about a {@link com.djrapitops.plan.extension.implementation.providers.NumberDataProvider}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@SuppressWarnings("Duplicates")
|
||||
public class StoreNumberProviderTransaction extends Transaction {
|
||||
|
||||
private final FormatType formatType;
|
||||
private final UUID serverUUID;
|
||||
private final ProviderInformation providerInformation;
|
||||
|
||||
public StoreNumberProviderTransaction(DataProvider<Long> provider, FormatType formatType, UUID serverUUID) {
|
||||
this.formatType = formatType;
|
||||
this.serverUUID = serverUUID;
|
||||
this.providerInformation = provider.getProviderInformation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(storeProvider());
|
||||
}
|
||||
|
||||
private Executable storeProvider() {
|
||||
return connection -> {
|
||||
if (!updateProvider().execute(connection)) {
|
||||
return insertProvider().execute(connection);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private Executable updateProvider() {
|
||||
String sql = "UPDATE " + TABLE_NAME + " SET " +
|
||||
TEXT + "=?," +
|
||||
DESCRIPTION + "=?," +
|
||||
PRIORITY + "=?," +
|
||||
CONDITION + "=?," +
|
||||
FORMAT_TYPE + "=?," +
|
||||
TAB_ID + "=" + ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
|
||||
ICON_ID + "=" + ExtensionIconTable.STATEMENT_SELECT_ICON_ID +
|
||||
WHERE + PLUGIN_ID + "=" + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID +
|
||||
AND + PROVIDER_NAME + "=?";
|
||||
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, providerInformation.getText());
|
||||
Optional<String> description = providerInformation.getDescription();
|
||||
if (description.isPresent()) {
|
||||
statement.setString(2, description.get());
|
||||
} else {
|
||||
statement.setNull(2, Types.VARCHAR);
|
||||
}
|
||||
statement.setInt(3, providerInformation.getPriority());
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent()) {
|
||||
statement.setString(4, condition.get());
|
||||
} else {
|
||||
statement.setNull(4, Types.VARCHAR);
|
||||
}
|
||||
statement.setString(5, formatType.name());
|
||||
ExtensionTabTable.set3TabValuesToStatement(statement, 6, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 9, providerInformation.getIcon());
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, 12, providerInformation.getPluginName(), serverUUID);
|
||||
statement.setString(14, providerInformation.getName());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Executable insertProvider() {
|
||||
String sql = "INSERT INTO " + TABLE_NAME + "(" +
|
||||
PROVIDER_NAME + "," +
|
||||
TEXT + "," +
|
||||
DESCRIPTION + "," +
|
||||
PRIORITY + "," +
|
||||
CONDITION + "," +
|
||||
FORMAT_TYPE + "," +
|
||||
TAB_ID + "," +
|
||||
ICON_ID + "," +
|
||||
PLUGIN_ID +
|
||||
") VALUES (?,?,?,?,?,?," +
|
||||
ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
|
||||
ExtensionIconTable.STATEMENT_SELECT_ICON_ID + "," +
|
||||
ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ")";
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, providerInformation.getName());
|
||||
statement.setString(2, providerInformation.getText());
|
||||
Optional<String> description = providerInformation.getDescription();
|
||||
if (description.isPresent()) {
|
||||
statement.setString(3, description.get());
|
||||
} else {
|
||||
statement.setNull(3, Types.VARCHAR);
|
||||
}
|
||||
statement.setInt(4, providerInformation.getPriority());
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent()) {
|
||||
statement.setString(5, condition.get());
|
||||
} else {
|
||||
statement.setNull(5, Types.VARCHAR);
|
||||
}
|
||||
statement.setString(6, formatType.name());
|
||||
ExtensionTabTable.set3TabValuesToStatement(statement, 7, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 10, providerInformation.getIcon());
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, 13, providerInformation.getPluginName(), serverUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.transactions.providers;
|
||||
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionIconTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionPluginTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionTabTable;
|
||||
import com.djrapitops.plan.extension.implementation.ProviderInformation;
|
||||
import com.djrapitops.plan.extension.implementation.providers.DataProvider;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.AND;
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
|
||||
import static com.djrapitops.plan.db.sql.tables.ExtensionProviderTable.*;
|
||||
|
||||
/**
|
||||
* Transaction to store information about a {@link com.djrapitops.plan.extension.implementation.providers.StringDataProvider}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class StoreStringProviderTransaction extends Transaction {
|
||||
|
||||
private final boolean playerName;
|
||||
private final UUID serverUUID;
|
||||
private ProviderInformation providerInformation;
|
||||
|
||||
public StoreStringProviderTransaction(DataProvider<String> provider, boolean playerName, UUID serverUUID) {
|
||||
this.playerName = playerName;
|
||||
this.serverUUID = serverUUID;
|
||||
providerInformation = provider.getProviderInformation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(storeProvider());
|
||||
}
|
||||
|
||||
private Executable storeProvider() {
|
||||
return connection -> {
|
||||
if (!updateProvider().execute(connection)) {
|
||||
return insertProvider().execute(connection);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private Executable updateProvider() {
|
||||
String sql = "UPDATE " + TABLE_NAME +
|
||||
" SET " +
|
||||
TEXT + "=?," +
|
||||
DESCRIPTION + "=?," +
|
||||
PRIORITY + "=?," +
|
||||
CONDITION + "=?," +
|
||||
IS_PLAYER_NAME + "=?," +
|
||||
TAB_ID + "=" + ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
|
||||
ICON_ID + "=" + ExtensionIconTable.STATEMENT_SELECT_ICON_ID +
|
||||
WHERE + PLUGIN_ID + "=" + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID +
|
||||
AND + PROVIDER_NAME + "=?";
|
||||
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, providerInformation.getText());
|
||||
Optional<String> description = providerInformation.getDescription();
|
||||
if (description.isPresent()) {
|
||||
statement.setString(2, description.get());
|
||||
} else {
|
||||
statement.setNull(2, Types.VARCHAR);
|
||||
}
|
||||
statement.setInt(3, providerInformation.getPriority());
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent()) {
|
||||
statement.setString(4, condition.get());
|
||||
} else {
|
||||
statement.setNull(4, Types.VARCHAR);
|
||||
}
|
||||
statement.setBoolean(5, playerName);
|
||||
ExtensionTabTable.set3TabValuesToStatement(statement, 6, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 9, providerInformation.getIcon());
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, 12, providerInformation.getPluginName(), serverUUID);
|
||||
statement.setString(14, providerInformation.getName());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Executable insertProvider() {
|
||||
String sql = "INSERT INTO " + TABLE_NAME + "(" +
|
||||
PROVIDER_NAME + "," +
|
||||
TEXT + "," +
|
||||
DESCRIPTION + "," +
|
||||
PRIORITY + "," +
|
||||
CONDITION + "," +
|
||||
IS_PLAYER_NAME + "," +
|
||||
TAB_ID + "," +
|
||||
ICON_ID + "," +
|
||||
PLUGIN_ID +
|
||||
") VALUES (?,?,?,?,?,?," +
|
||||
ExtensionTabTable.STATEMENT_SELECT_TAB_ID + "," +
|
||||
ExtensionIconTable.STATEMENT_SELECT_ICON_ID + "," +
|
||||
ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID + ")";
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, providerInformation.getName());
|
||||
statement.setString(2, providerInformation.getText());
|
||||
Optional<String> description = providerInformation.getDescription();
|
||||
if (description.isPresent()) {
|
||||
statement.setString(3, description.get());
|
||||
} else {
|
||||
statement.setNull(3, Types.VARCHAR);
|
||||
}
|
||||
statement.setInt(4, providerInformation.getPriority());
|
||||
Optional<String> condition = providerInformation.getCondition();
|
||||
if (condition.isPresent()) {
|
||||
statement.setString(5, condition.get());
|
||||
} else {
|
||||
statement.setNull(5, Types.VARCHAR);
|
||||
}
|
||||
statement.setBoolean(6, playerName);
|
||||
ExtensionTabTable.set3TabValuesToStatement(statement, 7, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
|
||||
ExtensionIconTable.set3IconValuesToStatement(statement, 10, providerInformation.getIcon());
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, 13, providerInformation.getPluginName(), serverUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.transactions.results;
|
||||
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionPlayerValueTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionPluginTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionProviderTable;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.AND;
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
|
||||
|
||||
/**
|
||||
* Transaction to remove method results that correspond to {@link com.djrapitops.plan.extension.annotation.InvalidateMethod} annotations.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class RemoveInvalidResultsTransaction extends Transaction {
|
||||
|
||||
private final String pluginName;
|
||||
private final UUID serverUUID;
|
||||
private final Collection<String> invalidatedMethods;
|
||||
|
||||
public RemoveInvalidResultsTransaction(String pluginName, UUID serverUUID, Collection<String> invalidatedMethods) {
|
||||
this.pluginName = pluginName;
|
||||
this.serverUUID = serverUUID;
|
||||
this.invalidatedMethods = invalidatedMethods;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
for (String invalidatedMethod : invalidatedMethods) {
|
||||
execute(deleteInvalidMethodResults(invalidatedMethod));
|
||||
execute(deleteInvalidMethodProvider(invalidatedMethod));
|
||||
}
|
||||
}
|
||||
|
||||
private Executable deleteInvalidMethodResults(String invalidMethod) {
|
||||
String sql = "DELETE FROM " + ExtensionPlayerValueTable.TABLE_NAME +
|
||||
WHERE + ExtensionPlayerValueTable.PROVIDER_ID + "=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID;
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
ExtensionProviderTable.set3PluginValuesToStatement(statement, 1, invalidMethod, pluginName, serverUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Executable deleteInvalidMethodProvider(String invalidMethod) {
|
||||
String sql = "DELETE FROM " + ExtensionProviderTable.TABLE_NAME +
|
||||
WHERE + ExtensionProviderTable.PROVIDER_NAME + "=?" +
|
||||
AND + ExtensionProviderTable.PLUGIN_ID + ExtensionPluginTable.STATEMENT_SELECT_PLUGIN_ID;
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, invalidMethod);
|
||||
ExtensionPluginTable.set2PluginValuesToStatement(statement, 2, pluginName, serverUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.transactions.results;
|
||||
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionPlayerValueTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionProviderTable;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Transaction to remove older results that violate an updated condition value.
|
||||
* <p>
|
||||
* How it works:
|
||||
* - Select all fulfilled conditions for all players (conditionName when true and not_conditionName when false)
|
||||
* - Left join with player value & provider tables when uuids match, and when condition matches a condition in the query above.
|
||||
* - Filter the join query for values where the condition did not match any provided condition in the join (Is null)
|
||||
* - Delete all player values with IDs that are returned by the left join query after filtering
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class RemoveUnsatisfiedConditionalResultsTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(deleteUnsatisfied());
|
||||
}
|
||||
|
||||
private Executable deleteUnsatisfied() {
|
||||
String reversedCondition = dbType == DBType.SQLITE ? "'not_' || " + ExtensionProviderTable.PROVIDED_CONDITION : "CONCAT('not_'," + ExtensionProviderTable.PROVIDED_CONDITION + ')';
|
||||
|
||||
String providerTable = ExtensionProviderTable.TABLE_NAME;
|
||||
String playerValueTable = ExtensionPlayerValueTable.TABLE_NAME;
|
||||
|
||||
String selectSatisfiedPositiveConditions = SELECT +
|
||||
ExtensionProviderTable.PROVIDED_CONDITION + ',' +
|
||||
ExtensionPlayerValueTable.USER_UUID +
|
||||
FROM + providerTable +
|
||||
INNER_JOIN + playerValueTable + " on " + providerTable + '.' + ExtensionProviderTable.ID + "=" + ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
WHERE + ExtensionPlayerValueTable.BOOLEAN_VALUE + "=?" +
|
||||
AND + ExtensionProviderTable.PROVIDED_CONDITION + IS_NOT_NULL;
|
||||
String selectSatisfiedNegativeConditions = SELECT +
|
||||
reversedCondition + " as " + ExtensionProviderTable.PROVIDED_CONDITION + ',' +
|
||||
ExtensionPlayerValueTable.USER_UUID +
|
||||
FROM + providerTable +
|
||||
INNER_JOIN + playerValueTable + " on " + providerTable + '.' + ExtensionProviderTable.ID + "=" + ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
WHERE + ExtensionPlayerValueTable.BOOLEAN_VALUE + "=?" +
|
||||
AND + ExtensionProviderTable.PROVIDED_CONDITION + IS_NOT_NULL;
|
||||
|
||||
// Query contents: Set of provided_conditions
|
||||
String selectSatisfiedConditions = '(' + selectSatisfiedPositiveConditions + " UNION " + selectSatisfiedNegativeConditions + ") q1";
|
||||
|
||||
// Query contents:
|
||||
// id | uuid | q1.uuid | condition | q1.provided_condition
|
||||
// -- | ---- | ------- | --------- | ---------------------
|
||||
// 1 | ... | ... | A | A Satisfied condition
|
||||
// 2 | ... | ... | not_B | not_B Satisfied condition
|
||||
// 3 | ... | ... | NULL | NULL Satisfied condition
|
||||
// 4 | ... | ... | B | NULL Unsatisfied condition, filtered to these in WHERE clause.
|
||||
// 5 | ... | ... | not_C | NULL Unsatisfied condition
|
||||
String selectUnsatisfiedValueIDs = SELECT + playerValueTable + '.' + ExtensionPlayerValueTable.ID +
|
||||
FROM + providerTable +
|
||||
INNER_JOIN + playerValueTable + " on " + providerTable + '.' + ExtensionProviderTable.ID + "=" + ExtensionPlayerValueTable.PROVIDER_ID +
|
||||
LEFT_JOIN + selectSatisfiedConditions + // Left join to preserve values that don't have their condition fulfilled
|
||||
" on (" +
|
||||
playerValueTable + '.' + ExtensionPlayerValueTable.USER_UUID +
|
||||
"=q1." + ExtensionPlayerValueTable.USER_UUID +
|
||||
AND + ExtensionProviderTable.CONDITION +
|
||||
"=q1." + ExtensionProviderTable.PROVIDED_CONDITION +
|
||||
')' +
|
||||
WHERE + "q1." + ExtensionProviderTable.PROVIDED_CONDITION + IS_NULL + // Conditions that were not in the satisfied condition query
|
||||
AND + ExtensionProviderTable.CONDITION + IS_NOT_NULL; // Ignore values that don't need condition
|
||||
|
||||
// Nested query here is required because MySQL limits update statements with nested queries:
|
||||
// The nested query creates a temporary table that bypasses the same table query-update limit.
|
||||
// Note: MySQL versions 5.6.7+ might optimize this nested query away leading to an exception.
|
||||
String sql = "DELETE FROM " + playerValueTable +
|
||||
WHERE + ExtensionPlayerValueTable.ID + " IN (" + SELECT + ExtensionPlayerValueTable.ID + FROM + '(' + selectUnsatisfiedValueIDs + ") as ids)";
|
||||
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setBoolean(1, true); // Select provided conditions with 'true' value
|
||||
statement.setBoolean(2, false); // Select negated conditions with 'false' value
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.transactions.results;
|
||||
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionProviderTable;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.AND;
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
|
||||
import static com.djrapitops.plan.db.sql.tables.ExtensionPlayerValueTable.*;
|
||||
|
||||
/**
|
||||
* Transaction to store method result of a {@link com.djrapitops.plan.extension.implementation.providers.BooleanDataProvider}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class StorePlayerBooleanResultTransaction extends Transaction {
|
||||
|
||||
private final String pluginName;
|
||||
private final UUID serverUUID;
|
||||
private final String providerName;
|
||||
private final UUID playerUUID;
|
||||
|
||||
private final boolean value;
|
||||
|
||||
public StorePlayerBooleanResultTransaction(String pluginName, UUID serverUUID, String providerName, UUID playerUUID, boolean value) {
|
||||
this.pluginName = pluginName;
|
||||
this.serverUUID = serverUUID;
|
||||
this.providerName = providerName;
|
||||
this.playerUUID = playerUUID;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(storeValue());
|
||||
}
|
||||
|
||||
private Executable storeValue() {
|
||||
return connection -> {
|
||||
if (!updateValue().execute(connection)) {
|
||||
return insertValue().execute(connection);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private Executable updateValue() {
|
||||
String sql = "UPDATE " + TABLE_NAME +
|
||||
" SET " +
|
||||
BOOLEAN_VALUE + "=?" +
|
||||
WHERE + USER_UUID + "=?" +
|
||||
AND + PROVIDER_ID + "=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID;
|
||||
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setBoolean(1, value);
|
||||
statement.setString(2, playerUUID.toString());
|
||||
ExtensionProviderTable.set3PluginValuesToStatement(statement, 3, providerName, pluginName, serverUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Executable insertValue() {
|
||||
String sql = "INSERT INTO " + TABLE_NAME + "(" +
|
||||
BOOLEAN_VALUE + "," +
|
||||
USER_UUID + "," +
|
||||
PROVIDER_ID +
|
||||
") VALUES (?,?," + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID + ")";
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setBoolean(1, value);
|
||||
statement.setString(2, playerUUID.toString());
|
||||
ExtensionProviderTable.set3PluginValuesToStatement(statement, 3, providerName, pluginName, serverUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.storage.transactions.results;
|
||||
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.sql.tables.ExtensionProviderTable;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.AND;
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.WHERE;
|
||||
import static com.djrapitops.plan.db.sql.tables.ExtensionPlayerValueTable.*;
|
||||
|
||||
/**
|
||||
* Transaction to store method result of a {@link com.djrapitops.plan.extension.implementation.providers.DoubleDataProvider}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class StorePlayerDoubleResultTransaction extends Transaction {
|
||||
|
||||
private final String pluginName;
|
||||
private final UUID serverUUID;
|
||||
private final String providerName;
|
||||
private final UUID playerUUID;
|
||||
|
||||
private final double value;
|
||||
|
||||
public StorePlayerDoubleResultTransaction(String pluginName, UUID serverUUID, String providerName, UUID playerUUID, double value) {
|
||||
this.pluginName = pluginName;
|
||||
this.serverUUID = serverUUID;
|
||||
this.providerName = providerName;
|
||||
this.playerUUID = playerUUID;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(storeValue());
|
||||
}
|
||||
|
||||
private Executable storeValue() {
|
||||
return connection -> {
|
||||
if (!updateValue().execute(connection)) {
|
||||
return insertValue().execute(connection);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private Executable updateValue() {
|
||||
String sql = "UPDATE " + TABLE_NAME +
|
||||
" SET " +
|
||||
DOUBLE_VALUE + "=?" +
|
||||
WHERE + USER_UUID + "=?" +
|
||||
AND + PROVIDER_ID + "=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID;
|
||||
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setDouble(1, value);
|
||||
statement.setString(2, playerUUID.toString());
|
||||
ExtensionProviderTable.set3PluginValuesToStatement(statement, 3, providerName, pluginName, serverUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Executable insertValue() {
|
||||
String sql = "INSERT INTO " + TABLE_NAME + "(" +
|
||||
DOUBLE_VALUE + "," +
|
||||
USER_UUID + "," +
|
||||
PROVIDER_ID +
|
||||
") VALUES (?,?," + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID + ")";
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setDouble(1, value);
|
||||
statement.setString(2, playerUUID.toString());
|
||||
ExtensionProviderTable.set3PluginValuesToStatement(statement, 3, providerName, pluginName, serverUUID);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user