Archived
0

JDBC -> JPA

This commit is contained in:
2018-10-07 19:05:19 +03:00
parent 48b8d0377c
commit f9553794e9
21 changed files with 420 additions and 697 deletions

View File

@@ -1,12 +1,17 @@
version '1.0-SNAPSHOT'
ext {
spring_data_version = '2.1.0.RELEASE'
}
dependencies {
/* Core */
compile_excludeCopy project(':core')
/* Spring */
compile (group: 'org.springframework', name: 'spring-jdbc', version: spring_version)
compile (group: 'org.springframework.data', name: 'spring-data-jpa', version: spring_data_version)
/* Database */
compile (group: 'org.hibernate', name: 'hibernate-entitymanager', version: '5.3.6.Final')
compile (group: 'com.h2database', name: 'h2', version: '1.4.197')
}

View File

@@ -1,259 +0,0 @@
package mc.core.h2db;
import lombok.extern.slf4j.Slf4j;
import mc.core.EntityLocation;
import mc.core.world.World;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.UUID;
@Slf4j
@Component
public class H2PlayerDAO {
private static String INSERT_SQL, INSERT2_SQL,
SELECT_BYNAME_SQL, SELECT_BYID_SQL,
UPDATE_SQL, UPDATE_LOCATION_SQL,
DELETE_SQL;
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private World world;
@PostConstruct
public void init() throws IOException {
jdbcTemplate.execute(IOUtils.resourceToString("/sqls/create_tables.sql", StandardCharsets.UTF_8));
}
private void checkPlayer(H2Player player) throws SQLException {
if (player.getName() == null || player.getName().isEmpty()) {
throw new SQLException("Field 'name' is " + (player.getName() == null ? "null" : "empty"));
}
if (player.getUuid() == null) {
throw new SQLException("Field 'uuid' is null");
}
if (player.getLocation() == null) {
throw new SQLException("Fields 'location_*' is null");
}
if (player.getWorld() == null) {
throw new SQLException("Field 'location_world' is null");
}
}
private void insertWithoutId(H2Player player) throws SQLException {
KeyHolder keyHolder = new GeneratedKeyHolder();
int affectedRows = jdbcTemplate.update(psc -> {
PreparedStatement stmt = psc.prepareStatement(INSERT_SQL, Statement.RETURN_GENERATED_KEYS);
stmt.setString(1, player.getUuid().toString());
stmt.setString(2, player.getName());
stmt.setDouble(3, player.getLocation().getX());
stmt.setDouble(4, player.getLocation().getY());
stmt.setDouble(5, player.getLocation().getZ());
stmt.setFloat(6, player.getLocation().getYaw());
stmt.setFloat(7, player.getLocation().getPitch());
stmt.setString(8, player.getWorld().getName());
return stmt;
}, keyHolder);
if (affectedRows == 0) {
throw new SQLException("Serialize player failed: no rows affected.");
}
player.setId(keyHolder.getKey().intValue());
}
private void insertWithId(H2Player player) throws SQLException {
int affectedRows = jdbcTemplate.update(psc -> {
PreparedStatement stmt = psc.prepareStatement(INSERT2_SQL);
stmt.setString(1, player.getUuid().toString());
stmt.setString(2, player.getName());
stmt.setDouble(3, player.getLocation().getX());
stmt.setDouble(4, player.getLocation().getY());
stmt.setDouble(5, player.getLocation().getZ());
stmt.setFloat(6, player.getLocation().getYaw());
stmt.setFloat(7, player.getLocation().getPitch());
stmt.setString(8, player.getWorld().getName());
stmt.setInt(9, player.getId());
return stmt;
});
if (affectedRows == 0) {
throw new SQLException("Serialize player failed: no rows affected.");
}
}
public void insert(H2Player player) throws SQLException {
checkPlayer(player);
if (player.getId() > 0) {
insertWithId(player);
} else {
insertWithoutId(player);
}
}
private void locationDeserialize(H2Player playerBuffer, ResultSet resultSet) throws SQLException {
if (!world.getName().equals(resultSet.getString("location_world"))) {
log.warn("Unknown world \"{}\"", resultSet.getString("location_world"));
log.warn("Using default (spawn) location for user \"{}\"", playerBuffer.getName());
playerBuffer.setLocation(world.getSpawn().clone());
} else {
playerBuffer.setLocation(new EntityLocation(
resultSet.getDouble("location_x"),
resultSet.getDouble("location_y"),
resultSet.getDouble("location_z"),
resultSet.getFloat("location_yaw"),
resultSet.getFloat("location_pitch")
));
playerBuffer.setWorld(world);
}
}
public boolean getByName(H2Player playerBuffer) throws SQLException {
if (playerBuffer.getName() == null || playerBuffer.getName().isEmpty()) {
throw new SQLException("Field 'name' is " + (playerBuffer.getName() == null ? "null" : "empty"));
}
final boolean[] result = new boolean[]{false};
jdbcTemplate.query(SELECT_BYNAME_SQL,
ps -> ps.setString(1, playerBuffer.getName()),
rs -> {
playerBuffer.setId(rs.getInt("id"));
playerBuffer.setUuid(UUID.fromString(rs.getString("uuid")));
locationDeserialize(playerBuffer, rs);
result[0] = true;
});
return result[0];
}
public boolean getById(H2Player playerBuffer) throws SQLException {
if (playerBuffer.getId() == 0) {
throw new SQLException("Field 'id' is zero");
}
final boolean[] result = new boolean[]{false};
jdbcTemplate.query(SELECT_BYID_SQL,
ps -> ps.setInt(1, playerBuffer.getId()),
rs -> {
playerBuffer.setUuid(UUID.fromString(rs.getString("uuid")));
playerBuffer.setName(rs.getString("name"));
locationDeserialize(playerBuffer, rs);
result[0] = true;
});
return result[0];
}
public void update(H2Player player) throws SQLException {
if (player.getId() == 0) {
throw new SQLException("Field 'id' is zero");
}
checkPlayer(player);
int affectedRows = jdbcTemplate.update(UPDATE_SQL, pss -> {
pss.setInt(9, player.getId());
pss.setString(1, player.getUuid().toString());
pss.setString(2, player.getName());
pss.setDouble(3, player.getLocation().getX());
pss.setDouble(4, player.getLocation().getY());
pss.setDouble(5, player.getLocation().getZ());
pss.setFloat(6, player.getLocation().getYaw());
pss.setFloat(7, player.getLocation().getPitch());
pss.setString(8, player.getWorld().getName());
});
if (affectedRows == 0) {
throw new SQLException("Update player failed, no rows affected.");
}
}
public void updateLocation(H2Player player) throws SQLException {
if (player.getId() == 0) {
throw new SQLException("Field 'id' is zero");
}
if (player.getLocation() == null) {
throw new SQLException("Fields 'location_*' is null");
}
if (player.getWorld() == null) {
throw new SQLException("Field 'location_world' is null");
}
if (player.getLocation() == null) {
throw new SQLException("Fields 'location_*' is null");
}
if (player.getWorld() == null) {
throw new SQLException("Field 'location_world' is null");
}
int affectedRows = jdbcTemplate.update(connection -> {
PreparedStatement stmt = connection.prepareStatement(UPDATE_LOCATION_SQL);
stmt.setInt(7, player.getId());
stmt.setDouble(1, player.getLocation().getX());
stmt.setDouble(2, player.getLocation().getY());
stmt.setDouble(3, player.getLocation().getZ());
stmt.setFloat(4, player.getLocation().getYaw());
stmt.setFloat(5, player.getLocation().getPitch());
stmt.setString(6, player.getWorld().getName());
return stmt;
});
if (affectedRows == 0) {
throw new SQLException("Update player failed, no rows affected.");
}
}
public void remove(H2Player player) throws SQLException {
if (player.getId() == 0) {
throw new SQLException("Field 'id' is zero");
}
int affectedRows = jdbcTemplate.update(DELETE_SQL, pss -> pss.setInt(1, player.getId()));
if (affectedRows == 0) {
throw new SQLException("Remove player failed, no rows affected.");
}
player.setId(0);
}
static {
try {
INSERT_SQL = IOUtils.resourceToString("/sqls/insert_player.sql", StandardCharsets.UTF_8);
INSERT2_SQL = IOUtils.resourceToString("/sqls/insert_player_withId.sql", StandardCharsets.UTF_8);
SELECT_BYNAME_SQL = IOUtils.resourceToString("/sqls/select_player_byName.sql", StandardCharsets.UTF_8);
SELECT_BYID_SQL = IOUtils.resourceToString("/sqls/select_player_byId.sql", StandardCharsets.UTF_8);
UPDATE_SQL = IOUtils.resourceToString("/sqls/update_player.sql", StandardCharsets.UTF_8);
UPDATE_LOCATION_SQL = IOUtils.resourceToString("/sqls/update_player_location.sql", StandardCharsets.UTF_8);
DELETE_SQL = IOUtils.resourceToString("/sqls/delete_player.sql", StandardCharsets.UTF_8);
} catch (IOException e) {
log.error("Load sql templates", e);
}
}
}

