Gathering of groups

This commit is contained in:
Rsl1122 2019-08-26 17:16:47 +03:00
parent ca8b89338e
commit c0da4c03b4
13 changed files with 385 additions and 59 deletions

View File

@ -48,7 +48,6 @@ public class RemoveEverythingTransaction extends Transaction {
clearTable(ServerTable.TABLE_NAME);
clearTable(ExtensionPlayerValueTable.TABLE_NAME);
clearTable(ExtensionServerValueTable.TABLE_NAME);
clearTable(ExtensionPlayerGroupsTable.TABLE_NAME);
clearTable(ExtensionGroupsTable.TABLE_NAME);
clearTable(ExtensionProviderTable.TABLE_NAME);
clearTable(ExtensionPlayerTableValueTable.TABLE_NAME);

View File

@ -60,7 +60,7 @@ public class RemovePlayerTransaction extends Transaction {
deleteFromTable(ExtensionPlayerTableValueTable.TABLE_NAME);
deleteFromTable(ExtensionPlayerValueTable.TABLE_NAME);
deleteFromTable(ExtensionPlayerGroupsTable.TABLE_NAME);
deleteFromTable(ExtensionGroupsTable.TABLE_NAME);
}
private void deleteWebUser(String username) {

View File

@ -57,6 +57,5 @@ public class CreateTablesTransaction extends OperationCriticalTransaction {
execute(ExtensionPlayerTableValueTable.createTableSQL(dbType));
execute(ExtensionServerTableValueTable.createTableSQL(dbType));
execute(ExtensionGroupsTable.createTableSQL(dbType));
execute(ExtensionPlayerGroupsTable.createTableSQL(dbType));
}
}

View File

@ -31,6 +31,7 @@ public class ExtensionGroupsTable {
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 GROUP_NAME = "group_name";
private ExtensionGroupsTable() {
@ -40,6 +41,7 @@ public class ExtensionGroupsTable {
public static String createTableSQL(DBType dbType) {
return CreateTableParser.create(TABLE_NAME, dbType)
.column(ID, Sql.INT).primaryKey()
.column(USER_UUID, Sql.varchar(36)).notNull()
.column(GROUP_NAME, Sql.varchar(50))
.column(PROVIDER_ID, Sql.INT).notNull()
.foreignKey(PROVIDER_ID, ExtensionProviderTable.TABLE_NAME, ExtensionProviderTable.ID)

View File

@ -1,49 +0,0 @@
/*
* 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_player_groups'.
*
* @author Rsl1122
*/
public class ExtensionPlayerGroupsTable {
public static final String TABLE_NAME = "plan_extension_player_groups";
public static final String ID = "id";
public static final String GROUP_ID = "group_id";
public static final String USER_UUID = "uuid";
private ExtensionPlayerGroupsTable() {
/* Static information class */
}
public static String createTableSQL(DBType dbType) {
return CreateTableParser.create(TABLE_NAME, dbType)
.column(ID, Sql.INT).primaryKey()
.column(GROUP_ID, Sql.INT).notNull()
.column(USER_UUID, Sql.varchar(36)).notNull()
.foreignKey(GROUP_ID, ExtensionGroupsTable.TABLE_NAME, ExtensionGroupsTable.ID)
.build();
}
}

View File

@ -125,6 +125,7 @@ public class DataProviderExtractor {
extractDataProviders(pluginInfo, tabs, conditions, NumberProvider.class, NumberDataProvider::placeToDataProviders);
extractDataProviders(pluginInfo, tabs, conditions, StringProvider.class, StringDataProvider::placeToDataProviders);
extractDataProviders(pluginInfo, tabs, conditions, TableProvider.class, TableDataProvider::placeToDataProviders);
extractDataProviders(pluginInfo, tabs, conditions, GroupProvider.class, GroupDataProvider::placeToDataProviders);
}
private <T extends Annotation> void extractDataProviders(PluginInfo pluginInfo, Map<Method, Tab> tabs, Map<Method, Conditional> conditions, Class<T> ofKind, DataProviderFactory<T> factory) {

View File

@ -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.providers;
import com.djrapitops.plan.extension.Group;
import com.djrapitops.plan.extension.annotation.Conditional;
import com.djrapitops.plan.extension.annotation.GroupProvider;
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 GroupDataProvider extends DataProvider<Group[]> {
private GroupDataProvider(ProviderInformation providerInformation, MethodWrapper<Group[]> methodWrapper) {
super(providerInformation, methodWrapper);
}
public static void placeToDataProviders(
DataProviders dataProviders, Method method, GroupProvider annotation,
Conditional condition, String tab, String pluginName
) {
MethodWrapper<Group[]> methodWrapper = new MethodWrapper<>(method, Group[].class);
Icon providerIcon = new Icon(annotation.iconFamily(), annotation.iconName(), annotation.groupColor());
ProviderInformation providerInformation = new ProviderInformation(
pluginName, method.getName(), annotation.text(), null, providerIcon, 0, true, tab, condition
);
dataProviders.put(new GroupDataProvider(providerInformation, methodWrapper));
}
}

View File

@ -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.gathering;
import com.djrapitops.plan.api.exceptions.DataExtensionMethodCallException;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.extension.DataExtension;
import com.djrapitops.plan.extension.Group;
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.storage.transactions.StoreIconTransaction;
import com.djrapitops.plan.extension.implementation.storage.transactions.providers.StoreGroupProviderTransaction;
import com.djrapitops.plan.extension.implementation.storage.transactions.results.StorePlayerGroupsResultTransaction;
import java.util.Optional;
import java.util.UUID;
/**
* Gathers GroupProvider method data.
*
* @author Rsl1122
*/
class GroupProviderValueGatherer {
private final String pluginName;
private final DataExtension extension;
private final UUID serverUUID;
private final Database database;
private final DataProviders dataProviders;
GroupProviderValueGatherer(
String pluginName, DataExtension extension,
UUID serverUUID, Database database,
DataProviders dataProviders
) {
this.pluginName = pluginName;
this.extension = extension;
this.serverUUID = serverUUID;
this.database = database;
this.dataProviders = dataProviders;
}
void gatherGroupDataOfPlayer(UUID playerUUID, String playerName, Conditions conditions) {
for (DataProvider<Group[]> groupProvider : dataProviders.getPlayerMethodsByType(Group[].class)) {
gatherGroupDataOfProvider(playerUUID, playerName, conditions, groupProvider);
}
}
private void gatherGroupDataOfProvider(
UUID playerUUID, String playerName,
Conditions conditions,
DataProvider<Group[]> groupProvider
) {
ProviderInformation providerInformation = groupProvider.getProviderInformation();
Optional<String> condition = providerInformation.getCondition();
if (condition.isPresent() && conditions.isNotFulfilled(condition.get())) {
return;
}
MethodWrapper<Group[]> method = groupProvider.getMethod();
try {
Group[] result = method.callMethod(extension, playerUUID, playerName);
if (result == null) {
return; // Error during call
}
database.executeTransaction(new StoreIconTransaction(providerInformation.getIcon()));
database.executeTransaction(new StoreGroupProviderTransaction(groupProvider, serverUUID));
database.executeTransaction(new StorePlayerGroupsResultTransaction(pluginName, serverUUID, method.getMethodName(), playerUUID, result));
} catch (Exception | NoClassDefFoundError | NoSuchFieldError | NoSuchMethodError e) {
throw new DataExtensionMethodCallException(e, pluginName, method);
}
}
}

View File

@ -51,6 +51,7 @@ public class ProviderValueGatherer {
private DoubleAndPercentageProviderValueGatherer doubleAndPercentageGatherer;
private StringProviderValueGatherer stringGatherer;
private TableProviderValueGatherer tableGatherer;
private GroupProviderValueGatherer groupGatherer;
public ProviderValueGatherer(
@ -83,6 +84,9 @@ public class ProviderValueGatherer {
tableGatherer = new TableProviderValueGatherer(
pluginName, extension, serverUUID, database, dataProviders
);
groupGatherer = new GroupProviderValueGatherer(
pluginName, extension, serverUUID, database, dataProviders
);
}
public void disableMethodFromUse(MethodWrapper method) {
@ -129,6 +133,7 @@ public class ProviderValueGatherer {
doubleAndPercentageGatherer.gatherDoubleDataOfPlayer(playerUUID, playerName, conditions);
stringGatherer.gatherStringDataOfPlayer(playerUUID, playerName, conditions);
tableGatherer.gatherTableDataOfPlayer(playerUUID, playerName, conditions);
groupGatherer.gatherGroupDataOfPlayer(playerUUID, playerName, conditions);
}
public void updateValues() {

View File

@ -0,0 +1,127 @@
/*
* 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.Group;
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.GroupDataProvider}.
*
* @author Rsl1122
*/
public class StoreGroupProviderTransaction extends Transaction {
private final UUID serverUUID;
private ProviderInformation providerInformation;
public StoreGroupProviderTransaction(DataProvider<Group[]> provider, UUID serverUUID) {
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 + "=?," +
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> condition = providerInformation.getCondition();
if (condition.isPresent()) {
statement.setString(2, condition.get());
} else {
statement.setNull(2, Types.VARCHAR);
}
ExtensionTabTable.set3TabValuesToStatement(statement, 3, providerInformation.getTab().orElse("No Tab"), providerInformation.getPluginName(), serverUUID);
ExtensionIconTable.set3IconValuesToStatement(statement, 6, providerInformation.getIcon());
ExtensionPluginTable.set2PluginValuesToStatement(statement, 9, providerInformation.getPluginName(), serverUUID);
statement.setString(11, providerInformation.getName());
}
};
}
private Executable insertProvider() {
String sql = "INSERT INTO " + TABLE_NAME + "(" +
PROVIDER_NAME + "," +
TEXT + "," +
CONDITION + "," +
SHOW_IN_PLAYERS_TABLE + "," +
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> condition = providerInformation.getCondition();
if (condition.isPresent()) {
statement.setString(3, condition.get());
} else {
statement.setNull(3, Types.VARCHAR);
}
statement.setBoolean(4, providerInformation.isShownInPlayersTable());
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);
}
};
}
}

View File

@ -45,14 +45,12 @@ public class RemoveUnsatisfiedConditionalPlayerResultsTransaction extends Transa
private final String playerTableValueTable;
private final String tableTable;
private final String groupTable;
private final String playerGroupTable;
public RemoveUnsatisfiedConditionalPlayerResultsTransaction() {
providerTable = ExtensionProviderTable.TABLE_NAME;
playerValueTable = ExtensionPlayerValueTable.TABLE_NAME;
tableTable = ExtensionTableProviderTable.TABLE_NAME;
groupTable = ExtensionGroupsTable.TABLE_NAME;
playerGroupTable = ExtensionPlayerGroupsTable.TABLE_NAME;
playerTableValueTable = ExtensionPlayerTableValueTable.TABLE_NAME;
}
@ -162,13 +160,12 @@ public class RemoveUnsatisfiedConditionalPlayerResultsTransaction extends Transa
// -
// Conditions are in plan_extensions_providers
// selectSatisfiedConditions lists 'provided_condition' Strings
String selectUnsatisfiedIDs = SELECT + playerGroupTable + '.' + ID +
FROM + playerGroupTable +
INNER_JOIN + groupTable + " on " + groupTable + '.' + ID + '=' + playerGroupTable + '.' + ExtensionPlayerGroupsTable.GROUP_ID +
String selectUnsatisfiedIDs = SELECT + groupTable + '.' + ID +
FROM + groupTable +
INNER_JOIN + providerTable + " on " + providerTable + '.' + ID + '=' + groupTable + '.' + ExtensionGroupsTable.PROVIDER_ID +
LEFT_JOIN + selectSatisfiedConditions + // Left join to preserve values that don't have their condition fulfilled
" on (" + // Join when uuid and plugin_id match and condition for the group provider is satisfied
playerGroupTable + '.' + P_UUID +
groupTable + '.' + P_UUID +
"=q1." + P_UUID +
AND + ExtensionProviderTable.CONDITION +
"=q1." + ExtensionProviderTable.PROVIDED_CONDITION +
@ -181,7 +178,7 @@ public class RemoveUnsatisfiedConditionalPlayerResultsTransaction extends Transa
// 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 deleteValuesSQL = "DELETE FROM " + playerGroupTable +
String deleteValuesSQL = "DELETE FROM " + groupTable +
WHERE + ID + " IN (" + SELECT + ID + FROM + '(' + selectUnsatisfiedIDs + ") as ids)";
return new ExecStatement(deleteValuesSQL) {

View File

@ -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.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.ExtensionGroupsTable;
import com.djrapitops.plan.db.sql.tables.ExtensionProviderTable;
import com.djrapitops.plan.extension.Group;
import org.apache.commons.lang3.StringUtils;
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 store method result of a {@link com.djrapitops.plan.extension.implementation.providers.GroupDataProvider}.
*
* @author Rsl1122
*/
public class StorePlayerGroupsResultTransaction extends Transaction {
private final String pluginName;
private final UUID serverUUID;
private final String providerName;
private final UUID playerUUID;
private final Group[] value;
public StorePlayerGroupsResultTransaction(String pluginName, UUID serverUUID, String providerName, UUID playerUUID, Group[] value) {
this.pluginName = pluginName;
this.serverUUID = serverUUID;
this.providerName = providerName;
this.playerUUID = playerUUID;
this.value = value;
}
@Override
protected void performOperations() {
execute(deleteOldValues());
for (Group group : value) {
String groupName = StringUtils.truncate(group.getGroupName(), 50);
execute(insertGroup(groupName));
}
}
private Executable deleteOldValues() {
String sql = "DELETE FROM " + ExtensionGroupsTable.TABLE_NAME +
WHERE + ExtensionGroupsTable.USER_UUID + "=?" +
AND + ExtensionGroupsTable.PROVIDER_ID + "=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID;
return new ExecStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, playerUUID.toString());
ExtensionProviderTable.set3PluginValuesToStatement(statement, 2, providerName, pluginName, serverUUID);
}
};
}
private Executable insertGroup(String group) {
String sql = "INSERT INTO " + ExtensionGroupsTable.TABLE_NAME + "(" +
ExtensionGroupsTable.GROUP_NAME + "," +
ExtensionGroupsTable.USER_UUID + "," +
ExtensionGroupsTable.PROVIDER_ID +
") VALUES (?,?," + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID + ")";
return new ExecStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, group);
statement.setString(2, playerUUID.toString());
ExtensionProviderTable.set3PluginValuesToStatement(statement, 3, providerName, pluginName, serverUUID);
}
};
}
}

View File

@ -1238,6 +1238,7 @@ public interface DatabaseTest {
OptionalAssert.equals("0.5", tabData.getDouble("doubleVal_total").map(data -> data.getFormattedValue(Objects::toString)));
OptionalAssert.equals("5", tabData.getNumber("value_avg").map(data -> data.getFormattedValue(Objects::toString)));
OptionalAssert.equals("5", tabData.getNumber("value_total").map(data -> data.getFormattedValue(Objects::toString)));
// TODO Add test that group exists
}
@Test
@ -1527,6 +1528,11 @@ public interface DatabaseTest {
public String stringVal(UUID playerUUID) {
return "Something";
}
@GroupProvider(text = "a group")
public Group[] group(UUID playerUUID) {
return new Group[]{() -> "group"};
}
}
@PluginInfo(name = "TableExtension")