Compare commits
3 commits
friday_04-
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| c58c8725e8 | |||
|
|
b3bdec1049 | ||
|
|
e1301f007b |
19 changed files with 133 additions and 24 deletions
31
README.md
Normal file
31
README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# JWS
|
||||||
|
|
||||||
|
> **Note** This is a school project, therefore it probably won't interest you if you are looking for something useful.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
JWS stands for Java Web Services and as its name doesn't suggest at all, it's basically a web server for a a pokemon-like game. It's written in Java and built onto Quarkus and Jakarta, providing a REST API with strict server-side rules like cooldowns and cheating prevention.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
> **Note** Source code is located inside the `yakamon` folder, both others are school requirements and aren't important
|
||||||
|
|
||||||
|
Each layer is strictly separated and can only communicate via to the one directly below or above it via converters.
|
||||||
|
|
||||||
|
### Presentation Layer (REST & DTOs)
|
||||||
|
* located at `yakamon/jws/yakamon/src/main/java/fr/epita/assistants/yakamon/presentation`
|
||||||
|
* Handled by JAX-RS (Jakarta RESTful Web Services).
|
||||||
|
* Exposes standard HTTP endpoints (`/player`, `/move`, `/yakadex`, etc.). Full API specification can be found inside `yakamon/src/main/resources/openapi.yaml`
|
||||||
|
* Implements strict **Data Transfer Objects (DTOs)** for both Requests and Responses to ensure the internal database models are never exposed directly to the client.
|
||||||
|
|
||||||
|
### Business Logic Layer (Services)
|
||||||
|
* located at `yakamon/jws/yakamon/src/main/java/fr/epita/assistants/yakamon/domain`
|
||||||
|
* Acts as the brain of the application.
|
||||||
|
* Implements complex game rules: validating if a target tile is walkable based on the terrain type, calculating cooldowns between moves, and managing creature capture probabilities.
|
||||||
|
* **Converters** are used to translate Entities from the Data Layer into DTOs for the Presentation Layer.
|
||||||
|
|
||||||
|
### Data Access Layer (Hibernate ORM)
|
||||||
|
* located at `yakamon/jws/yakamon/src/main/java/fr/epita/assistants/yakamon/data`
|
||||||
|
* Manages persistence using **Hibernate ORM** with the Active Record / Repository pattern.
|
||||||
|
* Defines relational entities (Player, Game, Yakamon, Item) mapped to a PostgreSQL database.
|
||||||
|
|
||||||
|
|
@ -9,10 +9,34 @@ public class ItemModel {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
protected Integer id;
|
private Integer id;
|
||||||
|
|
||||||
@Enumerated
|
@Enumerated
|
||||||
public ItemType type;
|
private ItemType type;
|
||||||
|
|
||||||
public Integer quantity;
|
private Integer quantity;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(ItemType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getQuantity() {
|
||||||
|
return quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuantity(Integer quantity) {
|
||||||
|
this.quantity = quantity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,8 @@ public class GameService {
|
||||||
|
|
||||||
// Initialize player inventory
|
// Initialize player inventory
|
||||||
ItemModel yakaballs = new ItemModel();
|
ItemModel yakaballs = new ItemModel();
|
||||||
yakaballs.type = ItemType.YAKABALL;
|
yakaballs.setType(ItemType.YAKABALL);
|
||||||
yakaballs.quantity = 5;
|
yakaballs.setQuantity(5);
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
playerRepository.persist(player);
|
playerRepository.persist(player);
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ public class PlayerService {
|
||||||
ItemModel yakaballItem = itemRepository
|
ItemModel yakaballItem = itemRepository
|
||||||
.find("type", ItemType.YAKABALL)
|
.find("type", ItemType.YAKABALL)
|
||||||
.firstResult();
|
.firstResult();
|
||||||
if (yakaballItem == null || yakaballItem.quantity < 1) {
|
if (yakaballItem == null || yakaballItem.getQuantity() < 1) {
|
||||||
throw new WebApplicationException(
|
throw new WebApplicationException(
|
||||||
Response.status(400).entity("Not enough Yakaballs").build()
|
Response.status(400).entity("Not enough Yakaballs").build()
|
||||||
);
|
);
|
||||||
|
|
@ -170,7 +170,7 @@ public class PlayerService {
|
||||||
ErrorCode.BAD_REQUEST.throwException("Yakamon species not found");
|
ErrorCode.BAD_REQUEST.throwException("Yakamon species not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
yakaballItem.quantity -= 1;
|
yakaballItem.setQuantity(yakaballItem.getQuantity() - 1);
|
||||||
itemRepository.persist(yakaballItem);
|
itemRepository.persist(yakaballItem);
|
||||||
|
|
||||||
YakamonModel newYakamon = new YakamonModel();
|
YakamonModel newYakamon = new YakamonModel();
|
||||||
|
|
@ -342,11 +342,11 @@ public class PlayerService {
|
||||||
.firstResult();
|
.firstResult();
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
item = new ItemModel();
|
item = new ItemModel();
|
||||||
item.type = itemType;
|
item.setType(itemType);
|
||||||
item.quantity = 1;
|
item.setQuantity(1);
|
||||||
itemRepository.persist(item);
|
itemRepository.persist(item);
|
||||||
} else {
|
} else {
|
||||||
item.quantity += 1;
|
item.setQuantity(item.getQuantity() + 1);
|
||||||
itemRepository.persist(item);
|
itemRepository.persist(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package fr.epita.assistants.yakamon.presentation.api;
|
package fr.epita.assistants.yakamon.presentation.api;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class YakamonAction {
|
public class YakamonAction {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package fr.epita.assistants.yakamon.presentation.api.request;
|
package fr.epita.assistants.yakamon.presentation.api.request;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class StartGameRequest {
|
public class StartGameRequest {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package fr.epita.assistants.yakamon.presentation.api.request;
|
package fr.epita.assistants.yakamon.presentation.api.request;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class TeamFeedRequest {
|
public class TeamFeedRequest {
|
||||||
|
|
||||||
public Integer quantity;
|
public Integer quantity;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package fr.epita.assistants.yakamon.presentation.api.request;
|
package fr.epita.assistants.yakamon.presentation.api.request;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class TeamRenameRequest {
|
public class TeamRenameRequest {
|
||||||
|
|
||||||
public String newNickname;
|
public String newNickname;
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,37 @@ package fr.epita.assistants.yakamon.presentation.api.response;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class GetInventoryResponse {
|
public class GetInventoryResponse {
|
||||||
|
|
||||||
public class ItemType {
|
public class ItemType {
|
||||||
|
|
||||||
public String type;
|
public String type;
|
||||||
public String value;
|
public String value;
|
||||||
|
|
||||||
|
public ItemType() {}
|
||||||
|
|
||||||
|
public ItemType(String type, String value) {
|
||||||
|
this.type = type;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Items {
|
public class Items {
|
||||||
|
|
||||||
public ItemType itemType;
|
public ItemType itemType;
|
||||||
public Integer quantity;
|
public Integer quantity;
|
||||||
|
|
||||||
|
public Items() {}
|
||||||
|
|
||||||
|
public Items(ItemType itemType, Integer quantity) {
|
||||||
|
this.itemType = itemType;
|
||||||
|
this.quantity = quantity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Items> items;
|
public List<Items> items;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package fr.epita.assistants.yakamon.presentation.api.response;
|
package fr.epita.assistants.yakamon.presentation.api.response;
|
||||||
|
|
||||||
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
|
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
public class PlayerCatchResponse extends YakamonAction {
|
public class PlayerCatchResponse extends YakamonAction {
|
||||||
|
|
||||||
public PlayerCatchResponse(
|
public PlayerCatchResponse(
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,36 @@ package fr.epita.assistants.yakamon.presentation.api.response;
|
||||||
import fr.epita.assistants.yakamon.utils.tile.ItemType;
|
import fr.epita.assistants.yakamon.utils.tile.ItemType;
|
||||||
import fr.epita.assistants.yakamon.utils.tile.TerrainType;
|
import fr.epita.assistants.yakamon.utils.tile.TerrainType;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class PlayerCollectResponse {
|
public class PlayerCollectResponse {
|
||||||
|
|
||||||
public class TileType {
|
public class TileType {
|
||||||
|
|
||||||
public class Collectible {
|
public class Collectible {
|
||||||
|
|
||||||
ItemType type;
|
public ItemType type;
|
||||||
String value;
|
public String value;
|
||||||
|
|
||||||
|
public Collectible() {}
|
||||||
|
|
||||||
|
public Collectible(ItemType type, String value) {
|
||||||
|
this.type = type;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TerrainType terrainType;
|
public TerrainType terrainType;
|
||||||
Collectible collectible;
|
public Collectible collectible;
|
||||||
|
|
||||||
|
public TileType() {}
|
||||||
|
|
||||||
|
public TileType(TerrainType terrainType, Collectible collectible) {
|
||||||
|
this.terrainType = terrainType;
|
||||||
|
this.collectible = collectible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TileType tileType;
|
public TileType tileType;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package fr.epita.assistants.yakamon.presentation.api.response;
|
package fr.epita.assistants.yakamon.presentation.api.response;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class PlayerInfosResponse {
|
public class PlayerInfosResponse {
|
||||||
|
|
||||||
|
|
@ -10,7 +12,7 @@ public class PlayerInfosResponse {
|
||||||
public Integer posX;
|
public Integer posX;
|
||||||
public Integer posY;
|
public Integer posY;
|
||||||
public String lastMove;
|
public String lastMove;
|
||||||
public String lastCatch;
|
|
||||||
public String lastCollect;
|
public String lastCollect;
|
||||||
|
public String lastCatch;
|
||||||
public String lastFeed;
|
public String lastFeed;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package fr.epita.assistants.yakamon.presentation.api.response;
|
package fr.epita.assistants.yakamon.presentation.api.response;
|
||||||
|
|
||||||
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
|
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
public class TeamEvolveResponse extends YakamonAction {
|
public class TeamEvolveResponse extends YakamonAction {
|
||||||
|
|
||||||
public TeamEvolveResponse(
|
public TeamEvolveResponse(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package fr.epita.assistants.yakamon.presentation.api.response;
|
package fr.epita.assistants.yakamon.presentation.api.response;
|
||||||
|
|
||||||
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
|
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
public class TeamFeedResponse extends YakamonAction {
|
public class TeamFeedResponse extends YakamonAction {
|
||||||
|
|
||||||
public TeamFeedResponse(
|
public TeamFeedResponse(
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@ package fr.epita.assistants.yakamon.presentation.api.response;
|
||||||
|
|
||||||
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
|
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class TeamInfosResponse {
|
public class TeamInfosResponse {
|
||||||
|
|
||||||
YakamonAction[] yakamons;
|
public YakamonAction[] yakamons;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package fr.epita.assistants.yakamon.presentation.api.response;
|
package fr.epita.assistants.yakamon.presentation.api.response;
|
||||||
|
|
||||||
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
|
import fr.epita.assistants.yakamon.presentation.api.YakamonAction;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
public class TeamRenameResponse extends YakamonAction {
|
public class TeamRenameResponse extends YakamonAction {
|
||||||
|
|
||||||
public TeamRenameResponse(
|
public TeamRenameResponse(
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@ package fr.epita.assistants.yakamon.presentation.api.response;
|
||||||
|
|
||||||
import fr.epita.assistants.yakamon.presentation.api.YakadexEntry;
|
import fr.epita.assistants.yakamon.presentation.api.YakadexEntry;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class YakadexAllInfosResponse {
|
public class YakadexAllInfosResponse {
|
||||||
|
|
||||||
YakadexEntry[] entries;
|
public YakadexEntry[] entries;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,10 @@ public class InventoryResource {
|
||||||
for (ItemModel item : items) {
|
for (ItemModel item : items) {
|
||||||
GetInventoryResponse.Items responseItem = temp.new Items();
|
GetInventoryResponse.Items responseItem = temp.new Items();
|
||||||
GetInventoryResponse.ItemType itemType = temp.new ItemType();
|
GetInventoryResponse.ItemType itemType = temp.new ItemType();
|
||||||
itemType.type = item.type.name();
|
itemType.type = item.getType().name();
|
||||||
itemType.value = item.type.name();
|
itemType.value = item.getType().name();
|
||||||
responseItem.itemType = itemType;
|
responseItem.itemType = itemType;
|
||||||
responseItem.quantity = item.quantity;
|
responseItem.quantity = item.getQuantity();
|
||||||
responseItems.add(responseItem);
|
responseItems.add(responseItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -123,12 +123,12 @@ public class PlayerResource {
|
||||||
player.lastMove != null
|
player.lastMove != null
|
||||||
? player.lastMove.format(formatter)
|
? player.lastMove.format(formatter)
|
||||||
: null,
|
: null,
|
||||||
player.lastCatch != null
|
|
||||||
? player.lastCatch.format(formatter)
|
|
||||||
: null,
|
|
||||||
player.lastCollect != null
|
player.lastCollect != null
|
||||||
? player.lastCollect.format(formatter)
|
? player.lastCollect.format(formatter)
|
||||||
: null,
|
: null,
|
||||||
|
player.lastCatch != null
|
||||||
|
? player.lastCatch.format(formatter)
|
||||||
|
: null,
|
||||||
player.lastFeed != null
|
player.lastFeed != null
|
||||||
? player.lastFeed.format(formatter)
|
? player.lastFeed.format(formatter)
|
||||||
: null
|
: null
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue