0

10 Commits

Author SHA1 Message Date
2fc1bf36c1 update version 2021-01-03 00:24:06 +03:00
eb5396b891 Merge branch 'develop' 2021-01-03 00:23:40 +03:00
e12d005a25 update version 2021-01-02 14:39:35 +03:00
6e50fc278e Merge branch 'develop' 2021-01-02 14:39:18 +03:00
c8866af418 update version 2021-01-02 02:52:42 +03:00
359dbba09a Merge branch 'develop' 2021-01-02 02:52:19 +03:00
e4b1b40104 update version 2021-01-02 01:46:21 +03:00
73f044ab8b Merge branch 'develop' 2021-01-02 01:45:58 +03:00
32b868df22 update version 2021-01-01 22:08:31 +03:00
3a66dffa10 Merge branch 'develop' 2021-01-01 22:08:17 +03:00
29 changed files with 965 additions and 1946 deletions

698
README.MD
View File

@@ -1,698 +0,0 @@
# GHAST TOOLS
![version: 1.9](https://img.shields.io/badge/version-1.9-0a0.svg?style=flat)
![bukkit-api: 1.12](https://img.shields.io/badge/bukkit--api-1.12-d50.svg?style=flat)
Набор вспомогательных инструментов для Bukkit API.
_Основан на версии Bukkit API 1.12._
## Содержание
1. [Перед использованием](#перед-использованием)
2. [GhastTools](#ghasttools)
3. [AssetsManager](#assetsmanager)
4. [BuildHelper](#buildhelper)
5. [CommandManager](#commandmanager)
6. [EffectsHelper](#effectshelper)
7. [EventContext](#eventcontext)
8. [JdbcTemplate](#jdbctemplate)
9. [ScheduleManager](#schedulemanager)
10. [ScheduleTask](#scheduletask)
11. [Messages](#messages)
12. [XLog](#xlog)
13. [Подключение](#подключение)
1. [Gradle](#gradle)
2. [Maven](#maven)
---
## Перед использованием
Перед началом использования, необходимо в вашем Bukkit-плагине прописать подобный код:
```java
void onLoad() {
GhastTools.setPlugin(this);
}
```
Это необходимо сделать, т.к. весь инструментарий основан на статических (static) методах.
Все методы данного набора инструментов объеденены в классы, выполняющие роль группировщиков.
## GhastTools
Методы общего назначения или без определённой группировки.
### loadConfig
Загрузка файла настроек плагина - `config.yml`.
```java
YamlConfiguration config = GhastTools.loadConfig();
```
По-умолчанию "гаст" пытается файл найти в папке плагина - `getDataFolder()`.
Если файла там нет, то выгружает встроенный (имеющийся в `.jar` файле плагина) в эту папку и загружает его.
```java
YamlConfiguration config = GhastTools.loadConfig(false);
```
Если передать параметр `false`, то при отсутствии файла `config.yml` в папке плагина,
будет загруден исключительно встроенный файл настроек.
### copyLocation
Копирования объекта `Location`
```java
Location location = ...;
Location copyLoc = GhastTools.copyLocation(location);
```
## AssetsManager
Методы по работе с файлами плагина (_"ассетами"_).
У каждой группы методов один и тот же набор входных параметров:
- `resourceName` - наименование и путь к файлу в папке плагина
- `defaultResourceName` - наименование и путь к файлу в плагине.
_Опционально. По-умолчанию равнен `resourceName`_
- `saveDefault` - необходимость скопировать содержимое файла из `defaultResourceName` в файл `resourceName`.
_Опционально. По-умолчанию равен `true`_
Правила поиска файлов так же одинаков для каждой группы:
- В начале файл ищется в папке плагина
- Если файл отсутствует в папке плагина, то...
- если `defaultResourceName` не равен `null`...
- если `saveDefault` равен `true`, то файл из плагина будет выгружен в папку плагина и от туда загружен в память.
- если `saveDefault` равен `false`, то данные будут взяты из файлв в плагине.
- если `defaultResourceName` равен `null`, то будет брошено исключение `AssetsException` с описанием ошибки вида "Файл X не найден".
### getAsInputStream
```java
InputStream inputStream = AssetsManager.getAsInputStream("translate.ru.yml", "translate.yml", false);
```
### getAsReader
```java
Reader reader = AssetsManager.getAsReader("translate.ru.yml", "translate.yml", false);
```
### getAsString
```java
String string = AssetsManager.getAsString("readme.txt", "readme.txt", StandardCharsets.UTF_8, false);
```
У этой группы есть дополнительный _опциональный_ параметр - `charset` - в котором указывается кодиривка получаемой строки.
о-умолчанию равен `StandardCharsets.UTF_8`_
## BuildHelper
Набор методов облегчающих размецение объектов на карте.
### placeSkull
Установка черепа.
```java
Location location = ...;
Skull skull = BuildHelper.placeSkull(location, BlockFace.NORTH);
skull.update(true); // иначе изменения на карте не применятся и череп будет висеть в воздухе
```
### placePlayerHead
Установка головы игрока.
```java
Location location = ...;
Skull playerHead = BuildHelper.placePlayerHead(location, BlockFace.NORTH);
playerHead.update(true); // иначе изменения на карте не применятся и голова будет висеть в воздухе
```
Если третьим параметром передать URL текстуры, то голова будет текстурирована.
```java
Location location = ...;
BuildHelper.placePlayerHead(location, BlockFace.NORTH, "http://...");
```
### setPlayerHeadSkin
Установка текстуры для головы игрока.
```java
Location location = ...;
Skull playerHead = BuildHelper.placePlayerHead(location, BlockFace.NORTH);
playerHead.update(true); // иначе изменения на карте не применятся и голова будет висеть в воздухе
setPlayerHeadSkin(playerHead);
```
Порядок выполнения методов в приведённом выше примере **важен**. Если `playerHead.update(true)` вызвать после
установки текстуры, она собъётся на стандартную.
### placeSignWall
```java
Location location = ...;
Sign signWall = BuildHelper.placeSignWall(location, BlockFace.NORTH)
```
## CommandManager
Регистрация команд.
Имеется два варианта использования: упрощённый
```java
CommandManager.register("start", (sender, args) -> sender.sendMessage("hello!"));
```
и подробный:
```java
CommandManager.create("start")
.useOnlyPlayer()
.executer((sender, args) -> sender.sendMessage("hello!"))
.register();
```
### register
Упрощенная регистрация команды. Указывается лишь название команды и исполнитель.
```java
CommandManager.register("start", (sender, args) -> sender.sendMessage("hello!"));
```
### create
Конструктор для подробного варианта регистрации команды.
```java
CommandManager.Builder builder = CommandManager.create("start");
```
### executer
Указание исполнителя для команды
```java
CommandManager.Builder builder = CommandManager.create("start")
.executer((sender, args) -> sender.sendMessage("hello!"));
```
### onError
Обработчик исключений
```java
CommandManager.Builder builder = CommandManager.create("start")
.onError((sender, commandName, args, exception) -> {
sender.sendMessage(ChatColor.RED + "Произошла ошибка при выполнении команды '" + commandName + "'.");
exception.printStackTrace();
});
```
### useOnlyPlayer
Указание, что данную команду могут использовать только Игроки.
Опционально можно указать сообщение, которое будет выводиться в консоль.
_Отменяет действие указателя `useOnlyConsole`_
```java
CommandManager.Builder builder = CommandManager.create("start")
.useOnlyPlayer("Команду могут использовать только игроки");
```
### useOnlyConsole
Указание, что данную команду можно использовать только в консоле.
Опционально можно указать сообщение, которое будет выводиться Игроку.
_Отменяет действие указателя `useOnlyPlayer`_
```java
CommandManager.Builder builder = CommandManager.create("start")
.useOnlyConsole(ChatColor.RED + "Команду можно использовать только в консоли");
```
### register
Регистрация описанной в Конструкторе команды.
```java
CommandManager.create("start")
.useOnlyPlayer()
.executer((sender, args) -> sender.sendMessage("hello!"))
.register();
```
## EffectsHelper
Набор методов для работы с эффектами.
### playSound
Воспроизвести звук.
```java
Location location = ...;
EffectsHelper.playSound(location, Sound.AMBIENT_CAVE, 1.0f);
```
### particle
Создание частиц.
```java
Location location = ...;
EffectsHelper.particle(location, Particle.REDSTONE, 1.0d, 1.0d, 1.0d, 1.0d, 5);
```
## EventContext
Регистрация группы обработчиков событий, объединённых общим условием выполнения.
```java
EventContext.create()
.filter(() -> Bukkit.getOnlinePlayers().size() > 10)
.onEvent(PlayerJoinEvent.class, event -> { event.getPlayer().kickPlayer("Max players"); });
```
### create
Создание контекста событий.
```java
EventContext eventContext = EventContext.create();
```
### filter
Условие, при котором будут срабатывать обработчики событий в данном контексте.
```java
EventContext.create()
.filter(() -> Bukkit.getOnlinePlayers().size() > 10)
```
### onEvent
Указание события и его обработчика.
_Обработчик события регистрируется сразу же._
```java
EventContext.create()
.filter(() -> Bukkit.getOnlinePlayers().size() > 10)
.onEvent(PlayerJoinEvent.class, event -> event.getPlayer().kickPlayer("Max players"));
```
### cancelEvent
Отменить событие.
_Обработчик события регистрируется сразу же._
```java
EventContext.create()
.cancelEvent(BlockPlaceEvent.class);
```
эквивалентен коду:
```java
EventContext.create()
.onEvent(BlockPlaceEvent.class, event -> event.setCancelled(true))
```
## JdbcTemplate
Инструмент для упрощения работы с SQL базами данных, работающими через JDBC.
Для начала потребуется создать объект `DataSource`
```java
// На примере MySQL
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setServerName("localhost");
dataSource.setPort(3306);
dataSource.setCharacterEncoding(StandardCharsets.UTF_8.name());
dataSource.setDatabaseName("MyDataBase");
dataSource.setUser("root");
dataSource.setPassword("secret");
```
После чего создать `JdbcTemplate`
```java
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
```
### execute
Выполнение SQL запроса без последующей обработки результатов выполнения.
```java
jdbcTemplate.execute("CREATE TABLE my_table (id int, name varchar(16));");
```
### query
Выполнение SQL запроса и обработка его результатов.
Может возвращать любой тип объектов.
```java
String name = jdbcTemplate.query("SELECT name FROM my_table LIMIT 0,1", resultSet -> {
if (resultSet.next()) {
return resultSet.getString("name");
} else {
return null;
}
});
```
```java
List<String> names = jdbcTemplate.query("SELECT name FROM my_table", resultSet -> {
if (resultSet.next()) {
List<String> list = new ArrayList<>();
do {
list.add(resultSet.getString("name"));
} while (resultSet.next());
return list;
} else {
return Collections.emptyList();
}
});
```
### queryOne
Выполнение SQL запроса с расчетом, что результат будет единичным либо не будет вовсе.
Возвращает `Optional`.
```java
Optional<String> optName = jdbcTemplate.queryOne("SELECT name FROM my_table WHERE name LIKE 'dmitriymx'", rs -> rs.getString("name"));
```
### queryList
Выполнение SQL запроса и обработка результата как списка данных.
Возвращает `List`.
```java
List<String> names = jdbcTemplate.queryList("SELECT name FROM my_table", (resultSet, rowNum) -> resultSet.getString("name"));
```
### queryForMap
Выполнение SQL запроса с расчетом, что результат будет единичным либо не будет вовсе.
Возвращает `Map<String, Object>`, где ключ — это наименование колонок таблицы, а значения — это значения в ячейках таблицы.
```java
Map<String, Object> map = jdbcTemplate.queryForMap("SELECT * FROM my_table LIMIT 0,1;");
```
### queryForMapList
Выполнение SQL запроса и обработка результата как списка данных.
Возвращает `List<Map<String, Object>>`, где ключ — это наименование колонок таблицы, а значения — это значения в ячейках таблицы.
```java
List<Map<String, Object>> mapList = jdbcTemplate.queryForMapList("SELECT * FROM my_table");
```
### update
Выполнение SQL запроса где будет происходить обновление данных в таблице.
Под "обновлением" подразумеваются любые изменения в таблице: `UPDATE`, `DELETE`, `INSERT`.
Возвращает число строк, которые были _по факту обновлены_ в таблице.
```java
int rows = jdbcTemplate.update("DELETE FROM my_table WHERE name LIKE 'dmitriymx';");
```
## ScheduleManager
Набор методов для создания параллельных задач, выполняющихся один раз или по рассписанию.
### createTask
Создание конструктора задачи.
```java
ScheduleManager.Builder builder = ScheduleManager.createTask();
```
### useBukkitScheduler
Если задача будет взаимодействоватьс **Bukkit API** или необходима привязка задачи к _тикам_,
то необходимо использовать данный указатель.
В ином случае, указатель не нужен.
```java
ScheduleManager.Builder builder = ScheduleManager.createTask()
.useBukkitScheduler();
```
### after
Указание, что задачу нужно выполнить не сразу, а с некоторой задержкой перед запуском.
```java
ScheduleManager.Builder builder = ScheduleManager.createTask()
.after(5, TimeUnit.MINUTES);
```
### every
Указание, что задачу нужно повторять через указанное время.
```java
ScheduleManager.Builder builder = ScheduleManager.createTask()
.every(5, TimeUnit.MINUTES);
```
### create
Создание описанной задачи.
```java
ScheduleTask scheduleTask = ScheduleManager.createTask()
.every(1, TimeUnit.SECONDS)
.create(() -> Bukkit.getServer().getLogger().info("TimeMS: " + System.currentTimeMillis()));
```
_Задача будет только создана. Для её выполнения нужно вызвать `scheduleTask.start()`._
### execute
Создание и выполнение описанной задачи.
```java
ScheduleTask scheduleTask = ScheduleManager.createTask()
.every(1, TimeUnit.SECONDS)
.execute(() -> Bukkit.getServer().getLogger().info("TimeMS: " + System.currentTimeMillis()));
```
## ScheduleTask
Вспомогательный объект, созданный через `ScheduleManager`. Позволяет управлять созданной задачей.
### start
Запускает задачу, если она еще не запущена.
```java
ScheduleTask scheduleTask = ...;
scheduleTask.start();
```
### isCanceled
Возвращает состояние задачи. Если `true`, значит задача была или _отменена/остоновлена_ или была завершена.
```java
ScheduleTask scheduleTask = ...;
boolean status = scheduleTask.isCanceled();
```
### cancel
Отменяет/Остонавливает выполнение задачи.
```java
ScheduleTask scheduleTask = ...;
scheduleTask.cancel();
```
## Messages
Инструмент для работы с параметизированными сообщениями или просто сообщениями, которые храняться в отдельном файле.
Параметизированные сообщения имеют следующий вид: `Привет, {player}!`.
### load
Загрузка сообщений в инструмент.
Есть три варианта: через `Properties`
```java
Properties properties = ...;
Messages.load(properties);
```
через `Map<String, String>`
```java
Map<String, String> map = ...;
Messages.load(map);
```
через `Reader`
```java
Reader reader = ...;
Messages.load(reader);
```
Следует учесть, про при работе через `Reader`, **Messages** ожидает там обнаружить список строк в формате `key=value`.
### get
Получение обычноего или параметизированного сообщения.
Для примера, пусть у нас будут такие сообщения:
```properties
simple=Простое сообщение
welcome=Приветствуем, {player}!
```
Для получения простого сообщения, просто указываем его ключ:
```java
String message = Messages.get("simple");
// Простое сообщение
```
Для получения параметизированного сообщения, нужно помимо ключа передать параметры.
Есть два способа: через `Map<String, Object>`
```java
Map<String, Object> = map = new HashMap<>(1);
map.put("player", "David");
String message = Messages.get("welcome", map);
// Приветствуем, David!
```
через попарное перечисление параметров
```java
String message = Messages.get("welcome", "player", "David");
// Приветствуем, David!
```
Если по указанному ключу сообщение отсутствует, то **Messages** вернёт значение самого ключа
```java
String message = Messages.get("not_exists_key");
// not_exists_key
message = Messages.get("not_exists_key", "player", "David");
// not_exists_key
```
Если параметр, который указан в шаблоне не был указан/определён, то параметр останется как есть
```java
String message = Messages.get("welcome");
// Приветствуем, {player}!
message = Messages.get("welcome", "unknown_param_key", 123);
// Приветствуем, {player}!
```
### format
**Messages** можно использовать и просто для форматирования параметизированных шаблонов:
```java
Map<String, Object> = map = new HashMap<>(1);
map.put("player", "David");
String message = Messages.format("Приветствуем, {player}!", map);
// Приветствуем, David!
```
```java
String message = Messages.foramt("Приветствуем, {player}!", "player", "David");
// Приветствуем, David!
```
## XLog
Замена стандартному `getLogger()`, который использует `java.utils.Logger` и не всегда удобен для логирования.
Имеет 4 уровня логирования: `debug`, `info`, `warning`, `error`.
Сообщения могут быть шаблонизированными. Синтаксис шаблонов — `java.text.MessageFormat`.
Примеры:
```java
XLog.info("Hello");
XLog.info("Player {0} join game", event.getPlayer().getName());
XLog.error("ERROR!", exception);
XLog.error("ERROR: {0}", exception.getMessage());
// Для экранирования "{" нужно перед ней поставить "'".
// А для использования "'" нужно их дублировать.
XLog.error("ERROR ''{0}'' in Event '{{1}'}: {2}", exception.getClass(), event.getClass(), exception.getMessage());
XLog.error("ERROR: {0}", exception.getMessage(), exception);
```
---
## Подключение
### Gradle
```groovy
repositories {
maven { url 'https://dmx-mc-project.gitlab.io/maven-repository/' }
}
```
```groovy
implementation group: 'ghast', name: 'ghast-tools', version: '1.9'
```
### Maven
```xml
<repositories>
<repository>
<id>dmx-mc-project</id>
<url>https://dmx-mc-project.gitlab.io/maven-repository/</url>
</repository>
</repositories>
```
```xml
<dependencies>
<dependency>
<groupId>ghast</groupId>
<artifactId>ghast-tools</artifactId>
<version>1.9</version>
</dependency>
</dependencies>
```

View File

@@ -29,7 +29,8 @@ ext {
]], ]],
commons_text: 'org.apache.commons:commons-text:1.9', commons_text: 'org.apache.commons:commons-text:1.9',
lombok: 'org.projectlombok:lombok:1.18.12', lombok: 'org.projectlombok:lombok:1.18.12',
reflection_object: 'ru.dmitriymx:reflection-object:1.2', reflection_object: 'ru.dmitriymx:reflection-object:1.0-BETA',
mysql: 'mysql:mysql-connector-java:8.0.22',
test: [ test: [
junit5: [ junit5: [
"org.junit.jupiter:junit-jupiter-api:$junitVersion", "org.junit.jupiter:junit-jupiter-api:$junitVersion",
@@ -65,6 +66,7 @@ dependencies {
annotationProcessor libs.lombok annotationProcessor libs.lombok
compileOnly2 libs.bukkit compileOnly2 libs.bukkit
compileOnly libs.mysql
implementation libs.commons_text implementation libs.commons_text
implementation libs.reflection_object implementation libs.reflection_object

View File

@@ -1,3 +1,3 @@
projectGroup=ghast projectGroup=ghast
projectName=ghast-tools projectName=ghast-tools
projectVersion=1.4 projectVersion=1.9

View File

@@ -3,145 +3,34 @@ package ghast;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.SkullType;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign; import org.bukkit.block.Sign;
import org.bukkit.block.Skull; import org.bukkit.block.Skull;
import ru.dmitriymx.reflection.ReflectionClass;
import ru.dmitriymx.reflection.ReflectionObject;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.UUID;
@UtilityClass @UtilityClass
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class BuildHelper { public class BuildHelper {
private final Class<?> CLASS_BLOCKPOSITION = getClassForName("net.minecraft.server.v1_12_R1.BlockPosition"); public Skull placeSkull(Location location, BlockFace face) {
private final Class<?> CLASS_GAMEPROFILE = getClassForName("com.mojang.authlib.GameProfile"); Block block = location.getWorld().getBlockAt(location);
block.setType(Material.SKULL);
Skull skull = (Skull) block.getState();
skull.setRotation(face);
org.bukkit.material.Skull skullMaterial = (org.bukkit.material.Skull) skull.getData();
skullMaterial.setFacingDirection(BlockFace.SELF);
/** return skull;
* Установка черепа. }
* <p>
* После установки, необходимо выполнить <code>skull.update(true);</code>
*
* @param location место установки.
* @param face куда будет повёрнут череп.
* @return Блок типа {@link Skull}
*/
public Skull placeSkull(Location location, BlockFace face) {
Location fixedLocation = GhastTools.copyLocation(location);
fixedLocation.setZ(fixedLocation.getZ() - 1);
Block block = location.getWorld().getBlockAt(location); public Sign placeSignWall(Location location, BlockFace face) {
block.setType(Material.SKULL); Block block = location.getWorld().getBlockAt(location);
block.setType(Material.WALL_SIGN);
Skull skull = (Skull) block.getState(); Sign sign = (Sign) block.getState();
skull.setRotation(face); org.bukkit.material.Sign signMaterial = (org.bukkit.material.Sign) sign.getData();
signMaterial.setFacingDirection(face);
org.bukkit.material.Skull skullMaterial = (org.bukkit.material.Skull) skull.getData(); return sign;
skullMaterial.setFacingDirection(BlockFace.SELF); }
return skull;
}
/**
* Установка головы игрока.
* <p>
* После установки, необходимо выполнить <code>skull.update(true);</code>
*
* @param location место установки.
* @param face куда будет повёрнута голова.
* @return Блок типа {@link Skull}
*/
public static Skull placePlayerHead(Location location, BlockFace face) {
Location fixedLocation = GhastTools.copyLocation(location);
fixedLocation.setZ(fixedLocation.getZ() - 1);
Block block = fixedLocation.getWorld().getBlockAt(fixedLocation);
block.setType(Material.SKULL);
Skull skull = (Skull) block.getState();
skull.setSkullType(SkullType.PLAYER);
skull.setRotation(face);
org.bukkit.material.Skull skullMaterial = (org.bukkit.material.Skull) skull.getData();
skullMaterial.setFacingDirection(BlockFace.SELF);
return skull;
}
/**
* Установка текстурированной головы игрока.
*
* @param location место установки.
* @param face куда будет повёрнута голова.
* @param skinUrl URL на текстуру
* @return Блок типа {@link Skull}
*/
public static Skull placePlayerHead(Location location, BlockFace face, String skinUrl) {
Skull playerHead = placePlayerHead(location, face);
playerHead.update(true);
setPlayerHeadSkin(playerHead, skinUrl);
return playerHead;
}
/**
* Установка текстуры для головы игрока.
*
* @param skull блок головы игрока
* @param skinUrl URL на текстуру
*/
public static void setPlayerHeadSkin(Skull skull, String skinUrl) {
//TODO заменить рефлексию на "фантомные" классы
ReflectionObject refobjBlockPosition = new ReflectionClass(CLASS_BLOCKPOSITION)
.constructor(double.class, double.class, double.class)
.newInstance(skull.getX(), skull.getY(), skull.getZ());
new ReflectionObject(skull.getWorld())
.method("getHandle").invoke()
.method("getTileEntity", CLASS_BLOCKPOSITION)
.invoke(refobjBlockPosition.getOriginalObject())
.method("setGameProfile", CLASS_GAMEPROFILE)
.invoke(getRefObjPlayerProfile(skinUrl).getOriginalObject());
}
public Sign placeSignWall(Location location, BlockFace face) {
Block block = location.getWorld().getBlockAt(location);
block.setType(Material.WALL_SIGN);
Sign sign = (Sign) block.getState();
org.bukkit.material.Sign signMaterial = (org.bukkit.material.Sign) sign.getData();
signMaterial.setFacingDirection(face);
return sign;
}
private ReflectionObject getRefObjPlayerProfile(String url){
ReflectionObject refobjProperty = new ReflectionClass(
getClassForName("com.mojang.authlib.properties.Property"))
.constructor(String.class, String.class)
.newInstance("textures", Base64.getEncoder()
.encodeToString(("{textures:{SKIN:{url:\"" + url + "\"}}}").getBytes(StandardCharsets.UTF_8)));
ReflectionObject refobjGameProfile = new ReflectionClass(CLASS_GAMEPROFILE)
.constructor(UUID.class, String.class)
.newInstance(UUID.randomUUID(), null);
refobjGameProfile
.method("getProperties").invoke()
.method("put", Object.class, Object.class)
.invoke("textures", refobjProperty.getOriginalObject());
return refobjGameProfile;
}
private Class<?> getClassForName(String className) {
try {
return Class.forName(className);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
} }

View File

@@ -11,17 +11,17 @@ import org.bukkit.util.Vector;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class EffectsHelper { public class EffectsHelper {
public void playSound(Location location, Sound sound, float pitch) { public void playSound(Location location, Sound sound, float pitch) {
location.getWorld().playSound(location, sound, SoundCategory.MASTER, 1.0f, pitch); location.getWorld().playSound(location, sound, SoundCategory.MASTER, 1.0f, pitch);
} }
public void particle(Location location, Particle particle, double dx, double dy, double dz, double speed, int amount) { public void particle(Location location, Particle particle, double dx, double dy, double dz, double speed, int amount) {
location.getWorld().spawnParticle(particle, location, amount, dx, dy, dz, speed); location.getWorld().spawnParticle(particle, location, amount, dx, dy, dz, speed);
} }
//TODO нужно проверить //TODO нужно проверить
public void particle(Location location, Particle particle, Vector vector, double speed, int amount) { public void particle(Location location, Particle particle, Vector vector, double speed, int amount) {
particle(location, particle, vector.getX(), vector.getY(), vector.getZ(), speed, amount); particle(location, particle, vector.getX(), vector.getY(), vector.getZ(), speed, amount);
} }
} }

View File

@@ -17,55 +17,55 @@ import java.util.function.Consumer;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class EventContext implements Listener { public class EventContext implements Listener {
private static final BooleanSupplier EMPTY_FILTER = () -> true; private static final BooleanSupplier EMPTY_FILTER = () -> true;
private static final Consumer<Cancellable> CANCEL_EVENT = event -> event.setCancelled(true); private static final Consumer<Cancellable> CANCEL_EVENT = event -> event.setCancelled(true);
private final Map<Class<? extends Event>, Consumer<?>> eventMap = new HashMap<>(); private final Map<Class<? extends Event>, Consumer<?>> eventMap = new HashMap<>();
private BooleanSupplier filter = EMPTY_FILTER; private BooleanSupplier filter = EMPTY_FILTER;
public EventContext filter(BooleanSupplier filter) { public EventContext filter(BooleanSupplier filter) {
this.filter = (filter != null ? filter : EMPTY_FILTER); this.filter = (filter != null ? filter : EMPTY_FILTER);
return this; return this;
} }
public <T extends Event> EventContext onEvent(Class<T> eventType, EventPriority eventPriority, Consumer<T> consumer) { public <T extends Event> EventContext onEvent(Class<T> eventType, EventPriority eventPriority, Consumer<T> consumer) {
if (consumer == null) { if (consumer == null) {
eventMap.remove(eventType); eventMap.remove(eventType);
} else { } else {
eventMap.put(eventType, consumer); eventMap.put(eventType, consumer);
bukkitRegisterEvent(eventType, eventPriority); bukkitRegisterEvent(eventType, eventPriority);
} }
return this; return this;
} }
public <T extends Event> EventContext onEvent(Class<T> eventType, Consumer<T> consumer) { public <T extends Event> EventContext onEvent(Class<T> eventType, Consumer<T> consumer) {
return onEvent(eventType, EventPriority.NORMAL, consumer); return onEvent(eventType, EventPriority.NORMAL, consumer);
} }
public <T extends Event & Cancellable> EventContext cancelEvent(Class<T> eventType, EventPriority eventPriority) { public <T extends Event & Cancellable> EventContext cancelEvent(Class<T> eventType, EventPriority eventPriority) {
eventMap.put(eventType, CANCEL_EVENT); eventMap.put(eventType, CANCEL_EVENT);
bukkitRegisterEvent(eventType, eventPriority); bukkitRegisterEvent(eventType, eventPriority);
return this; return this;
} }
public <T extends Event & Cancellable> EventContext cancelEvent(Class<T> eventType) { public <T extends Event & Cancellable> EventContext cancelEvent(Class<T> eventType) {
return cancelEvent(eventType, EventPriority.NORMAL); return cancelEvent(eventType, EventPriority.NORMAL);
} }
private void bukkitRegisterEvent(Class<? extends Event> eventType, EventPriority eventPriority) { private void bukkitRegisterEvent(Class<? extends Event> eventType, EventPriority eventPriority) {
Bukkit.getPluginManager().registerEvent(eventType, this, eventPriority, Bukkit.getPluginManager().registerEvent(eventType, this, eventPriority,
this::eventExecute, GhastTools.getPlugin()); this::eventExecute, GhastTools.getPlugin());
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
private void eventExecute(Listener listener, Event event) { private void eventExecute(Listener listener, Event event) {
Consumer consumer = eventMap.get(event.getClass()); Consumer consumer = eventMap.get(event.getClass());
if (consumer != null && filter.getAsBoolean()) { if (consumer != null && filter.getAsBoolean()) {
consumer.accept(event); consumer.accept(event);
} }
} }
public static EventContext create() { public static EventContext create() {
return new EventContext(); return new EventContext();
} }
} }

View File

@@ -2,7 +2,6 @@ package ghast;
import ghast.assets.AssetsManager; import ghast.assets.AssetsManager;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.bukkit.Location;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
@@ -14,42 +13,45 @@ import java.lang.ref.WeakReference;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class GhastTools { public class GhastTools {
private static WeakReference<Plugin> refPlugin; private static WeakReference<Plugin> refPlugin;
public void setPlugin(Plugin plugin) { @SuppressWarnings("java:S2696")
refPlugin = plugin == null ? null : new WeakReference<>(plugin); public void setPlugin(Plugin plugin) {
} if (plugin == null) {
refPlugin = null;
} else {
refPlugin = new WeakReference<>(plugin);
}
}
public Plugin getPlugin() { @SuppressWarnings("java:S112")
if (refPlugin == null) { public Plugin getPlugin() {
throw new RuntimeException("Plugin not set."); if (refPlugin == null) {
} throw new RuntimeException("Plugin not set.");
}
Plugin plugin = refPlugin.get(); Plugin plugin = refPlugin.get();
if (plugin == null) { if (plugin == null) {
throw new RuntimeException("Plugin not set."); throw new RuntimeException("Plugin not set.");
} }
return plugin; return plugin;
} }
public YamlConfiguration loadConfig(boolean saveDefault) { @SuppressWarnings("java:S112")
if (saveDefault) { public YamlConfiguration loadConfig(boolean saveDefault) {
getPlugin().saveDefaultConfig(); if (saveDefault) {
} getPlugin().saveDefaultConfig();
}
try (Reader reader = AssetsManager.getAsReader("config.yml", saveDefault)) { try (Reader reader = AssetsManager.getAsReader("config.yml", saveDefault)) {
return YamlConfiguration.loadConfiguration(reader); return YamlConfiguration.loadConfiguration(reader);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Error load config: " + e.getMessage(), e); throw new RuntimeException("Error load config: " + e.getMessage(), e);
} }
} }
public YamlConfiguration loadConfig() { public YamlConfiguration loadConfig() {
return loadConfig(true); return loadConfig(true);
} }
public Location copyLocation(Location location) {
return new Location(location.getWorld(), location.getX(), location.getY(), location.getZ());
}
} }

View File

@@ -14,81 +14,78 @@ import java.io.Reader;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/**
* @deprecated use {@link Messages}
*/
@UtilityClass @UtilityClass
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Deprecated
public class I18n { public class I18n {
private final String DEFAULT_LANG = "en"; private final String DEFAULT_LANG = "en";
private final Table<String/*Lang*/, String/*Key*/, String/*Template|Message*/> messagesMap = HashBasedTable.create(); private final Table<String/*Lang*/, String/*Key*/, String/*Template|Message*/> messagesMap = HashBasedTable.create();
//region Load messages //region Load messages
public void loadMessages(String lang, Reader reader) { @SuppressWarnings("java:S112")
Map<String, String> map = messagesMap.row(lang.toLowerCase()); public void loadMessages(String lang, Reader reader) {
Map<String, String> map = messagesMap.row(lang.toLowerCase());
try { try {
BufferedReader bufferedReader = new BufferedReader(reader); BufferedReader bufferedReader = new BufferedReader(reader);
String line; String line;
while ((line = bufferedReader.readLine()) != null) { while ((line = bufferedReader.readLine()) != null) {
String[] split = line.split("=", 2); String[] split = line.split("=", 2);
map.put(split[0].trim().toLowerCase(), split[1].trim()); map.put(split[0].trim().toLowerCase(), split[1].trim());
} }
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Error load messages: " + e.getMessage(), e); throw new RuntimeException("Error load messages: " + e.getMessage(), e);
} }
} }
public void loadMessages(String lang, Map<String, String> messages) { public void loadMessages(String lang, Map<String, String> messages) {
Map<String, String> map = messagesMap.row(lang.toLowerCase()); Map<String, String> map = messagesMap.row(lang.toLowerCase());
messages.forEach((k, v) -> map.put(k.toLowerCase(), v)); messages.forEach((k, v) -> map.put(k.toLowerCase(), v));
} }
public void loadMessages(Reader reader) { public void loadMessages(Reader reader) {
loadMessages(DEFAULT_LANG, reader); loadMessages(DEFAULT_LANG, reader);
} }
public void loadMessages(Map<String, String> messages) { public void loadMessages(Map<String, String> messages) {
loadMessages(DEFAULT_LANG, messages); loadMessages(DEFAULT_LANG, messages);
} }
//endregion //endregion
//region Get message //region Get message
public String get(String lang, String key) { public String get(String lang, String key) {
return messagesMap.row(lang.toLowerCase()).getOrDefault(key.toLowerCase(), StringUtils.EMPTY); return messagesMap.row(lang.toLowerCase()).getOrDefault(key.toLowerCase(), StringUtils.EMPTY);
} }
public String get(String lang, String key, Map<String, Object> params) { public String get(String lang, String key, Map<String, Object> params) {
return StringSubstitutor.replace(get(lang, key.toLowerCase()), params, "{", "}"); return StringSubstitutor.replace(get(lang, key.toLowerCase()), params, "{", "}");
} }
public String get(String key) { public String get(String key) {
return get(DEFAULT_LANG, key); return get(DEFAULT_LANG, key);
} }
public String get(String key, Map<String, Object> params) { public String get(String key, Map<String, Object> params) {
return get(DEFAULT_LANG, key, params); return get(DEFAULT_LANG, key, params);
} }
//endregion //endregion
public ParamBuilder paramBuilder() { public ParamBuilder paramBuilder() {
return new ParamBuilder(); return new ParamBuilder();
} }
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class ParamBuilder { public static class ParamBuilder {
private final Map<String, Object> params = new HashMap<>(); private final Map<String, Object> params = new HashMap<>();
public ParamBuilder add(String key, Object value) { public ParamBuilder add(String key, Object value) {
params.put(key, value); params.put(key, value);
return this; return this;
} }
public Map<String, Object> build() { public Map<String, Object> build() {
return params; return params;
} }
} }
} }

View File

@@ -1,150 +0,0 @@
package ghast;
import lombok.experimental.UtilityClass;
import org.apache.commons.text.StringSubstitutor;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@UtilityClass
public class Messages {
private final Map<String/*Key*/, String/*Template|Message*/> MESSAGES_MAP = new HashMap<>();
//region Load messages
/**
* Загрузка сообщений из {@link Properties}
*
* @param properties список сообщений и шаблонов
*/
public void load(Properties properties) {
MESSAGES_MAP.clear();
properties.forEach((key, value) -> MESSAGES_MAP.put(key.toString().trim().toLowerCase(), value.toString().trim()));
}
/**
* Загрузка сообщений из {@link Reader}.
* <p>
* Формат строк: {@code key=value}
* </p>
*
* @param reader {@link Reader} со списоком сообщений и шаблонов
*/
public void load(Reader reader) {
MESSAGES_MAP.clear();
try {
BufferedReader bufferedReader = new BufferedReader(reader);
String line;
while ((line = bufferedReader.readLine()) != null) {
String[] split = line.split("=", 2);
MESSAGES_MAP.put(split[0].trim().toLowerCase(), split[1].trim());
}
} catch (IOException e) {
//TODO заменить на специализированный Exception
throw new RuntimeException("Error load messages: " + e.getMessage(), e);
}
}
/**
* Загрузка сообщений из {@link Map}<{@link String}, {@link String}>.
*
* @param messages список сообщений и шаблонов
*/
public void load(Map<String, String> messages) {
MESSAGES_MAP.clear();
MESSAGES_MAP.putAll(messages);
}
//endregion
//region Get messages
/**
* Получить обычное сообщение по ключу/коду.
*
* @param key ключ/код
* @return сообщение, если таковое задано. Иначе - ключ
*/
public String get(String key) {
String keyLc = key.toLowerCase();
return MESSAGES_MAP.getOrDefault(keyLc, keyLc);
}
/**
* Получить параметизированное сообщение по ключу/коду.
*
* @param key ключ/код
* @param params список параметров
* @return сообщение, если таковое задано. Иначе - ключ
*/
public String get(String key, Map<String, Object> params) {
String keyLc = key.toLowerCase();
if (MESSAGES_MAP.containsKey(keyLc)) {
return format(MESSAGES_MAP.get(keyLc), params);
} else {
return keyLc;
}
}
/**
* Получить параметизированное сообщение по ключу/коду.
*
* @param key ключ/код
* @param params чередующийся по парный список параметров: {@link String (str)param_name}, {@link Object (obj)param_value} и т.д.
* @return сообщение, если таковое задано. Иначе - ключ
*/
public String get(String key, Object... params) {
String keyLc = key.toLowerCase();
if (MESSAGES_MAP.containsKey(keyLc)) {
return format(MESSAGES_MAP.get(keyLc), params);
} else {
return keyLc;
}
}
//endregion
//region Format message
/**
* Получить сообщение по формату.
*
* @param format параметизированное сообщение
* @param params параметры
* @return сообщение
*/
public String format(String format, Map<String, Object> params) {
return StringSubstitutor.replace(format, params, "{", "}");
}
/**
* Получить сообщение по формату.
*
* @param format параметизированное сообщение
* @param params параметры
* @return сообщение
*/
public String format(String format, Object... params) {
return format(format, arrayParamsToMap(params));
}
//endregion
private Map<String, Object> arrayParamsToMap(Object... params) {
int len;
if ((params.length % 2) == 1) {
len = params.length - 1;
} else {
len = params.length;
}
Map<String, Object> map = new HashMap<>(len / 2);
for (int i = 0; i < len; i = i + 2) {
map.put((String) params[i], params[i + 1]);
}
return map;
}
}

View File

@@ -10,68 +10,68 @@ import static java.text.MessageFormat.format;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class XLog { public class XLog {
//region Debug //region Debug
public void debug(String pattern, Object... objects) { public void debug(String pattern, Object... objects) {
if (objects.length > 1 && objects[objects.length - 1] instanceof Throwable) { if (objects.length > 1 && objects[objects.length - 1] instanceof Throwable) {
Throwable throwable = (Throwable) objects[objects.length - 1]; Throwable throwable = (Throwable) objects[objects.length - 1];
Object[] values = new Object[objects.length - 1]; Object[] values = new Object[objects.length - 1];
System.arraycopy(objects, 0, values, 0, values.length); System.arraycopy(objects, 0, values, 0, values.length);
debug(format(pattern, values), throwable); debug(format(pattern, values), throwable);
} else { } else {
debug(format(pattern, objects)); debug(format(pattern, objects));
} }
} }
public void debug(String message, Throwable throwable) { public void debug(String message, Throwable throwable) {
GhastTools.getPlugin().getLogger().log(Level.FINE, message, throwable); GhastTools.getPlugin().getLogger().log(Level.FINE, message, throwable);
} }
public void debug(String message) { public void debug(String message) {
GhastTools.getPlugin().getLogger().fine(message); GhastTools.getPlugin().getLogger().fine(message);
} }
//endregion //endregion
//region Info //region Info
public void info(String pattern, Object... objects) { public void info(String pattern, Object... objects) {
info(format(pattern, objects)); info(format(pattern, objects));
} }
public void info(String message) { public void info(String message) {
GhastTools.getPlugin().getLogger().info(message); GhastTools.getPlugin().getLogger().info(message);
} }
//endregion //endregion
//region Warning //region Warning
public void warn(String pattern, Object... objects) { public void warn(String pattern, Object... objects) {
warn(format(pattern, objects)); warn(format(pattern, objects));
} }
public void warn(String message) { public void warn(String message) {
GhastTools.getPlugin().getLogger().warning(message); GhastTools.getPlugin().getLogger().warning(message);
} }
//endregion //endregion
//region Error //region Error
public void error(String pattern, Object... objects) { public void error(String pattern, Object... objects) {
if (objects.length > 1 && objects[objects.length - 1] instanceof Throwable) { if (objects.length > 1 && objects[objects.length - 1] instanceof Throwable) {
Throwable throwable = (Throwable) objects[objects.length - 1]; Throwable throwable = (Throwable) objects[objects.length - 1];
Object[] values = new Object[objects.length - 1]; Object[] values = new Object[objects.length - 1];
System.arraycopy(objects, 0, values, 0, values.length); System.arraycopy(objects, 0, values, 0, values.length);
error(format(pattern, values), throwable); error(format(pattern, values), throwable);
} else { } else {
error(format(pattern, objects)); error(format(pattern, objects));
} }
} }
public void error(String message) { public void error(String message) {
GhastTools.getPlugin().getLogger().severe(message); GhastTools.getPlugin().getLogger().severe(message);
} }
public void error(String message, Throwable throwable) { public void error(String message, Throwable throwable) {
GhastTools.getPlugin().getLogger().log(Level.SEVERE, message, throwable); GhastTools.getPlugin().getLogger().log(Level.SEVERE, message, throwable);
} }
//endregion //endregion
} }

View File

@@ -2,12 +2,12 @@ package ghast.assets;
public class AssetsException extends RuntimeException { public class AssetsException extends RuntimeException {
public AssetsException(String message) { public AssetsException(String message) {
super(message); super(message);
} }
public AssetsException(String message, Throwable cause) { public AssetsException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
} }

View File

@@ -18,146 +18,146 @@ import static java.text.MessageFormat.format;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class AssetsManager { public class AssetsManager {
private static final String ERROR_NOT_FOUND = "Asset \"{0}\" not found"; private static final String ERROR_NOT_FOUND = "Asset \"{0}\" not found";
private static final String ERROR_OPEN = "Error open asset \"{0}\": {1}"; private static final String ERROR_OPEN = "Error open asset \"{0}\": {1}";
//region getAsInputStream methods //region getAsInputStream methods
public InputStream getAsInputStream(String resourceName, String defaultResourceName, boolean saveDefault) { public InputStream getAsInputStream(String resourceName, String defaultResourceName, boolean saveDefault) {
Plugin plugin = GhastTools.getPlugin(); Plugin plugin = GhastTools.getPlugin();
InputStream inputStream; InputStream inputStream;
Path pathToResource = plugin.getDataFolder().toPath().resolve(resourceName); Path pathToResource = plugin.getDataFolder().toPath().resolve(resourceName);
if (Files.exists(pathToResource)) { if (Files.exists(pathToResource)) {
inputStream = openResource(pathToResource); inputStream = openResource(pathToResource);
} else if (defaultResourceName != null) { } else if (defaultResourceName != null) {
URL resourceUrl = getResourceUrl(defaultResourceName); URL resourceUrl = getResourceUrl(defaultResourceName);
if (saveDefault) { if (saveDefault) {
doSaveTo(resourceUrl, pathToResource); doSaveTo(resourceUrl, pathToResource);
inputStream = openResource(pathToResource); inputStream = openResource(pathToResource);
} else { } else {
inputStream = openResource(resourceUrl); inputStream = openResource(resourceUrl);
} }
} else { } else {
throw new AssetsException(format(ERROR_NOT_FOUND, resourceName)); throw new AssetsException(format(ERROR_NOT_FOUND, resourceName));
} }
return inputStream; return inputStream;
} }
public InputStream getAsInputStream(String resourceName, String defaultResourceName) { public InputStream getAsInputStream(String resourceName, String defaultResourceName) {
return getAsInputStream(resourceName, defaultResourceName, true); return getAsInputStream(resourceName, defaultResourceName, true);
} }
public InputStream getAsInputStream(String resourceName, boolean saveDefault) { public InputStream getAsInputStream(String resourceName, boolean saveDefault) {
return getAsInputStream(resourceName, resourceName, saveDefault); return getAsInputStream(resourceName, resourceName, saveDefault);
} }
public InputStream getAsInputStream(String resourceName) { public InputStream getAsInputStream(String resourceName) {
return getAsInputStream(resourceName, resourceName, true); return getAsInputStream(resourceName, resourceName, true);
} }
//endregion //endregion
//region getAsReader methods //region getAsReader methods
public Reader getAsReader(String resourceName, String defaultResourceName, boolean saveDefault) { public Reader getAsReader(String resourceName, String defaultResourceName, boolean saveDefault) {
return new InputStreamReader(getAsInputStream(resourceName, defaultResourceName, saveDefault)); return new InputStreamReader(getAsInputStream(resourceName, defaultResourceName, saveDefault));
} }
public Reader getAsReader(String resourceName, String defaultResourceName) { public Reader getAsReader(String resourceName, String defaultResourceName) {
return new InputStreamReader(getAsInputStream(resourceName, defaultResourceName, true)); return new InputStreamReader(getAsInputStream(resourceName, defaultResourceName, true));
} }
public Reader getAsReader(String resourceName, boolean saveDefault) { public Reader getAsReader(String resourceName, boolean saveDefault) {
return new InputStreamReader(getAsInputStream(resourceName, resourceName, saveDefault)); return new InputStreamReader(getAsInputStream(resourceName, resourceName, saveDefault));
} }
public Reader getAsReader(String resourceName) { public Reader getAsReader(String resourceName) {
return new InputStreamReader(getAsInputStream(resourceName, resourceName, true)); return new InputStreamReader(getAsInputStream(resourceName, resourceName, true));
} }
//endregion //endregion
//region getAsString methods //region getAsString methods
public String getAsString(String resourceName, String defaultResourceName, Charset charset, boolean saveDefault) { public String getAsString(String resourceName, String defaultResourceName, Charset charset, boolean saveDefault) {
try (InputStream inputStream = getAsInputStream(resourceName, defaultResourceName, saveDefault); try (InputStream inputStream = getAsInputStream(resourceName, defaultResourceName, saveDefault);
Scanner scanner = new Scanner(inputStream, charset.name()).useDelimiter("\\A")) { Scanner scanner = new Scanner(inputStream, charset.name()).useDelimiter("\\A")) {
return scanner.next(); return scanner.next();
} catch (IOException e) { } catch (IOException e) {
throw new AssetsException(format(ERROR_OPEN, resourceName, e.getMessage()), e); throw new AssetsException(format(ERROR_OPEN, resourceName, e.getMessage()), e);
} }
} }
public String getAsString(String resourceName, String defaultResourceName, Charset charset) { public String getAsString(String resourceName, String defaultResourceName, Charset charset) {
return getAsString(resourceName, defaultResourceName, charset, true); return getAsString(resourceName, defaultResourceName, charset, true);
} }
public String getAsString(String resourceName, String defaultResourceName, boolean saveDefault) { public String getAsString(String resourceName, String defaultResourceName, boolean saveDefault) {
return getAsString(resourceName, defaultResourceName, StandardCharsets.UTF_8, saveDefault); return getAsString(resourceName, defaultResourceName, StandardCharsets.UTF_8, saveDefault);
} }
public String getAsString(String resourceName, String defaultResourceName) { public String getAsString(String resourceName, String defaultResourceName) {
return getAsString(resourceName, defaultResourceName, StandardCharsets.UTF_8, true); return getAsString(resourceName, defaultResourceName, StandardCharsets.UTF_8, true);
} }
public String getAsString(String resourceName, Charset charset, boolean saveDefault) { public String getAsString(String resourceName, Charset charset, boolean saveDefault) {
return getAsString(resourceName, resourceName, charset, saveDefault); return getAsString(resourceName, resourceName, charset, saveDefault);
} }
public String getAsString(String resourceName, Charset charset) { public String getAsString(String resourceName, Charset charset) {
return getAsString(resourceName, resourceName, charset, true); return getAsString(resourceName, resourceName, charset, true);
} }
public String getAsString(String resourceName, boolean saveDefault) { public String getAsString(String resourceName, boolean saveDefault) {
return getAsString(resourceName, resourceName, StandardCharsets.UTF_8, saveDefault); return getAsString(resourceName, resourceName, StandardCharsets.UTF_8, saveDefault);
} }
public String getAsString(String resourceName) { public String getAsString(String resourceName) {
return getAsString(resourceName, resourceName, StandardCharsets.UTF_8, true); return getAsString(resourceName, resourceName, StandardCharsets.UTF_8, true);
} }
//endregion //endregion
private URL getResourceUrl(String resourceName) {
URL resourceUrl = AssetsManager.class.getClassLoader().getResource(resourceName);
if (resourceUrl == null) {
throw new AssetsException(format(ERROR_NOT_FOUND, resourceName));
}
private URL getResourceUrl(String resourceName) { return resourceUrl;
URL resourceUrl = AssetsManager.class.getClassLoader().getResource(resourceName); }
if (resourceUrl == null) {
throw new AssetsException(format(ERROR_NOT_FOUND, resourceName));
}
return resourceUrl; private void doSaveTo(URL resourceUrl, Path saveToPath) {
} try {
Files.createDirectories(saveToPath.getParent());
private void doSaveTo(URL resourceUrl, Path saveToPath) { try (InputStream inputStream = resourceUrl.openStream();
try { OutputStream outputStream = Files.newOutputStream(saveToPath)) {
Files.createDirectories(saveToPath.getParent());
try (InputStream inputStream = resourceUrl.openStream(); byte[] buffer = new byte[8192];
OutputStream outputStream = Files.newOutputStream(saveToPath)) { int count;
while ((count = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, count);
}
outputStream.flush();
}
} catch (IOException e) {
throw new AssetsException(format("Error save asset \"{0}\" to \"{1}\": {2}",
resourceUrl, saveToPath, e.getMessage()), e);
}
}
byte[] buffer = new byte[8192]; private InputStream openResource(Path pathToResource) {
int count; try {
while ((count = inputStream.read(buffer)) != -1) { return Files.newInputStream(pathToResource);
outputStream.write(buffer, 0, count); } catch (IOException e) {
} throw new AssetsException(format(ERROR_OPEN, pathToResource, e.getMessage()), e);
outputStream.flush(); }
} }
} catch (IOException e) {
throw new AssetsException(format("Error save asset \"{0}\" to \"{1}\": {2}",
resourceUrl, saveToPath, e.getMessage()), e);
}
}
private InputStream openResource(Path pathToResource) { private InputStream openResource(URL resourceUrl) {
try { try {
return Files.newInputStream(pathToResource); return resourceUrl.openStream();
} catch (IOException e) { } catch (IOException e) {
throw new AssetsException(format(ERROR_OPEN, pathToResource, e.getMessage()), e); throw new AssetsException(format(ERROR_OPEN, resourceUrl, e.getMessage()), e);
} }
} }
private InputStream openResource(URL resourceUrl) {
try {
return resourceUrl.openStream();
} catch (IOException e) {
throw new AssetsException(format(ERROR_OPEN, resourceUrl, e.getMessage()), e);
}
}
} }

View File

@@ -4,5 +4,5 @@ import org.bukkit.command.CommandSender;
public interface CommandExecuter { public interface CommandExecuter {
void execute(CommandSender sender, String[] args); void execute(CommandSender sender, String[] args);
} }

View File

@@ -11,61 +11,61 @@ import ru.dmitriymx.reflection.ReflectionObject;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class CommandManager { public class CommandManager {
public Builder create(String name) { public Builder create(String name) {
return new Builder(name); return new Builder(name);
} }
public void register(String name, CommandExecuter executer) { public void register(String name, CommandExecuter executer) {
create(name).executer(executer).register(); create(name).executer(executer).register();
} }
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public static class Builder { public static class Builder {
private final String name; private final String name;
private CommandExecuter executer; private CommandExecuter executer;
private ErrorConsumer errorConsumer; private ErrorConsumer errorConsumer;
private Boolean onlyPlayer; private Boolean onlyPlayer;
private String deniedMessage; private String deniedMessage;
public Builder executer(CommandExecuter executer) { public Builder executer(CommandExecuter executer) {
this.executer = executer; this.executer = executer;
return this; return this;
} }
public Builder onError(ErrorConsumer errorConsumer) { public Builder onError(ErrorConsumer errorConsumer) {
this.errorConsumer = errorConsumer; this.errorConsumer = errorConsumer;
return this; return this;
} }
public Builder useOnlyPlayer(String deniedMessage) { public Builder useOnlyPlayer(String deniedMessage) {
this.onlyPlayer = true; this.onlyPlayer = true;
this.deniedMessage = deniedMessage; this.deniedMessage = deniedMessage;
return this; return this;
} }
public Builder useOnlyPlayer() { public Builder useOnlyPlayer() {
return useOnlyPlayer(null); return useOnlyPlayer(null);
} }
public Builder useOnlyConsole(String deniedMessage) { public Builder useOnlyConsole(String deniedMessage) {
this.onlyPlayer = false; this.onlyPlayer = false;
this.deniedMessage = deniedMessage; this.deniedMessage = deniedMessage;
return this; return this;
} }
public Builder useOnlyConsole() { public Builder useOnlyConsole() {
return useOnlyConsole(null); return useOnlyConsole(null);
} }
public void register() { public void register() {
//TODO для Paper такие "извращения" не требуются. Нужно продумать. //TODO для Paper такие "извращения" не требуются. Нужно продумать.
new ReflectionObject(Bukkit.getServer()) new ReflectionObject(Bukkit.getServer())
.method("getCommandMap").invoke() .method("getCommandMap").invoke()
.method("register", String.class, Command.class).invoke( .method("register", String.class, Command.class).invoke(
name, new CommandWrapper(name, this.onlyPlayer, this.deniedMessage, name, new CommandWrapper(name, this.onlyPlayer, this.deniedMessage,
this.executer, this.errorConsumer) this.executer, this.errorConsumer)
); );
} }
} }
} }

View File

@@ -8,63 +8,64 @@ import org.bukkit.entity.Player;
class CommandWrapper extends BukkitCommand { class CommandWrapper extends BukkitCommand {
private static final String DEFAULT_DENIED_MESSAGE_PLAYERS = ChatColor.RED + "This command use only players"; private static final String DEFAULT_DENIED_MESSAGE_PLAYERS = ChatColor.RED + "This command use only players";
private static final String DEFAULT_DENIED_MESSAGE_CONSOLE = ChatColor.RED + "This command use only in console"; private static final String DEFAULT_DENIED_MESSAGE_CONSOLE = ChatColor.RED + "This command use only in console";
private static final ErrorConsumer DEFAULT_ERROR_CONSUMER = private static final ErrorConsumer DEFAULT_ERROR_CONSUMER =
(sender, commandName, args, exception) -> { (sender, commandName, args, exception) -> {
sender.sendMessage(String.format("%sError execute command '%s'!", ChatColor.RED, commandName)); sender.sendMessage(String.format("%sError execute command '%s'!", ChatColor.RED, commandName));
XLog.error("Error execute command ''{0}'' with args ''{1}''", XLog.error("Error execute command ''{0}'' with args ''{1}''",
commandName, String.join(" ", args), exception); commandName, String.join(" ", args), exception);
}; };
private final CommandExecuter executer; private final CommandExecuter executer;
private final ErrorConsumer errorConsumer; private final ErrorConsumer errorConsumer;
private final Boolean onlyPlayer; private final Boolean onlyPlayer;
private String deniedMessage; private String deniedMessage;
protected CommandWrapper(String name, Boolean onlyPlayer, String deniedMessage, protected CommandWrapper(String name, Boolean onlyPlayer, String deniedMessage,
CommandExecuter executer, ErrorConsumer errorConsumer) { CommandExecuter executer, ErrorConsumer errorConsumer) {
super(name); super(name);
this.onlyPlayer = onlyPlayer; this.onlyPlayer = onlyPlayer;
this.executer = executer; this.executer = executer;
if (onlyPlayer != null) { if (onlyPlayer != null) {
if (deniedMessage == null) { if (deniedMessage == null) {
this.deniedMessage = Boolean.TRUE.equals(onlyPlayer) ? DEFAULT_DENIED_MESSAGE_PLAYERS this.deniedMessage = Boolean.TRUE.equals(onlyPlayer) ? DEFAULT_DENIED_MESSAGE_PLAYERS
: DEFAULT_DENIED_MESSAGE_CONSOLE; : DEFAULT_DENIED_MESSAGE_CONSOLE;
} else { } else {
this.deniedMessage = deniedMessage; this.deniedMessage = deniedMessage;
} }
} }
if(errorConsumer == null) { if(errorConsumer == null) {
this.errorConsumer = DEFAULT_ERROR_CONSUMER; this.errorConsumer = DEFAULT_ERROR_CONSUMER;
} else { } else {
this.errorConsumer = errorConsumer; this.errorConsumer = errorConsumer;
} }
} }
@Override @Override
public boolean execute(CommandSender commandSender, String commandName, String[] args) { @SuppressWarnings("java:S1066")
if (Boolean.TRUE.equals(onlyPlayer)) { public boolean execute(CommandSender commandSender, String commandName, String[] args) {
if (!(commandSender instanceof Player)) { if (Boolean.TRUE.equals(onlyPlayer)) {
commandSender.sendMessage(deniedMessage); if (!(commandSender instanceof Player)) {
return true; commandSender.sendMessage(deniedMessage);
} return true;
} else if (Boolean.FALSE.equals(onlyPlayer)) { // use console only }
if (commandSender instanceof Player) { } else if (Boolean.FALSE.equals(onlyPlayer)) { // use console only
commandSender.sendMessage(deniedMessage); if (commandSender instanceof Player) {
return true; commandSender.sendMessage(deniedMessage);
} return true;
} }
}
try { try {
executer.execute(commandSender, args); executer.execute(commandSender, args);
return true; return true;
} catch (Exception e) { } catch (Exception e) {
errorConsumer.accept(commandSender, commandName, args, e); errorConsumer.accept(commandSender, commandName, args, e);
return false; return false;
} }
} }
} }

View File

@@ -4,5 +4,5 @@ import org.bukkit.command.CommandSender;
public interface ErrorConsumer { public interface ErrorConsumer {
void accept(CommandSender sender, String commandName, String[] args, Exception exception); void accept(CommandSender sender, String commandName, String[] args, Exception exception);
} }

View File

@@ -4,7 +4,7 @@ import java.sql.SQLException;
public class CannotGetJdbcConnectionException extends DataAccessException { public class CannotGetJdbcConnectionException extends DataAccessException {
public CannotGetJdbcConnectionException(String msg, SQLException ex) { public CannotGetJdbcConnectionException(String msg, SQLException ex) {
super(msg, ex); super(msg, ex);
} }
} }

View File

@@ -2,17 +2,27 @@ package ghast.database;
import lombok.Getter; import lombok.Getter;
@SuppressWarnings("java:S1165")
@Getter @Getter
public class DataAccessException extends RuntimeException { public class DataAccessException extends RuntimeException {
private String sql; private String sql;
public DataAccessException(String msg, Throwable cause) { public DataAccessException(String msg) {
super(msg, cause); super(msg);
} }
public DataAccessException(String msg, String sql, Throwable cause) { public DataAccessException(String msg, String sql) {
this(msg, cause); this(msg);
this.sql = sql; this.sql = sql;
} }
public DataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
public DataAccessException(String msg, String sql, Throwable cause) {
this(msg, cause);
this.sql = sql;
}
} }

View File

@@ -0,0 +1,8 @@
package ghast.database;
public class EmptyResultDataAccessException extends IncorrectResultSizeDataAccessException {
public EmptyResultDataAccessException(int expectedSize) {
super(expectedSize);
}
}

View File

@@ -0,0 +1,8 @@
package ghast.database;
public class IncorrectResultSizeDataAccessException extends DataAccessException {
public IncorrectResultSizeDataAccessException(int expectedSize) {
super("Incorrect result size: expected " + expectedSize);
}
}

View File

@@ -2,21 +2,22 @@ package ghast.database;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
public interface JdbcOperations { public interface JdbcOperations {
void execute(String sql) throws DataAccessException; void execute(String sql) throws DataAccessException;
<T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException; <T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException;
<T> Optional<T> queryOne(String sql, ResultSetExtractor<T> rse) throws DataAccessException; <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException;
<T> List<T> queryList(String sql, RowMapper<T> rowMapper) throws DataAccessException; <T> T queryForObject(String sql, RowMapper<T> rowMapper) throws DataAccessException;
Map<String, Object> queryForMap(String sql) throws DataAccessException; Map<String, Object> queryForMap(String sql) throws DataAccessException;
List<Map<String, Object>> queryForMapList(String sql) throws DataAccessException; List<Map<String, Object>> queryForList(String sql) throws DataAccessException;
int update(String sql) throws DataAccessException; int update(String sql) throws DataAccessException;
int delete(String sql) throws DataAccessException;
} }

View File

@@ -6,239 +6,232 @@ import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.sql.Date;
import java.sql.*; import java.sql.*;
import java.util.*; import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@NoArgsConstructor @NoArgsConstructor
@Getter @Getter
@Setter @Setter
public class JdbcTemplate implements JdbcOperations { public class JdbcTemplate implements JdbcOperations {
private static final String DBG_SQL_INFO = "Execute SQL: {0}"; private DataSource dataSource;
private DataSource dataSource;
public JdbcTemplate(DataSource dataSource) { public JdbcTemplate(DataSource dataSource) {
setDataSource(dataSource); setDataSource(dataSource);
} }
@Override @Override
public void execute(String sql) throws DataAccessException { public void execute(String sql) throws DataAccessException {
XLog.debug(DBG_SQL_INFO, sql); XLog.debug("Execute SQL: {0}", sql);
Connection connection = openConnection(); Connection connection = openConnection();
Statement statement = null; Statement statement = null;
try { try {
statement = connection.createStatement(); statement = connection.createStatement();
statement.execute(sql); statement.execute(sql);
} catch (SQLException e) { } catch (SQLException e) {
throw new DataAccessException("Error execute SQL", sql, e); throw new DataAccessException("Error execute SQL", sql, e);
} finally { } finally {
closeStatement(statement); closeStatement(statement);
closeConnection(connection); closeConnection(connection);
} }
} }
@Override @Override
public <T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException { public <T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException {
XLog.debug(DBG_SQL_INFO, sql); XLog.debug("Execute SQL: {0}", sql);
Connection connection = openConnection(); Connection connection = openConnection();
Statement statement = null; Statement statement = null;
ResultSet resultSet = null; ResultSet resultSet = null;
try { try {
statement = connection.createStatement(); statement = connection.createStatement();
resultSet = statement.executeQuery(sql); resultSet = statement.executeQuery(sql);
return rse.extractData(resultSet); return rse.extractData(resultSet);
} catch (SQLException e) { } catch (SQLException e) {
throw new DataAccessException("Error execute SQL", sql, e); throw new DataAccessException("Error execute SQL", sql, e);
} finally { } finally {
closeResultSet(resultSet); closeResultSet(resultSet);
closeStatement(statement); closeStatement(statement);
closeConnection(connection); closeConnection(connection);
} }
} }
@Override @Override
public <T> Optional<T> queryOne(String sql, ResultSetExtractor<T> rse) throws DataAccessException { public <T> List<T> query(String sql, final RowMapper<T> rowMapper) throws DataAccessException {
return query(sql, rs -> { return query(sql, rs -> {
if (rs.next()) { List<T> resultList = new ArrayList<>();
return Optional.ofNullable(rse.extractData(rs)); int rowNum = 0;
} else { while (rs.next()) {
return Optional.empty(); resultList.add(rowMapper.mapRow(rs, rowNum++));
} }
}); return resultList;
} });
}
@Override @Override
public <T> List<T> queryList(String sql, final RowMapper<T> rowMapper) throws DataAccessException { public <T> T queryForObject(String sql, RowMapper<T> rowMapper) throws DataAccessException {
return query(sql, rs -> { return query(sql, rs -> {
List<T> resultList; if (rs.next()) {
int rowNum = 0; T resultObj = rowMapper.mapRow(rs, 0);
if (rs.next()) {
resultList = new ArrayList<>();
do { if (rs.next()) {
resultList.add(rowMapper.mapRow(rs, rowNum++)); throw new IncorrectResultSizeDataAccessException(1);
} while (rs.next()); }
} else {
resultList = Collections.emptyList();
}
return resultList; return resultObj;
}); } else {
} throw new EmptyResultDataAccessException(1);
}
});
}
@Override @Override
public Map<String, Object> queryForMap(String sql) throws DataAccessException { public Map<String, Object> queryForMap(String sql) throws DataAccessException {
return query(sql, rs -> { return queryForObject(sql, (rs, rowNum) -> {
if (rs.next()) { ResultSetMetaData metaData = rs.getMetaData();
ResultSetMetaData metaData = rs.getMetaData(); int columnCount = metaData.getColumnCount();
int columnCount = metaData.getColumnCount(); Map<String, Object> resultMap = new LinkedHashMap<>(columnCount);
return rowToMap(columnCount, metaData, rs); for (int i = 1; i <= columnCount; i++) {
} else { String key = lookupColumnName(metaData, i);
return Collections.emptyMap(); Object value = getResultSetRawValue(rs, i);
} resultMap.put(key, value);
}); }
}
@Override return resultMap;
public List<Map<String, Object>> queryForMapList(String sql) throws DataAccessException { });
return query(sql, rs -> { }
List<Map<String, Object>> resultList;
if (rs.next()) { @Override
resultList = new ArrayList<>(); public List<Map<String, Object>> queryForList(String sql) throws DataAccessException {
return query(sql, (rs, rowNum) -> {
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
Map<String, Object> resultMap = new LinkedHashMap<>(columnCount);
ResultSetMetaData metaData = rs.getMetaData(); for (int i = 1; i <= columnCount; i++) {
int columnCount = metaData.getColumnCount(); String key = lookupColumnName(metaData, i);
Object value = getResultSetRawValue(rs, i);
resultMap.put(key, value);
}
do { return resultMap;
resultList.add(rowToMap(columnCount, metaData, rs)); });
} while (rs.next()); }
} else {
resultList = Collections.emptyList();
}
return resultList; @Override
}); public int update(String sql) throws DataAccessException {
} XLog.debug("Execute SQL: {0}", sql);
@Override Connection connection = openConnection();
public int update(String sql) throws DataAccessException { Statement statement = null;
XLog.debug(DBG_SQL_INFO, sql); try {
statement = connection.createStatement();
int rows = statement.executeUpdate(sql);
XLog.debug("Affected {0} rows", rows);
return rows;
} catch (SQLException e) {
XLog.error("Error execute SQL: {0}", e.getMessage(), e);
return 0;
} finally {
closeStatement(statement);
closeConnection(connection);
}
}
Connection connection = openConnection(); @Override
Statement statement = null; public int delete(String sql) throws DataAccessException {
try { return update(sql);
statement = connection.createStatement(); }
int rows = statement.executeUpdate(sql);
XLog.debug("Affected {0} rows", rows);
return rows;
} catch (SQLException e) {
XLog.error("Error execute SQL: {0}", e.getMessage(), e);
return 0;
} finally {
closeStatement(statement);
closeConnection(connection);
}
}
private Connection openConnection() { private Connection openConnection() {
try { try {
return getDataSource().getConnection(); return getDataSource().getConnection();
} catch (SQLException ex) { }
throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex); catch (SQLException ex) {
} throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
} }
}
private String lookupColumnName(ResultSetMetaData resultSetMetaData, int columnIndex) throws SQLException { private String lookupColumnName(ResultSetMetaData resultSetMetaData, int columnIndex) throws SQLException {
String name = resultSetMetaData.getColumnLabel(columnIndex); String name = resultSetMetaData.getColumnLabel(columnIndex);
if (name == null || name.isEmpty()) { if (name == null || name.isEmpty()) {
name = resultSetMetaData.getColumnName(columnIndex); name = resultSetMetaData.getColumnName(columnIndex);
} }
return name; return name;
} }
private Map<String, Object> rowToMap(int columnCount, ResultSetMetaData metaData, ResultSet rs) throws SQLException { private Object getResultSetRawValue(ResultSet resultSet, int index) throws SQLException {
Map<String, Object> rowMap = new LinkedHashMap<>(columnCount); Object obj = resultSet.getObject(index);
String className = null;
if (obj != null) {
className = obj.getClass().getName();
}
for (int i = 1; i <= columnCount; i++) { if (obj instanceof Blob) {
String key = lookupColumnName(metaData, i); Blob blob = (Blob) obj;
Object value = getResultSetRawValue(rs, i); obj = blob.getBytes(1, (int) blob.length());
rowMap.put(key, value); } else if (obj instanceof Clob) {
} Clob clob = (Clob) obj;
obj = clob.getSubString(1, (int) clob.length());
} else if ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ".equals(className)) {
obj = resultSet.getTimestamp(index);
} else if (className != null && className.startsWith("oracle.sql.DATE")) {
String metaDataClassName = resultSet.getMetaData().getColumnClassName(index);
if ("java.sql.Timestamp".equals(metaDataClassName) || "oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
obj = resultSet.getTimestamp(index);
}
else {
obj = resultSet.getDate(index);
}
} else if (obj instanceof Date) {
if ("java.sql.Timestamp".equals(resultSet.getMetaData().getColumnClassName(index))) {
obj = resultSet.getTimestamp(index);
}
}
return rowMap; return obj;
} }
private Object getResultSetRawValue(ResultSet resultSet, int index) throws SQLException { private void closeResultSet(ResultSet resultSet) {
Object obj = resultSet.getObject(index); if (resultSet != null) {
if (obj == null) { try {
return null; resultSet.close();
} } catch (SQLException e) {
XLog.debug("Could not close JDBC ResultSet", e);
} catch (Exception e) {
XLog.debug("Unexpected exception on closing JDBC ResultSet", e);
}
}
}
String className = obj.getClass().getName(); private void closeStatement(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
XLog.debug("Could not close JDBC Statement", e);
} catch (Exception e) {
XLog.debug("Unexpected exception on closing JDBC Statement", e);
}
}
}
if (obj instanceof Blob) { private void closeConnection(Connection con) {
Blob blob = (Blob) obj; if (con == null) {
obj = blob.getBytes(1, (int) blob.length()); return;
} else if (obj instanceof Clob) { }
Clob clob = (Clob) obj;
obj = clob.getSubString(1, (int) clob.length());
} else if ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ".equals(className)) {
obj = resultSet.getTimestamp(index);
} else if (className.startsWith("oracle.sql.DATE")) {
String metaDataClassName = resultSet.getMetaData().getColumnClassName(index);
if ("java.sql.Timestamp".equals(metaDataClassName) || "oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
obj = resultSet.getTimestamp(index);
} else {
obj = resultSet.getDate(index);
}
} else if (obj instanceof Date
&& "java.sql.Timestamp".equals(resultSet.getMetaData().getColumnClassName(index))) {
obj = resultSet.getTimestamp(index);
}
return obj; try {
} con.close();
} catch (SQLException e) {
private void closeResultSet(ResultSet resultSet) { XLog.debug("Could not close JDBC Connection", e);
if (resultSet != null) { } catch (Exception e) {
try { XLog.debug("Unexpected exception on closing JDBC Connection", e);
resultSet.close(); }
} catch (SQLException e) { }
XLog.debug("Could not close JDBC ResultSet", e);
} catch (Exception e) {
XLog.debug("Unexpected exception on closing JDBC ResultSet", e);
}
}
}
private void closeStatement(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
XLog.debug("Could not close JDBC Statement", e);
} catch (Exception e) {
XLog.debug("Unexpected exception on closing JDBC Statement", e);
}
}
}
private void closeConnection(Connection con) {
if (con == null) {
return;
}
try {
con.close();
} catch (SQLException e) {
XLog.debug("Could not close JDBC Connection", e);
} catch (Exception e) {
XLog.debug("Unexpected exception on closing JDBC Connection", e);
}
}
} }

View File

@@ -5,5 +5,5 @@ import java.sql.SQLException;
public interface ResultSetExtractor<T> { public interface ResultSetExtractor<T> {
T extractData(ResultSet rs) throws SQLException, DataAccessException; T extractData(ResultSet rs) throws SQLException, DataAccessException;
} }

View File

@@ -5,5 +5,5 @@ import java.sql.SQLException;
public interface RowMapper<T> { public interface RowMapper<T> {
T mapRow(ResultSet rs, int rowNum) throws SQLException; T mapRow(ResultSet rs, int rowNum) throws SQLException;
} }

View File

@@ -8,26 +8,26 @@ import java.util.function.Supplier;
@RequiredArgsConstructor @RequiredArgsConstructor
public class BukkitScheduleTask implements ScheduleTask { public class BukkitScheduleTask implements ScheduleTask {
private final Supplier<BukkitTask> generator; private final Supplier<BukkitTask> generator;
private BukkitTask bukkitTask; private BukkitTask bukkitTask;
@Override @Override
public void start() { public void start() {
if (isCanceled()) { if (isCanceled()) {
bukkitTask = generator.get(); bukkitTask = generator.get();
} }
} }
@Override @Override
public boolean isCanceled() { public boolean isCanceled() {
return bukkitTask == null || bukkitTask.isCancelled(); return bukkitTask == null || bukkitTask.isCancelled();
} }
@Override @Override
public void cancel() { public void cancel() {
if (bukkitTask != null) { if (bukkitTask != null) {
bukkitTask.cancel(); bukkitTask.cancel();
bukkitTask = null; bukkitTask = null;
} }
} }
} }

View File

@@ -8,26 +8,26 @@ import java.util.function.Supplier;
@RequiredArgsConstructor @RequiredArgsConstructor
public class JavaScheduleTask implements ScheduleTask { public class JavaScheduleTask implements ScheduleTask {
private final Supplier<Future<?>> generator; private final Supplier<Future<?>> generator;
private Future<?> future; private Future<?> future;
@Override @Override
public void start() { public void start() {
if (future == null || future.isDone()) { if (future == null || future.isDone()) {
future = generator.get(); future = generator.get();
} }
} }
@Override @Override
public boolean isCanceled() { public boolean isCanceled() {
return future == null || future.isCancelled(); return future == null || future.isCancelled();
} }
@Override @Override
public void cancel() { public void cancel() {
if (future != null) { if (future != null) {
future.cancel(true); future.cancel(true);
future = null; future = null;
} }
} }
} }

View File

@@ -14,100 +14,100 @@ import java.util.concurrent.*;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class ScheduleManager { public class ScheduleManager {
private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder() private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder()
.setNameFormat("ScheduleManager-Thread-%d") .setNameFormat("ScheduleManager-Thread-%d")
.setDaemon(true) .setDaemon(true)
.build(); .build();
public Builder createTask() { public Builder createTask() {
return new Builder(); return new Builder();
} }
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class Builder { public static class Builder {
private static final long MS_PER_ONE_TICK = 1000L/*one second by ms*/ / 20L/*tick per second*/; private static final long MS_PER_ONE_TICK = 1000L/*one second by ms*/ / 20L/*tick per second*/;
private boolean useBukkitScheduler = false; private boolean useBukkitScheduler = false;
private Long afterMs; private Long afterMs;
private Long everyMs; private Long everyMs;
public Builder useBukkitScheduler() { public Builder useBukkitScheduler() {
this.useBukkitScheduler = true; this.useBukkitScheduler = true;
return this; return this;
} }
public Builder after(long value, TimeUnit unit) { public Builder after(long value, TimeUnit unit) {
this.afterMs = unit.toMillis(value); this.afterMs = unit.toMillis(value);
return this; return this;
} }
public Builder every(long value, TimeUnit unit) { public Builder every(long value, TimeUnit unit) {
this.everyMs = unit.toMillis(value); this.everyMs = unit.toMillis(value);
return this; return this;
} }
public ScheduleTask create(Runnable runnable) { public ScheduleTask create(Runnable runnable) {
if (useBukkitScheduler) { if (useBukkitScheduler) {
return createBukkitSchedule(runnable); return createBukkitSchedule(runnable);
} else { } else {
return createSchedule(runnable); return createSchedule(runnable);
} }
} }
public ScheduleTask execute(Runnable runnable) { public ScheduleTask execute(Runnable runnable) {
ScheduleTask scheduleTask = create(runnable); ScheduleTask scheduleTask = create(runnable);
scheduleTask.start(); scheduleTask.start();
return scheduleTask; return scheduleTask;
} }
private ScheduleTask createBukkitSchedule(Runnable runnable) { private ScheduleTask createBukkitSchedule(Runnable runnable) {
BukkitScheduler bukkitScheduler = Bukkit.getScheduler(); BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
BukkitScheduleTask resultTask; BukkitScheduleTask resultTask;
if (this.afterMs == null && this.everyMs == null) { if (this.afterMs == null && this.everyMs == null) {
resultTask = new BukkitScheduleTask(() -> bukkitScheduler.runTask(GhastTools.getPlugin(), runnable)); resultTask = new BukkitScheduleTask(() -> bukkitScheduler.runTask(GhastTools.getPlugin(), runnable));
} else if (this.everyMs != null) { } else if (this.everyMs != null) {
long everyTicks = this.everyMs / MS_PER_ONE_TICK; long everyTicks = this.everyMs / MS_PER_ONE_TICK;
long afterTicks = this.afterMs != null ? this.afterMs / MS_PER_ONE_TICK : 0; long afterTicks = this.afterMs != null ? this.afterMs / MS_PER_ONE_TICK : 0;
resultTask = new BukkitScheduleTask(() -> resultTask = new BukkitScheduleTask(() ->
bukkitScheduler.runTaskTimer(GhastTools.getPlugin(), runnable, afterTicks, everyTicks)); bukkitScheduler.runTaskTimer(GhastTools.getPlugin(), runnable, afterTicks, everyTicks));
} else { } else {
long ticks = this.afterMs / MS_PER_ONE_TICK; long ticks = this.afterMs / MS_PER_ONE_TICK;
resultTask = new BukkitScheduleTask(() -> resultTask = new BukkitScheduleTask(() ->
bukkitScheduler.runTaskLater(GhastTools.getPlugin(), runnable, ticks)); bukkitScheduler.runTaskLater(GhastTools.getPlugin(), runnable, ticks));
} }
return resultTask; return resultTask;
} }
private ScheduleTask createSchedule(Runnable runnable) { private ScheduleTask createSchedule(Runnable runnable) {
ExecutorService executorService; ExecutorService executorService;
JavaScheduleTask resultTask; JavaScheduleTask resultTask;
if (this.afterMs == null && this.everyMs == null) { if (this.afterMs == null && this.everyMs == null) {
executorService = Executors.newSingleThreadExecutor(THREAD_FACTORY); executorService = Executors.newSingleThreadExecutor(THREAD_FACTORY);
resultTask = new JavaScheduleTask(() -> executorService.submit(runnable)); resultTask = new JavaScheduleTask(() -> executorService.submit(runnable));
} else if (this.everyMs != null) { } else if (this.everyMs != null) {
ScheduledExecutorService scheduledExecutorService ScheduledExecutorService scheduledExecutorService
= Executors.newScheduledThreadPool(1, THREAD_FACTORY); = Executors.newScheduledThreadPool(1, THREAD_FACTORY);
resultTask = new JavaScheduleTask(() -> resultTask = new JavaScheduleTask(() ->
scheduledExecutorService.scheduleAtFixedRate(runnable, scheduledExecutorService.scheduleAtFixedRate(runnable,
this.afterMs != null ? this.afterMs : 0, this.afterMs != null ? this.afterMs : 0,
everyMs, TimeUnit.MILLISECONDS)); everyMs, TimeUnit.MILLISECONDS));
executorService = scheduledExecutorService; executorService = scheduledExecutorService;
} else { } else {
ScheduledExecutorService scheduledExecutorService ScheduledExecutorService scheduledExecutorService
= Executors.newScheduledThreadPool(1, THREAD_FACTORY); = Executors.newScheduledThreadPool(1, THREAD_FACTORY);
resultTask = new JavaScheduleTask(() -> resultTask = new JavaScheduleTask(() ->
scheduledExecutorService.schedule(runnable, afterMs, TimeUnit.MILLISECONDS)); scheduledExecutorService.schedule(runnable, afterMs, TimeUnit.MILLISECONDS));
executorService = scheduledExecutorService; executorService = scheduledExecutorService;
} }
executorService.shutdown(); executorService.shutdown();
return resultTask; return resultTask;
} }
} }
} }

View File

@@ -2,9 +2,9 @@ package ghast.scheduler;
public interface ScheduleTask { public interface ScheduleTask {
void start(); void start();
boolean isCanceled(); boolean isCanceled();
void cancel(); void cancel();
} }

View File

@@ -17,7 +17,6 @@ import java.sql.SQLException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.StringJoiner; import java.util.StringJoiner;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -29,261 +28,218 @@ import static org.mockito.Mockito.when;
class JdbcTemplateTest { class JdbcTemplateTest {
static final String JDBC_USER = "sa"; static final String JDBC_USER = "sa";
static final String JDBC_PASSWORD = ""; static final String JDBC_PASSWORD = "";
static final String JDBC_DB_NAME = "in_mem_db"; static final String JDBC_DB_NAME = "in_mem_db";
static final String JDBC_URL = "jdbc:h2:mem:" + JDBC_DB_NAME + ";DB_CLOSE_DELAY=-1"; static final String JDBC_URL = "jdbc:h2:mem:" + JDBC_DB_NAME + ";DB_CLOSE_DELAY=-1";
static final String TABLE_NAME = "TEST_TABLE"; static final String TABLE_NAME = "TEST_TABLE";
static final String COLUMN_ID = "ID"; static final String COLUMN_ID = "ID";
static final String COLUMN_NAME = "C_NAME"; static final String COLUMN_NAME = "C_NAME";
static final String COLUMN_VALUE = "C_VALUE"; static final String COLUMN_VALUE = "C_VALUE";
static final Object[][] DATA = new Object[][]{ static final Object[][] DATA = new Object[][]{
{ "Player 1", 100 }, { "Player 2", 250 }, { "Player 1", 100 }, { "Player 2", 250 },
{ "Player 3", 0 }, { "Player 4", 780 } { "Player 3", 0 }, { "Player 4", 780 }
}; };
static DataSource dataSource; static DataSource dataSource;
JdbcTemplate jdbcTemplate; JdbcTemplate jdbcTemplate;
@BeforeAll @BeforeAll
static void beforeAll() { static void beforeAll() {
Logger logger = Logger.getLogger(JdbcTemplateTest.class.getName()); Logger logger = Logger.getLogger(JdbcTemplateTest.class.getName());
Plugin mockPlugin = mock(Plugin.class); Plugin mockPlugin = mock(Plugin.class);
when(mockPlugin.getLogger()).thenReturn(logger); when(mockPlugin.getLogger()).thenReturn(logger);
GhastTools.setPlugin(mockPlugin); GhastTools.setPlugin(mockPlugin);
JdbcDataSource jdbcDataSource = new JdbcDataSource(); JdbcDataSource jdbcDataSource = new JdbcDataSource();
jdbcDataSource.setUser(JDBC_USER); jdbcDataSource.setUser(JDBC_USER);
jdbcDataSource.setPassword(JDBC_PASSWORD); jdbcDataSource.setPassword(JDBC_PASSWORD);
jdbcDataSource.setURL(JDBC_URL); jdbcDataSource.setURL(JDBC_URL);
dataSource = jdbcDataSource; dataSource = jdbcDataSource;
} }
@BeforeEach @BeforeEach
void before() { void before() {
jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate = new JdbcTemplate(dataSource);
createTable(); createTable();
String sql_head = MessageFormat.format("INSERT INTO {0} ({1}, {2}) VALUES ", String sql_head = MessageFormat.format("INSERT INTO {0} ({1}, {2}) VALUES ",
TABLE_NAME, COLUMN_NAME, COLUMN_VALUE); TABLE_NAME, COLUMN_NAME, COLUMN_VALUE);
StringJoiner sql_sj = new StringJoiner(", "); StringJoiner sql_sj = new StringJoiner(", ");
for (Object[] datum : DATA) { for (Object[] datum : DATA) {
sql_sj.add(MessageFormat.format("( ''{0}'', {1} )", datum[0], datum[1])); sql_sj.add(MessageFormat.format("( ''{0}'', {1} )", datum[0], datum[1]));
} }
jdbcTemplate.execute(sql_head + sql_sj.toString()); jdbcTemplate.execute(sql_head + sql_sj.toString());
} }
@AfterEach @AfterEach
void after() { void after() {
dropTable(); dropTable();
} }
@Test @Test
void testQuery_Simple_Single() { void testQuery_Single() {
String sql = MessageFormat.format("SELECT {2} FROM {0} WHERE {1} LIKE ''{3}''", String sql = MessageFormat.format("SELECT {2} FROM {0} WHERE {1} LIKE ''{3}''",
TABLE_NAME, COLUMN_NAME, COLUMN_VALUE, DATA[0][0]); TABLE_NAME, COLUMN_NAME, COLUMN_VALUE, DATA[0][0]);
Integer value = jdbcTemplate.query(sql, rs -> { Integer value = jdbcTemplate.query(sql, rs -> {
if (rs.next()) { if (rs.next()) {
return rs.getInt(1); return rs.getInt(1);
} else { } else {
return null; return null;
} }
}); });
assertEquals(DATA[0][1], value); assertEquals(DATA[0][1], value);
} }
@Test @Test
void testQuery_Simple_Optional() { void testQuery_List() {
String sql = MessageFormat.format("SELECT {2} FROM {0} WHERE {1} LIKE ''{3}''", String sql = MessageFormat.format("SELECT {2} FROM {0} WHERE {1} LIKE ''{3}'' OR {1} LIKE ''{4}''",
TABLE_NAME, COLUMN_NAME, COLUMN_VALUE, DATA[0][0]); TABLE_NAME, COLUMN_NAME, COLUMN_VALUE, DATA[0][0], DATA[1][0]);
Optional<Integer> optValue = jdbcTemplate.queryOne(sql, rs -> rs.getInt(1)); List<Integer> listValues = jdbcTemplate.query(sql, (rs, rowNum) -> rs.getInt(1));
assertTrue(optValue.isPresent()); assertIterableEquals(Lists.newArrayList(DATA[0][1], DATA[1][1]), listValues);
assertEquals(DATA[0][1], optValue.get()); }
}
@Test @Test
void testQuery_Simple_List() { void testQueryForObject() {
String sql = MessageFormat.format("SELECT {2} FROM {0} WHERE {1} LIKE ''{3}'' OR {1} LIKE ''{4}''", class Player {
TABLE_NAME, COLUMN_NAME, COLUMN_VALUE, DATA[0][0], DATA[1][0]); String name;
int value;
List<Integer> listValues = jdbcTemplate.queryList(sql, (rs, rowNum) -> rs.getInt(1)); @Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Player)) return false;
Player player = (Player) o;
return new EqualsBuilder().append(value, player.value).append(name, player.name).isEquals();
}
assertIterableEquals(Lists.newArrayList(DATA[0][1], DATA[1][1]), listValues); @Override
} public int hashCode() {
return new HashCodeBuilder(17, 37).append(name).append(value).toHashCode();
}
}
@Test String sql = MessageFormat.format("SELECT {1}, {2} FROM {0} WHERE {1} LIKE ''{3}''",
void testQuery_Object_Single() { TABLE_NAME, COLUMN_NAME, COLUMN_VALUE, DATA[0][0]);
String sql = MessageFormat.format("SELECT {1}, {2} FROM {0} WHERE {1} LIKE ''{3}''",
TABLE_NAME, COLUMN_NAME, COLUMN_VALUE, DATA[0][0]);
Player actualPlayer = jdbcTemplate.query(sql, rs -> { Player actualPlayer = jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
if (rs.next()) { Player player0 = new Player();
Player player0 = new Player(); player0.name = rs.getString(COLUMN_NAME);
player0.name = rs.getString(COLUMN_NAME); player0.value = rs.getInt(COLUMN_VALUE);
player0.value = rs.getInt(COLUMN_VALUE);
return player0; return player0;
} else { });
return null;
}
});
Player expectedPlayer = new Player(); Player expectedPlayer = new Player();
expectedPlayer.name = (String) DATA[0][0]; expectedPlayer.name = (String) DATA[0][0];
expectedPlayer.value = (int) DATA[0][1]; expectedPlayer.value = (int) DATA[0][1];
assertEquals(expectedPlayer, actualPlayer); assertEquals(expectedPlayer, actualPlayer);
} }
@Test @Test
void testQuery_Object_List() { void testQueryForMap() {
String sql = MessageFormat.format("SELECT {1}, {2} FROM {0}", String sql = MessageFormat.format("SELECT {1}, {2} FROM {0} WHERE {1} LIKE ''{3}''",
TABLE_NAME, COLUMN_NAME, COLUMN_VALUE); TABLE_NAME, COLUMN_NAME, COLUMN_VALUE, DATA[0][0]);
List<Player> actualPlayers = jdbcTemplate.queryList(sql, (rs, num) -> { Map<String, Object> actualMap = jdbcTemplate.queryForMap(sql);
Player player0 = new Player();
player0.name = rs.getString(COLUMN_NAME);
player0.value = rs.getInt(COLUMN_VALUE);
return player0; Map<String, Object> expectedMap = ImmutableMap.of(
}); COLUMN_NAME, DATA[0][0],
COLUMN_VALUE, DATA[0][1]);
assertIterableEquals(expectedMap.entrySet(), actualMap.entrySet());
}
List<Player> expectedPlayers = Stream.of(DATA) @Test
.map(datum -> { void testQueryForList() {
Player player1 = new Player(); String sql = MessageFormat.format("SELECT {1}, {2} FROM {0}",
player1.name = (String) datum[0]; TABLE_NAME, COLUMN_NAME, COLUMN_VALUE);
player1.value = (int) datum[1];
return player1; List<Map<String, Object>> actualMapList = jdbcTemplate.queryForList(sql);
})
.collect(Collectors.toList());
List<Map<String, Object>> expectedMapList = Stream.of(DATA)
.map(datum -> ImmutableMap.of(COLUMN_NAME, datum[0], COLUMN_VALUE, datum[1]))
.collect(Collectors.toList());
assertIterableEquals(expectedPlayers, actualPlayers); assertIterableEquals(expectedMapList, actualMapList);
}
@Test }
void testQueryForMap() {
String sql = MessageFormat.format("SELECT {1}, {2} FROM {0} WHERE {1} LIKE ''{3}''",
TABLE_NAME, COLUMN_NAME, COLUMN_VALUE, DATA[0][0]);
Map<String, Object> actualMap = jdbcTemplate.queryForMap(sql); @Test
void testUpdate() {
String newName = "Player X";
String sql = MessageFormat.format("UPDATE {0} SET {1} = ''{3}'' WHERE {1} LIKE ''{2}''",
TABLE_NAME, COLUMN_NAME, DATA[0][0], newName);
Map<String, Object> expectedMap = ImmutableMap.of( int rows = jdbcTemplate.update(sql);
COLUMN_NAME, DATA[0][0],
COLUMN_VALUE, DATA[0][1]);
assertIterableEquals(expectedMap.entrySet(), actualMap.entrySet()); assertEquals(1, rows);
}
@Test sql = MessageFormat.format("SELECT {2} FROM {0} WHERE {1} LIKE ''{3}''",
void testQueryForMapList() { TABLE_NAME, COLUMN_NAME, COLUMN_VALUE, newName);
String sql = MessageFormat.format("SELECT {1}, {2} FROM {0}",
TABLE_NAME, COLUMN_NAME, COLUMN_VALUE);
List<Map<String, Object>> actualMapList = jdbcTemplate.queryForMapList(sql); Integer value = jdbcTemplate.query(sql, rs -> {
if (rs.next()) {
return rs.getInt(1);
} else {
return null;
}
});
List<Map<String, Object>> expectedMapList = Stream.of(DATA) assertEquals(DATA[0][1], value);
.map(datum -> ImmutableMap.of(COLUMN_NAME, datum[0], COLUMN_VALUE, datum[1])) }
.collect(Collectors.toList());
assertIterableEquals(expectedMapList, actualMapList); private void createTable() {
jdbcTemplate.execute("CREATE TABLE " + TABLE_NAME + " (" +
COLUMN_ID + " bigint auto_increment," +
COLUMN_NAME + " varchar(16)," +
COLUMN_VALUE + " integer)");
}
} private void dropTable() {
jdbcTemplate.execute("DROP TABLE IF EXISTS " + TABLE_NAME);
}
@Test @Nested
void testUpdate() { class JdbcTemplateTest_ExecuteTestCase {
String newName = "Player X";
String sql = MessageFormat.format("UPDATE {0} SET {1} = ''{3}'' WHERE {1} LIKE ''{2}''",
TABLE_NAME, COLUMN_NAME, DATA[0][0], newName);
int rows = jdbcTemplate.update(sql); @BeforeEach
void before() {
jdbcTemplate = new JdbcTemplate(dataSource);
dropTable();
}
assertEquals(1, rows); @AfterEach
void after() {
dropTable();
}
sql = MessageFormat.format("SELECT {2} FROM {0} WHERE {1} LIKE ''{3}''", @Test
TABLE_NAME, COLUMN_NAME, COLUMN_VALUE, newName); void test() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
createTable();
Integer value = jdbcTemplate.query(sql, rs -> { //region Check result
if (rs.next()) { Class.forName("org.h2.Driver").newInstance();
return rs.getInt(1); Connection connection = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
} else { ResultSet resultSet = connection.getMetaData().getTables(JDBC_DB_NAME.toUpperCase(), "PUBLIC",
return null; TABLE_NAME.toUpperCase(), new String[]{"TABLE"});
}
});
assertEquals(DATA[0][1], value); assertTrue(resultSet.next());
}
private void createTable() { resultSet.close();
jdbcTemplate.execute("CREATE TABLE " + TABLE_NAME + " (" + connection.close();
COLUMN_ID + " bigint auto_increment," + //endregion
COLUMN_NAME + " varchar(16)," + }
COLUMN_VALUE + " integer)"); }
}
private void dropTable() {
jdbcTemplate.execute("DROP TABLE IF EXISTS " + TABLE_NAME);
}
class Player {
String name;
int value;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Player)) return false;
Player player = (Player) o;
return new EqualsBuilder().append(value, player.value).append(name, player.name).isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37).append(name).append(value).toHashCode();
}
}
@Nested
class JdbcTemplateTest_ExecuteTestCase {
@BeforeEach
void before() {
jdbcTemplate = new JdbcTemplate(dataSource);
dropTable();
}
@AfterEach
void after() {
dropTable();
}
@Test
void test() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
createTable();
//region Check result
Class.forName("org.h2.Driver").newInstance();
Connection connection = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
ResultSet resultSet = connection.getMetaData().getTables(JDBC_DB_NAME.toUpperCase(), "PUBLIC",
TABLE_NAME.toUpperCase(), new String[]{"TABLE"});
assertTrue(resultSet.next());
resultSet.close();
connection.close();
//endregion
}
}
} }