View File

@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import mc.core.EntityLocation;
import mc.core.h2db.service.H2PlayerService;
import mc.core.network.BroadcastNetChannel;
import mc.core.network.NetChannel;
import mc.core.player.Player;
@@ -13,28 +14,23 @@ import mc.core.world.World;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import static org.slf4j.helpers.MessageFormatter.format;
@Slf4j
@Component
public class H2PlayerManager implements PlayerManager {
@Setter
@Autowired
private H2PlayerDAO h2playerDao;
private H2PlayerService h2PlayerService;
private List<H2Player> playerList = Collections.synchronizedList(new ArrayList<>());
@Autowired
private World world;
private World world; //FIXME
@Override
public Player createPlayer(String name, EntityLocation location, World world) {
//TODO в дальнейшем следует в этом методе только имплементацию Player
H2Player h2Player = new H2Player();
h2Player.setName(name);
h2Player.setUuid(UUID.randomUUID());
@@ -43,14 +39,7 @@ public class H2PlayerManager implements PlayerManager {
h2Player.setWorld(world);
h2Player.setSettings(new PlayerSettings());
try {
h2playerDao.insert(h2Player);
} catch (SQLException e) {
log.error(format("Insert player '{}'", h2Player.getName()).getMessage(), e);
return null;
}
return h2Player;
return h2PlayerService.save(h2Player);
}
@Override
@@ -64,15 +53,9 @@ public class H2PlayerManager implements PlayerManager {
@Override
public void leftServer(Player player) {
H2Player h2Player = (H2Player) player;
try {
h2playerDao.update(h2Player);
} catch (SQLException e) {
log.error(format("Update player '{}'", h2Player.getName()).getMessage(), e);
playerList.remove(h2Player);
} finally {
h2Player.setOnline(false);
h2Player.getLoadedChunks().clear();
}
h2PlayerService.save(h2Player);
h2Player.setOnline(false);
h2Player.getLoadedChunks().clear();
}
@Override
@@ -108,26 +91,17 @@ public class H2PlayerManager implements PlayerManager {
@Override
public Player getOfflinePlayer(String name) {
//TODO похоже в попытке где-то оптимизировать/сэконопить я сам себя ******[обманул]
//необходимо этот участок кода переписать
//потому как похоже на экономию на спичках
H2Player h2Player = playerList.stream()
.filter(player -> player.getName().equals(name))
.filter(player -> !player.isOnline())
.findFirst().orElse(null);
if (h2Player == null) {
h2Player = playerList.stream()
.filter(player -> !player.isOnline())
.findAny().orElse(new H2Player());
h2Player.setName(name);
boolean result;
try {
result = h2playerDao.getByName(h2Player);
} catch (SQLException e) {
log.error(format("getByName player '{}'", h2Player.getName()).getMessage(), e);
return null;
}
if (result) {
h2Player = h2PlayerService.getByName(name);
if (h2Player != null) {
h2Player.setWorld(world);
return h2Player;
} else {

View File

@@ -0,0 +1,104 @@
package mc.core.h2db.entity;
import lombok.Data;
import lombok.NoArgsConstructor;
import mc.core.EntityLocation;
import mc.core.h2db.H2Player;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.UUID;
@Entity
@Table(name = "players",
indexes = {@Index(name = "idx_players_uuid", columnList = "uuid", unique = true),
@Index(name = "idx_players_name", columnList = "name")})
@NoArgsConstructor
@Data
public class H2PlayerEntity {
@Id
@GeneratedValue(generator = "increment")
@GenericGenerator(name= "increment", strategy= "increment")
@Column(nullable = false)
private Long id;
@Column(length = 36, nullable = false)
private String uuid;
@Column(length = 16, nullable = false)
private String name;
@Column(name = "location_x", nullable = false)
private Double locationX;
@Column(name = "location_y", nullable = false)
private Double locationY;
@Column(name = "location_z", nullable = false)
private Double locationZ;
@Column(name = "location_yaw", nullable = false)
private Float locationYaw;
@Column(name = "location_pitch", nullable = false)
private Float locationPitch;
@Column(name = "location_world", length = 64, nullable = false)
private String locationWorld;
public H2PlayerEntity(H2Player player) {
this.id = (long) player.getId();
setUuid(player.getUuid().toString());
setName(this.name = player.getName());
this.locationX = player.getLocation().getX();
this.locationY = player.getLocation().getY();
this.locationZ = player.getLocation().getZ();
this.locationYaw = player.getLocation().getYaw();
this.locationPitch = player.getLocation().getPitch();
if (player.getWorld() != null) { //FIXME
this.locationWorld = player.getWorld().getName();
} else {
this.locationWorld = "null_world";
}
}
public void setUuid(String uuid) {
if (uuid == null || uuid.trim().isEmpty()) {
this.uuid = null;
} else {
this.uuid = uuid;
}
}
public void setName(String name) {
if (name == null || name.trim().isEmpty()) {
this.name = null;
} else {
this.name = name;
}
}
public H2Player toPlayer() {
H2Player player = new H2Player();
return toPlayer(player);
}
public H2Player toPlayer(H2Player player) {
player.setId(this.id.intValue());
player.setUuid(UUID.fromString(this.uuid));
player.setName(this.name);
if (player.getLocation() == null) {
player.setLocation(new EntityLocation(
this.locationX, this.locationY, this.locationZ,
this.locationYaw, this.locationPitch
));
} else {
player.getLocation().setXYZ(this.locationX, this.locationY, this.locationZ);
player.getLocation().setYawPitch(this.locationYaw, this.locationPitch);
}
player.setWorld(null); //FIXME
return player;
}
}

View File

@@ -0,0 +1,12 @@
package mc.core.h2db.repository;
import mc.core.h2db.entity.H2PlayerEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface H2PlayerEntityRepository extends JpaRepository<H2PlayerEntity, Long> {
Optional<H2PlayerEntity> findByName(String name);
}

View File

@@ -0,0 +1,11 @@
package mc.core.h2db.service;
import mc.core.h2db.H2Player;
public interface H2PlayerService {
H2Player save(H2Player player);
void remove(H2Player player);
H2Player getByName(String name);
H2Player getById(int id);
}

View File

@@ -0,0 +1,41 @@
package mc.core.h2db.service;
import mc.core.h2db.H2Player;
import mc.core.h2db.entity.H2PlayerEntity;
import mc.core.h2db.repository.H2PlayerEntityRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class H2PlayerServiceImpl implements H2PlayerService {
@Autowired
private H2PlayerEntityRepository h2PlayerEntityRepository;
@Override
public H2Player save(H2Player player) {
H2PlayerEntity entity = new H2PlayerEntity(player);
//TODO возможно имеет смысл здесь оптимизация
//вместо toPlayer() сделать toPlayer(H2Player) который в существующий
//будет дописывать/обновлять данные
return h2PlayerEntityRepository.saveAndFlush(entity).toPlayer(player);
}
@Override
public void remove(H2Player player) {
h2PlayerEntityRepository.deleteById((long) player.getId());
}
@Override
public H2Player getByName(String name) {
Optional<H2PlayerEntity> optEntity = h2PlayerEntityRepository.findByName(name);
return optEntity.map(H2PlayerEntity::toPlayer).orElse(null);
}
@Override
public H2Player getById(int id) {
Optional<H2PlayerEntity> optEntity = h2PlayerEntityRepository.findById((long) id);
return optEntity.map(H2PlayerEntity::toPlayer).orElse(null);
}
}

View File

@@ -1,14 +0,0 @@
CREATE TABLE IF NOT EXISTS players (
id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
uuid VARCHAR(36) NOT NULL UNIQUE,
name VARCHAR(16) NOT NULL,
location_x DOUBLE NOT NULL,
location_y DOUBLE NOT NULL,
location_z DOUBLE NOT NULL,
location_yaw FLOAT NOT NULL,
location_pitch FLOAT NOT NULL,
location_world VARCHAR(64) NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_players_uuid ON players(uuid);
CREATE INDEX IF NOT EXISTS idx_players_name ON players(name);

View File

@@ -1 +0,0 @@
DELETE FROM players WHERE id = ?;

View File

@@ -1,2 +0,0 @@
INSERT INTO players (uuid, name, location_x, location_y, location_z, location_yaw, location_pitch, location_world)
VALUES (?, ?, ?, ?, ?, ?, ?, ?);

View File

@@ -1,2 +0,0 @@
INSERT INTO players (uuid, name, location_x, location_y, location_z, location_yaw, location_pitch, location_world, id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);

View File

@@ -1,3 +0,0 @@
SELECT uuid, name, location_x, location_y, location_z, location_yaw, location_pitch, location_world
FROM players WHERE id = ?
LIMIT 1;

View File

@@ -1,3 +0,0 @@
SELECT id, uuid, location_x, location_y, location_z, location_yaw, location_pitch, location_world
FROM players WHERE name LIKE ?
LIMIT 1;

View File

@@ -1,10 +0,0 @@
UPDATE players
SET uuid = ?,
name = ?,
location_x = ?,
location_y = ?,
location_z = ?,
location_yaw = ?,
location_pitch = ?,
location_world = ?
WHERE id = ?;

View File

@@ -1,8 +0,0 @@
UPDATE players
SET location_x = ?,
location_y = ?,
location_z = ?,
location_yaw = ?,
location_pitch = ?,
location_world = ?
WHERE id = ?;

View File

@@ -1,49 +0,0 @@
package mc.core.h2db;
import mc.core.world.World;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@Configuration
@ComponentScan("mc.core.h2db")
public class SpringConfig {
@Bean
public World mockWorld() {
World mockWorld = mock(World.class);
when(mockWorld.getName()).thenReturn("mock_world");
return mockWorld;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dmds = new DriverManagerDataSource();
dmds.setDriverClassName("org.h2.Driver");
dmds.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
dmds.setUsername("sa");
return dmds;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean
@Scope(value = "prototype")
public H2PlayerManager h2PlayerManager(H2PlayerDAO h2PlayerDAO) {
H2PlayerManager playerManager = new H2PlayerManager();
playerManager.setH2playerDao(h2PlayerDAO);
return playerManager;
}
}

View File

@@ -1,274 +0,0 @@
package mc.core.h2db;
import mc.core.EntityLocation;
import mc.core.world.World;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class})
public class TestDAO {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private World mockWorld;
@Autowired
private H2PlayerDAO playerDAO;
private H2Player player;
private void createPlayer() {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final double minD = 0.0d, maxD = 10.0d;
final float minF = 0.0f, maxF = 359.9f;
final int minI = 1000, maxI = 9999;
player = new H2Player();
player.setUuid(UUID.randomUUID());
player.setName("player" + rnd.nextInt(minI, maxI));
player.setLocation(new EntityLocation(
rnd.nextDouble(minD, maxD),
rnd.nextDouble(minD, maxD),
rnd.nextDouble(minD, maxD),
rnd.nextFloat() * (maxF - minF) + minF,
rnd.nextFloat() * (maxF - minF) + minF
));
player.setWorld(mockWorld);
}
private void assertPlayer(H2Player actualPlayer) {
final String sql = "SELECT * FROM players WHERE id = ?";
jdbcTemplate.query(sql,
ps -> ps.setInt(1, player.getId()),
rs -> {
assertEquals(actualPlayer.getId(), rs.getInt("id"));
assertEquals(actualPlayer.getName(), rs.getString("name"));
assertEquals(actualPlayer.getLocation().getX(), rs.getDouble("location_x"), 0.01d);
assertEquals(actualPlayer.getLocation().getY(), rs.getDouble("location_y"), 0.01d);
assertEquals(actualPlayer.getLocation().getZ(), rs.getDouble("location_z"), 0.01d);
assertEquals(actualPlayer.getLocation().getYaw(), rs.getFloat("location_yaw"), 0.01f);
assertEquals(actualPlayer.getLocation().getPitch(), rs.getFloat("location_pitch"), 0.01f);
assertEquals(actualPlayer.getWorld().getName(), rs.getString("location_world"));
});
}
@Before
public void before() throws IOException {
jdbcTemplate.execute(IOUtils.resourceToString("/sqls/drop_table_players.sql", StandardCharsets.UTF_8));
jdbcTemplate.execute(IOUtils.resourceToString("/sqls/create_tables.sql", StandardCharsets.UTF_8));
createPlayer();
assertEquals(0, player.getId());
}
@Test
public void testInsert() throws SQLException {
playerDAO.insert(player);
assertNotEquals(0, player.getId());
assertPlayer(player);
}
@Test(expected = DuplicateKeyException.class)
public void testInsertDuplicateKey() throws SQLException {
playerDAO.insert(player);
playerDAO.insert(player);
}
@Test(expected = SQLException.class)
public void testInsertEmptyName() throws SQLException {
player.setName("");
playerDAO.insert(player);
}
@Test(expected = SQLException.class)
public void testInsertNullName() throws SQLException {
player.setName(null);
playerDAO.insert(player);
}
@Test(expected = SQLException.class)
public void testInsertNullUuid() throws SQLException {
player.setUuid(null);
playerDAO.insert(player);
}
@Test(expected = SQLException.class)
public void testInsertNullLocation() throws SQLException {
player.setLocation(null);
playerDAO.insert(player);
}
@Test(expected = SQLException.class)
public void testInsertNullWorld() throws SQLException {
player.setWorld(null);
playerDAO.insert(player);
}
@Test
public void testGetByName() throws SQLException {
playerDAO.insert(this.player);
H2Player queryPlayer = new H2Player();
queryPlayer.setName(player.getName());
boolean result = playerDAO.getByName(queryPlayer);
assertTrue(result);
assertEquals(player, queryPlayer);
}
@Test
public void testGetByNonExistsName() throws SQLException {
playerDAO.insert(this.player);
H2Player player = new H2Player();
player.setName("NON_EXISTS_NAME");
boolean result = playerDAO.getByName(player);
assertFalse(result);
}
@Test
public void testGetById() throws SQLException {
playerDAO.insert(this.player);
H2Player queryPlayer = new H2Player();
queryPlayer.setId(player.getId());
boolean result = playerDAO.getById(queryPlayer);
assertTrue(result);
assertEquals(player, queryPlayer);
}
@Test
public void testGetByNonExistsId() throws SQLException {
playerDAO.insert(player);
assertEquals(1, player.getId());
H2Player queryPlayer = new H2Player();
queryPlayer.setId(999);
boolean result = playerDAO.getById(queryPlayer);
assertFalse(result);
}
@Test
public void testUpdate() throws SQLException {
playerDAO.insert(player);
player.setName("UNKNOWN_PLAYER");
playerDAO.update(player);
assertPlayer(player);
}
@Test(expected = SQLException.class)
public void testUpdateEmptyName() throws SQLException {
playerDAO.insert(player);
player.setName("");
playerDAO.update(player);
}
@Test(expected = SQLException.class)
public void testUpdateNullName() throws SQLException {
playerDAO.insert(player);
player.setName(null);
playerDAO.update(player);
}
@Test(expected = SQLException.class)
public void testUpdateNullUuid() throws SQLException {
playerDAO.insert(player);
player.setUuid(null);
playerDAO.update(player);
}
@Test(expected = SQLException.class)
public void testUpdateNullLocation() throws SQLException {
playerDAO.insert(player);
player.setLocation(null);
playerDAO.update(player);
}
@Test(expected = SQLException.class)
public void testUpdateNullWorld() throws SQLException {
playerDAO.insert(player);
player.setWorld(null);
playerDAO.update(player);
}
@Test
public void testUpdateLocation() throws SQLException {
playerDAO.insert(player);
final String origName = player.getName();
player.setName("UNKNOWN_PLAYER");
player.getLocation().setX(33.1d);
player.getLocation().setZ(28.99d);
playerDAO.updateLocation(player);
final String sql = "SELECT * FROM players WHERE id = ?";
jdbcTemplate.query(sql,
ps -> ps.setInt(1, player.getId()),
rs -> {
assertEquals(player.getId(), rs.getInt("id"));
assertEquals(origName, rs.getString("name"));
assertEquals(player.getLocation().getX(), rs.getDouble("location_x"), 0.01d);
assertEquals(player.getLocation().getY(), rs.getDouble("location_y"), 0.01d);
assertEquals(player.getLocation().getZ(), rs.getDouble("location_z"), 0.01d);
assertEquals(player.getLocation().getYaw(), rs.getFloat("location_yaw"), 0.01f);
assertEquals(player.getLocation().getPitch(), rs.getFloat("location_pitch"), 0.01f);
assertEquals(player.getWorld().getName(), rs.getString("location_world"));
});
}
@Test(expected = SQLException.class)
public void testUpdateLocationNull() throws SQLException {
playerDAO.insert(player);
player.setLocation(null);
playerDAO.updateLocation(player);
}
@Test
public void testRemove() throws SQLException {
playerDAO.insert(player);
final int origId = player.getId();
playerDAO.remove(player);
assertEquals(0, player.getId());
final String sql = "SELECT COUNT(*) FROM players WHERE id = ?";
jdbcTemplate.query(sql,
ps -> ps.setInt(1, origId),
rs -> {assertEquals(0, rs.getInt(1));});
}
@Test(expected = SQLException.class)
public void testRemoveNonExistsId() throws SQLException {
playerDAO.insert(player);
player.setId(999);
playerDAO.remove(player);
}
}

View File

@@ -1,48 +1,33 @@
package mc.core.h2db;
import mc.core.EntityLocation;
import mc.core.h2db.service.H2PlayerService;
import mc.core.player.Player;
import mc.core.world.World;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.List;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class})
@ContextConfiguration(classes = {TestSpringConfig.class})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class TestH2PlayerManager {
@Autowired
private ApplicationContext context;
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private H2PlayerDAO h2PlayerDAO;
private H2PlayerService h2PlayerService;
@Autowired
private World mockWorld;
@Autowired
private H2PlayerManager playerManager;
@Before
public void before() throws IOException {
playerManager = context.getBean(H2PlayerManager.class);
jdbcTemplate.execute(IOUtils.resourceToString("/sqls/drop_table_players.sql", StandardCharsets.UTF_8));
jdbcTemplate.execute(IOUtils.resourceToString("/sqls/create_tables.sql", StandardCharsets.UTF_8));
}
@Test
public void testCreatePlayer() throws SQLException {
public void testCreatePlayer() {
final String playerName = "NEW_PLAYER";
final Player newPlayer = playerManager.createPlayer(playerName, EntityLocation.ZERO(), mockWorld);
@@ -50,9 +35,7 @@ public class TestH2PlayerManager {
assertEquals(H2Player.class, newPlayer.getClass());
assertTrue(newPlayer.getId() > 0);
final H2Player queryPlayer = new H2Player();
queryPlayer.setName(playerName);
h2PlayerDAO.getByName(queryPlayer);
final H2Player queryPlayer = h2PlayerService.getByName(playerName);
assertTrue(queryPlayer.getId() > 0);
assertEquals(newPlayer, queryPlayer);
@@ -74,7 +57,7 @@ public class TestH2PlayerManager {
}
@Test
public void testLeftServer() throws SQLException {
public void testLeftServer() {
assertEquals(0, playerManager.getCountPlayers());
final String playerName = "NEW_PLAYER";
@@ -96,11 +79,9 @@ public class TestH2PlayerManager {
assertFalse(player.isOnline());
assertTrue(player.getLoadedChunks().isEmpty());
H2Player queryPlayer = new H2Player();
queryPlayer.setId(playerId);
boolean result = h2PlayerDAO.getById(queryPlayer);
final H2Player queryPlayer = h2PlayerService.getById(playerId);
assertTrue(result);
assertNotNull(queryPlayer);
((H2Player)player).setId(playerId);
assertEquals(player, queryPlayer);
}

View File

@@ -0,0 +1,90 @@
package mc.core.h2db;
import mc.core.h2db.service.H2PlayerService;
import mc.core.world.World;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@Configuration
@EnableJpaRepositories
@EnableTransactionManagement
@ComponentScan("mc.core.h2db")
public class TestSpringConfig {
private static final String DATABASE_DRIVER = "org.h2.Driver";
private static final String DATABASE_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";
private static final String DATABASE_USERNAME = "sa";
private static final String DATABASE_PASSWORD = "s3cReT";
static {
System.setProperty("org.jboss.logging.provider", "slf4j");
}
private Properties hibernateProp() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.format_sql", "true");
properties.put("hibernate.use_sql_comments", "true");
properties.put("hibernate.hbm2ddl.auto", "create");
return properties;
}
@Bean
public World mockWorld() {
World mockWorld = mock(World.class);
when(mockWorld.getName()).thenReturn("mock_world");
return mockWorld;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dmds = new DriverManagerDataSource();
dmds.setDriverClassName(DATABASE_DRIVER);
dmds.setUrl(DATABASE_URL);
dmds.setUsername(DATABASE_USERNAME);
dmds.setPassword(DATABASE_PASSWORD);
return dmds;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
entityManagerFactoryBean.setPackagesToScan("mc.core.h2db.entity");
entityManagerFactoryBean.setJpaProperties(hibernateProp());
return entityManagerFactoryBean;
}
@Bean
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
@Bean
public H2PlayerManager h2PlayerManager(H2PlayerService h2PlayerService) {
H2PlayerManager playerManager = new H2PlayerManager();
playerManager.setH2PlayerService(h2PlayerService);
return playerManager;
}
}

View File

@@ -0,0 +1,133 @@
package mc.core.h2db.service;
import mc.core.EntityLocation;
import mc.core.h2db.H2Player;
import mc.core.h2db.TestSpringConfig;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestSpringConfig.class})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class H2PlayerServiceTest {
@Autowired
private H2PlayerService h2PlayerService;
private H2Player buildPlayer() {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final double minD = 0.0d, maxD = 10.0d;
final float minF = 0.0f, maxF = 359.9f;
final int minI = 1000, maxI = 9999;
final H2Player player = new H2Player();
player.setUuid(UUID.randomUUID());
player.setName("player" + rnd.nextInt(minI, maxI));
player.setLocation(new EntityLocation(
rnd.nextDouble(minD, maxD),
rnd.nextDouble(minD, maxD),
rnd.nextDouble(minD, maxD),
rnd.nextFloat() * (maxF - minF) + minF,
rnd.nextFloat() * (maxF - minF) + minF
));
player.setWorld(null); //FIXME
return player;
}
@Test
public void save() {
H2Player player = buildPlayer();
H2Player savedPlayer = h2PlayerService.save(player);
player.setId(savedPlayer.getId()); //FIXME костыль, однако
Assert.assertEquals(player, savedPlayer);
}
@Test(expected = Exception.class)
public void save_NameEmpty() {
H2Player player = buildPlayer();
player.setName("");
h2PlayerService.save(player);
}
@Test(expected = Exception.class)
public void save_NameNull() {
H2Player player = buildPlayer();
player.setName(null);
h2PlayerService.save(player);
}
@Test(expected = Exception.class)
public void save_UuidNull() {
H2Player player = buildPlayer();
player.setUuid(null);
h2PlayerService.save(player);
}
@Test(expected = Exception.class)
public void save_LocationNull() {
H2Player player = buildPlayer();
player.setLocation(null);
h2PlayerService.save(player);
}
@Test
public void remove() {
H2Player player = h2PlayerService.save(buildPlayer());
h2PlayerService.remove(player);
H2Player player2 = h2PlayerService.getById(player.getId());
Assert.assertNull(player2);
}
@Test(expected = Exception.class)
public void remove_NotExists() {
H2Player player = h2PlayerService.save(buildPlayer());
h2PlayerService.remove(player);
h2PlayerService.remove(player);
}
@Test
public void getByName() {
H2Player player = h2PlayerService.save(buildPlayer());
H2Player player2 = h2PlayerService.getByName(player.getName());
Assert.assertEquals(player, player2);
}
@Test
public void getByName_NotExists() {
Assert.assertNull(h2PlayerService.getByName("UNKNOW_PLAYER"));
}
@Test
public void getByName_Empty() {
Assert.assertNull(h2PlayerService.getByName(""));
}
@Test
public void getByName_Null() {
Assert.assertNull(h2PlayerService.getByName(null));
}
@Test
public void getById() {
H2Player player = h2PlayerService.save(buildPlayer());
H2Player player2 = h2PlayerService.getById(player.getId());
Assert.assertEquals(player, player2);
}
@Test
public void getById_NotExists() {
Assert.assertNull(h2PlayerService.getById(9999));
}
}

View File

@@ -1,3 +0,0 @@
DROP INDEX IF EXISTS idx_players_uuid;
DROP INDEX IF EXISTS idx_players_name;
DROP TABLE IF EXISTS players;