diff --git a/design/open-api.yaml b/design/open-api.yaml index 36c39d39133fb954e3ad6f9934a409b68ace2179..c07a91a2e7b522b99778b1f3e63d9ac730d5b1f3 100644 --- a/design/open-api.yaml +++ b/design/open-api.yaml @@ -2,32 +2,43 @@ openapi: "3.0.3" externalDocs: url: https://gitlab.utwente.nl/claudenirmf/mod4-wp-2023-2024-pokemon info: - title: Pokémon Trainer Database API + title: PokeApp API version: "1.0" license: name: Creative Commons Attribution 4.0 International (CC-BY-4.0) url: https://creativecommons.org/licenses/by/4.0/deed.en - description: The [Pokémon Trainer Database API](https://gitlab.utwente.nl/claudenirmf/mod4-wp-2023-2024-pokemon) is a REST API part of a sample web application designed to teach web development concepts at the [Data & Information module](https://www.utwente.nl/en/education/bachelor/programmes/technical-computer-science/study-programme/#modules-technical-computer-science) of the [Technical Computer Science](https://www.utwente.nl/en/education/bachelor/programmes/technical-computer-science/) program of the [University of Twente](https://utwente.nl/en). + description: The [PokeApp API](https://gitlab.utwente.nl/claudenirmf/mod4-wp-2023-2024-pokemon) is a REST API part of a sample web application designed to teach web development concepts at the [Data & Information module](https://www.utwente.nl/en/education/bachelor/programmes/technical-computer-science/study-programme/#modules-technical-computer-science) of the [Technical Computer Science](https://www.utwente.nl/en/education/bachelor/programmes/technical-computer-science/) program of the [University of Twente](https://utwente.nl/en). contact: name: Claudenir M. Fonseca url: https://gitlab.utwente.nl/claudenirmf/mod4-wp-2023-2024-pokemon/issues email: c.moraisfonseca@utwente.nl servers: - description: Local Deployment - url: http://localhost:8080/pokemon_war_exploded + url: http://localhost:8080/pokemon/api tags: - name: Trainer description: Routes for managing data about trainers. - name: Pokémon description: Routes for managing data about pokémon. - - name: Pokémon Type - description: Routes for managing data about pokémon types. +# - name: Pokémon Type +# description: Routes for managing data about pokémon types. paths: /trainers: get: description: Retrieves a collection of resources. tags: - Trainer + parameters: + - name: pageNumber + description: Returns the desired page. + in: query + schema: + type: number + - name: pageSize + description: Returns the desired number of resources. + in: query + schema: + type: number responses: 200: description: OK @@ -114,102 +125,122 @@ paths: 405: description: Server error - /pokemon: +# /pokemon: +# get: +# description: Retrieves a collection of resources. +# tags: +# - Pokémon +# responses: +# 200: +# description: OK +# post: +# description: Creates a resource on the route's collection. +# tags: +# - Pokémon +# requestBody: +# content: +# 'application/json': +# schema: +# type: object +# responses: +# 200: +# description: OK +# 400: +# description: Bad request +# 405: +# description: Server error +# /pokemon/{id}: +# get: +# description: Retrieves a resource with matching a {id}. +# tags: +# - Pokémon +# parameters: +# - name: id +# description: The {id} of the desired resource. +# in: path +# schema: +# type: string +# minLength: 1 +# required: true +# responses: +# 200: +# description: OK +# 404: +# description: Not found +# put: +# description: Replaces the resource {id} with the provided one. +# tags: +# - Pokémon +# parameters: +# - name: id +# description: The {id} of the desired resource. +# in: path +# schema: +# type: string +# minLength: 1 +# required: true +# +# requestBody: +# content: +# 'application/json': +# schema: +# type: object +# responses: +# 200: +# description: OK +# 400: +# description: Bad request +# 404: +# description: Not found +# 405: +# description: Server error +# delete: +# description: Deletes the resource identified as {id}. +# tags: +# - Pokémon +# parameters: +# - name: id +# description: The {id} of the desired resource. +# in: path +# schema: +# type: string +# minLength: 1 +# required: true +# responses: +# 204: +# description: No content +# 400: +# description: Bad request +# 404: +# description: Not found +# 405: +# description: Server error + + /pokemonTypes: get: description: Retrieves a collection of resources. tags: - - Pokémon - responses: - 200: - description: OK - post: - description: Creates a resource on the route's collection. - tags: - - Pokémon - requestBody: - content: - 'application/json': - schema: - type: object - responses: - 200: - description: OK - 400: - description: Bad request - 405: - description: Server error - /pokemon/{id}: - get: - description: Retrieves a resource with matching a {id}. - tags: - - Pokémon + - Pokémon Type parameters: - - name: id - description: The {id} of the desired resource. - in: path + - name: pageNumber + description: Returns the desired page. + in: query schema: - type: string - minLength: 1 - required: true - responses: - 200: - description: OK - 404: - description: Not found - put: - description: Replaces the resource {id} with the provided one. - tags: - - Pokémon - parameters: - - name: id - description: The {id} of the desired resource. - in: path + type: number + - name: pageSize + description: Returns the desired number of resources. + in: query schema: - type: string - minLength: 1 - required: true - - requestBody: - content: - 'application/json': - schema: - type: object - responses: - 200: - description: OK - 400: - description: Bad request - 404: - description: Not found - 405: - description: Server error - delete: - description: Deletes the resource identified as {id}. - tags: - - Pokémon - parameters: - - name: id - description: The {id} of the desired resource. - in: path + type: number + - name: sortBy + description: Returns resources sorted according the desired attribute. + in: query schema: type: string - minLength: 1 - required: true - responses: - 204: - description: No content - 400: - description: Bad request - 404: - description: Not found - 405: - description: Server error - - /pokemonTypes: - get: - description: Retrieves a collection of resources. - tags: - - Pokémon Type + enum: + - id + - pokedexNumber + - lastUpDate responses: 200: description: OK @@ -305,95 +336,65 @@ components: id: type: string minLength: 1 - type: + created: type: string - enum: - - trainer - meta: - type: object - properties: - creation: - type: string - format: date-time - lastUpdate: - type: string - format: date-time - data: - type: object - properties: - name: - type: string - minLength: 1 - profileUrl: - type: string - format: uri - pokemon: - type: array - items: - type: string - minLength: 1 - party: - type: array - items: - type: string - minLength: 1 - links: - additionalProperties: - type: array - items: - type: string - format: uri - Pokemon: - description: Schema describing the overall shape of pokemon resources. - type: object - properties: - id: + format: date-time + lastUpdate: + type: string + format: date-time + name: type: string minLength: 1 - type: + profileUrl: type: string - enum: - - pokemon - meta: - type: object - properties: - creation: - type: string - format: date-time - lastUpdate: - type: string - format: date-time - data: - type: object - properties: - name: - type: string - minLength: 1 - height: - type: number - weight: - type: number - hp: - type: number - attack: - type: number - spAttack: - type: number - defense: - type: number - spDefense: - type: number - speed: - type: number - pokemonType: - type: string - minLength: 1 - links: - additionalProperties: - type: array - items: - type: string - format: uri + format: uri + pokemon: + type: array + items: + type: string + minLength: 1 + party: + type: array + items: + type: string + minLength: 1 + +# Pokemon: +# description: Schema describing the overall shape of pokemon resources. +# type: object +# properties: +# id: +# type: string +# minLength: 1 +# created: +# type: string +# format: date-time +# lastUpdate: +# type: string +# format: date-time +# name: +# type: string +# minLength: 1 +# height: +# type: number +# weight: +# type: number +# hp: +# type: number +# attack: +# type: number +# spAttack: +# type: number +# defense: +# type: number +# spDefense: +# type: number +# speed: +# type: number +# pokemonType: +# type: string +# minLength: 1 + PokemonType: description: Schema describing the overall shape of pokemon type resources. type: object @@ -401,96 +402,101 @@ components: id: type: string minLength: 1 - type: + created: + type: string + format: date-time + lastUpdate: + type: string + format: date-time + name: + type: string + minLength: 1 + pokedexNumber: + type: number + minimum: 0 + generation: + type: number + minimum: 0 + japaneseName: + type: string + classification: + type: string + abilities: + type: array + items: + type: string + minLength: 1 + baseHeight: + type: number + minimum: 0 + baseWeight: + type: number + minimum: 0 + baseHp: + type: number + minimum: 0 + baseAttack: + type: number + minimum: 0 + baseSpAttack: + type: number + minimum: 0 + baseDefense: + type: number + minimum: 0 + baseSpDefense: + type: number + minimum: 0 + baseSpeed: + type: number + minimum: 0 + captureRate: + type: number + minimum: 0 + isLegendary: + type: boolean + imgUrl: + type: string + format: uri + primaryType: + type: string + enum: + - bug + - dark + - dragon + - electric + - fairy + - fighting + - fire + - flying + - ghost + - grass + - ground + - ice + - normal + - poison + - psychic + - rock + - steel + - water + secondaryType: type: string enum: - - pokemonType - meta: - type: object - properties: - creation: - type: string - format: date-time - lastUpdate: - type: string - format: date-time - data: - type: object - properties: - name: - type: string - minLength: 1 - pokedexNumber: - type: number - minimum: 0 - generation: - type: number - minimum: 0 - japaneseName: - type: string - classification: - type: string - abilities: - type: array - items: - type: string - minLength: 1 - baseHeight: - type: number - minimum: 0 - baseWeight: - type: number - minimum: 0 - baseHp: - type: number - minimum: 0 - baseAttack: - type: number - minimum: 0 - baseSpAttack: - type: number - minimum: 0 - baseDefense: - type: number - minimum: 0 - baseSpDefense: - type: number - minimum: 0 - baseSpeed: - type: number - minimum: 0 - captureRate: - type: number - minimum: 0 - isLegendary: - type: boolean - imgUrl: - type: string - format: uri - primaryType: - type: string - enum: - - BUG - - DARK - - DRAGON - - ELECTRIC - - FAIRY - - FIGHTING - - FIRE - - FLYING - - GHOST - - GRASS - - GROUND - - ICE - - NORMAL - - POISON - - PSYCHIC - - ROCK - - STEEL - - WATER - links: - additionalProperties: - type: array - items: - type: string - format: uri + - bug + - dark + - dragon + - electric + - fairy + - fighting + - fire + - flying + - ghost + - grass + - ground + - ice + - normal + - poison + - psychic + - rock + - steel + - water diff --git a/src/main/java/nl/utwente/mod4/pokemon/Listenner.java b/src/main/java/nl/utwente/mod4/pokemon/Listenner.java index 2581a77196345e1a13b31a4f5b9051250638b5dc..a2de4bbc08ee12c2ca95ef2802f3a7265150d4b6 100644 --- a/src/main/java/nl/utwente/mod4/pokemon/Listenner.java +++ b/src/main/java/nl/utwente/mod4/pokemon/Listenner.java @@ -4,6 +4,7 @@ import jakarta.servlet.ServletContextEvent; import jakarta.servlet.ServletContextListener; import jakarta.servlet.annotation.WebListener; import nl.utwente.mod4.pokemon.dao.PokemonTypeDao; +import nl.utwente.mod4.pokemon.dao.TrainerDao; import java.io.IOException; @@ -14,6 +15,7 @@ public class Listenner implements ServletContextListener { System.out.println("Initializing PokeApp..."); try { PokemonTypeDao.INSTANCE.load(); + TrainerDao.INSTANCE.load(); } catch (IOException e) { System.err.println("Error while loading data."); e.printStackTrace(); @@ -26,6 +28,7 @@ public class Listenner implements ServletContextListener { System.out.println("Shutting down PokeApp..."); try { PokemonTypeDao.INSTANCE.save(); + TrainerDao.INSTANCE.save(); } catch (IOException e) { System.err.println("Error while saving data."); e.printStackTrace(); diff --git a/src/main/java/nl/utwente/mod4/pokemon/Utils.java b/src/main/java/nl/utwente/mod4/pokemon/Utils.java index 1d2dce1e568186606c796b8af6f264dec966efd5..01bc8da9bc03d5faeb6250e9d935ef16eb2dec38 100644 --- a/src/main/java/nl/utwente/mod4/pokemon/Utils.java +++ b/src/main/java/nl/utwente/mod4/pokemon/Utils.java @@ -1,10 +1,29 @@ package nl.utwente.mod4.pokemon; import java.nio.file.Path; +import java.util.List; public class Utils { public static String getAbsolutePathToResources() { return Utils.class.getClassLoader().getResource("").getPath(); } + + public static <T extends Comparable<T>> int compare(T o1, T o2) { + if (o1 == null && o2 == null) + return 0; + if (o1 == null) + return -1; + if (o2 == null) + return 1; + return o1.compareTo(o2); + } + + public static List<?> pageSlice(List<?> list, int pageSize, int pageNumber) { + int total = list.size(); + int firstIndex = (pageNumber - 1) * pageSize; + int lastIndex = Math.min(pageNumber * pageSize, total); + return list.subList(firstIndex,lastIndex); + } + } diff --git a/src/main/java/nl/utwente/mod4/pokemon/dao/PokemonTypeDao.java b/src/main/java/nl/utwente/mod4/pokemon/dao/PokemonTypeDao.java index 119568f3a2401dc07400011221332649ccb7931b..a5d37fa878d513513b7a6461da5418366a6139d7 100644 --- a/src/main/java/nl/utwente/mod4/pokemon/dao/PokemonTypeDao.java +++ b/src/main/java/nl/utwente/mod4/pokemon/dao/PokemonTypeDao.java @@ -5,8 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.NotFoundException; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.NotSupportedException; import nl.utwente.mod4.pokemon.Utils; import nl.utwente.mod4.pokemon.model.PokemonType; @@ -32,8 +31,19 @@ public enum PokemonTypeDao { } } - public List<PokemonType> getPokemonTypes() { - return new ArrayList<>(pokemonTypes.values()); + public List<PokemonType> getPokemonTypes(int pageSize, int pageNumber, String sortBy) { + List<PokemonType> list = new ArrayList<>(pokemonTypes.values()); + + if (sortBy == null || sortBy.isEmpty() || "id".equals(sortBy)) + list.sort((pt1, pt2) -> Utils.compare(Integer.parseInt(pt1.id), Integer.parseInt(pt2.id))); + else if ("pokedexNumber".equals(sortBy)) + list.sort((pt1, pt2) -> Utils.compare(pt1.pokedexNumber, pt2.pokedexNumber)); + else if ("lastUpDate".equals(sortBy)) + list.sort((pt1, pt2) -> Utils.compare(pt1.lastUpDate, pt2.lastUpDate)); + else + throw new NotSupportedException("Sort field not supported"); + + return (List<PokemonType>) Utils.pageSlice(list,pageSize,pageNumber); } public PokemonType getPokemonType(String id) { @@ -56,6 +66,11 @@ public enum PokemonTypeDao { Arrays.stream(arr).forEach(pt -> pokemonTypes.put(pt.id, pt)); } + private boolean existsPokemonTypes() { + File f = new File(POKEMON_TYPES); + return f.exists() && !f.isDirectory(); + } + public void save() throws IOException { ObjectMapper mapper = new ObjectMapper(); ObjectWriter writer = mapper.writer(new DefaultPrettyPrinter()); @@ -64,20 +79,6 @@ public enum PokemonTypeDao { writer.writeValue(destination, pokemonTypes.values()); } - private boolean existsPokemonTypes() { - File f = new File(POKEMON_TYPES); - return f.exists() && !f.isDirectory(); - } - - private int getMaxId() { - Set<String> ids = pokemonTypes.keySet(); - return ids.isEmpty() ? 0 : ids.stream() - .map(Integer::parseInt) - .max(Integer::compareTo) - .get(); - } - - public PokemonType create(PokemonType newPokemonType) { String nextId = "" + (getMaxId() + 1); @@ -89,6 +90,14 @@ public enum PokemonTypeDao { return newPokemonType; } + private int getMaxId() { + Set<String> ids = pokemonTypes.keySet(); + return ids.isEmpty() ? 0 : ids.stream() + .map(Integer::parseInt) + .max(Integer::compareTo) + .get(); + } + public PokemonType update(PokemonType updated) { if(!updated.isValid()) throw new BadRequestException("Invalid pokemon type."); @@ -100,4 +109,8 @@ public enum PokemonTypeDao { return updated; } + + public int getTotalPokemonTypes() { + return pokemonTypes.keySet().size(); + } } diff --git a/src/main/java/nl/utwente/mod4/pokemon/dao/TrainerDao.java b/src/main/java/nl/utwente/mod4/pokemon/dao/TrainerDao.java new file mode 100644 index 0000000000000000000000000000000000000000..bd8a9151d099b18d2fa73ccc8c87e250e85498cd --- /dev/null +++ b/src/main/java/nl/utwente/mod4/pokemon/dao/TrainerDao.java @@ -0,0 +1,106 @@ +package nl.utwente.mod4.pokemon.dao; + +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.NotFoundException; +import nl.utwente.mod4.pokemon.Utils; +import nl.utwente.mod4.pokemon.model.Trainer; + +import java.io.File; +import java.io.IOException; +import java.time.Instant; +import java.util.*; + +public enum TrainerDao { + + INSTANCE; + + private static final String ORIGINAL_TRAINERS = Utils.getAbsolutePathToResources() + "/default-trainers-dataset.json"; + private static final String TRAINERS = Utils.getAbsolutePathToResources() + "/trainers.json"; + + private HashMap<String, Trainer> trainers = new HashMap<>(); + + public void delete(String id) { + if(trainers.containsKey(id)) { + trainers.remove(id); + } else { + throw new NotFoundException("Trainer '" + id + "' not found."); + } + } + + public List<Trainer> getTrainers(int pageSize, int pageNumber) { + var list = new ArrayList<>(trainers.values()); + return (List<Trainer>) Utils.pageSlice(list,pageSize,pageNumber); + } + + public Trainer getTrainer(String id) { + var pt = trainers.get(id); + + if (pt == null) { + throw new NotFoundException("Pokemon '" + id + "' not found!"); + } + + return pt; + } + + public void load() throws IOException { + ObjectMapper mapper = new ObjectMapper(); + File source = existsTrainers() ? + new File(TRAINERS) : + new File(ORIGINAL_TRAINERS); + Trainer[] arr = mapper.readValue(source, Trainer[].class); + + Arrays.stream(arr).forEach(trainer -> trainers.put(trainer.id, trainer)); + } + + public void save() throws IOException { + ObjectMapper mapper = new ObjectMapper(); + ObjectWriter writer = mapper.writer(new DefaultPrettyPrinter()); + File destination = new File(TRAINERS); + + writer.writeValue(destination, trainers.values()); + } + + private boolean existsTrainers() { + File f = new File(TRAINERS); + return f.exists() && !f.isDirectory(); + } + + private int getMaxId() { + Set<String> ids = trainers.keySet(); + return ids.isEmpty() ? 0 : ids.stream() + .map(Integer::parseInt) + .max(Integer::compareTo) + .get(); + } + + + public Trainer create(Trainer newTrainer) { + String nextId = "" + (getMaxId() + 1); + + newTrainer.id = nextId; + newTrainer.created = Instant.now().toString(); + newTrainer.lastUpDate = Instant.now().toString(); + trainers.put(nextId,newTrainer); + + return newTrainer; + } + + public Trainer update(Trainer updated) { + if(!updated.isValid()) + throw new BadRequestException("Invalid trainer."); + if(trainers.get(updated.id) == null) + throw new NotFoundException("Trainer id '" + updated.id + "' not found."); + + updated.lastUpDate = Instant.now().toString(); + trainers.put(updated.id,updated); + + return updated; + } + + public int getTotalTrainers() { + return trainers.keySet().size(); + } +} diff --git a/src/main/java/nl/utwente/mod4/pokemon/model/ResourceCollection.java b/src/main/java/nl/utwente/mod4/pokemon/model/ResourceCollection.java index fb2868ea4538fc84ce801203be3356e3520877f7..92529e4f9c6fe66de7fbe8ad94294d3909e0bc87 100644 --- a/src/main/java/nl/utwente/mod4/pokemon/model/ResourceCollection.java +++ b/src/main/java/nl/utwente/mod4/pokemon/model/ResourceCollection.java @@ -1,4 +1,31 @@ package nl.utwente.mod4.pokemon.model; -public class ResourceCollection { +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; + +public class ResourceCollection<T extends NamedEntity> { + + public HashMap<String,Object> meta; + public HashMap<String,Object> links; + public T[] data; + + public ResourceCollection() { + data = null; + meta = new HashMap<>(); + links = new HashMap<>(); + } + + public ResourceCollection(T[] resources, int pageSize, int pageNumber, int total) { + meta = new HashMap<>(); + links = new HashMap<>(); + + meta.put("total", total); + meta.put("pageNumber", pageNumber); + meta.put("pageSize", pageSize); + + data = resources; + } + } diff --git a/src/main/java/nl/utwente/mod4/pokemon/model/Trainer.java b/src/main/java/nl/utwente/mod4/pokemon/model/Trainer.java new file mode 100644 index 0000000000000000000000000000000000000000..4f6f1cce08a44122424b0b5879b0d59f82fc7ddb --- /dev/null +++ b/src/main/java/nl/utwente/mod4/pokemon/model/Trainer.java @@ -0,0 +1,12 @@ +package nl.utwente.mod4.pokemon.model; + + +public class Trainer extends NamedEntity { + + public String profileUrl; + + public Trainer() { + super(); + profileUrl = null; + } +} diff --git a/src/main/java/nl/utwente/mod4/pokemon/routes/PokemonTypeRoute.java b/src/main/java/nl/utwente/mod4/pokemon/routes/PokemonTypeRoute.java index 298706dce80154e7fd463969794094931c123549..b98b707c234f1723cf7ce87d107c5c7aa5a2c391 100644 --- a/src/main/java/nl/utwente/mod4/pokemon/routes/PokemonTypeRoute.java +++ b/src/main/java/nl/utwente/mod4/pokemon/routes/PokemonTypeRoute.java @@ -5,6 +5,7 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import nl.utwente.mod4.pokemon.dao.PokemonTypeDao; import nl.utwente.mod4.pokemon.model.PokemonType; +import nl.utwente.mod4.pokemon.model.ResourceCollection; import java.util.List; @@ -13,21 +14,30 @@ public class PokemonTypeRoute { @GET @Produces(MediaType.APPLICATION_JSON) - public List<PokemonType> getPokemon() { - return PokemonTypeDao.INSTANCE.getPokemonTypes(); + public ResourceCollection<PokemonType> getPokemonTypes( + @QueryParam("sortBy") String sortBy, + @QueryParam("pageSize") int pageSize, + @QueryParam("pageNumber") int pageNumber + ) { + int ps = pageSize > 0 ? pageSize : Integer.MAX_VALUE; + int pn = pageNumber > 0 ? pageNumber : 1; + var resources = PokemonTypeDao.INSTANCE.getPokemonTypes(ps, pn, sortBy).toArray(new PokemonType[0]); + var total = PokemonTypeDao.INSTANCE.getTotalPokemonTypes(); + + return new ResourceCollection<>(resources, ps, pn, total); } @POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - public PokemonType createPokemon(PokemonType pokemonType) { + public PokemonType createPokemonType(PokemonType pokemonType) { return PokemonTypeDao.INSTANCE.create(pokemonType); } @GET @Path("/{id}") @Produces(MediaType.APPLICATION_JSON) - public PokemonType getPokemon(@PathParam("id") String id) { + public PokemonType getPokemonType(@PathParam("id") String id) { return PokemonTypeDao.INSTANCE.getPokemonType(id); } @@ -35,8 +45,8 @@ public class PokemonTypeRoute { @Path("/{id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - public PokemonType updatePokemon(@PathParam("id") String id, PokemonType toUpdate) { - if(id == null || !id.equals(toUpdate.id)) + public PokemonType updatePokemonType(@PathParam("id") String id, PokemonType toUpdate) { + if (id == null || !id.equals(toUpdate.id)) throw new BadRequestException("Id mismatch."); return PokemonTypeDao.INSTANCE.update(toUpdate); @@ -44,7 +54,7 @@ public class PokemonTypeRoute { @DELETE @Path("/{id}") - public void deletePokemon(@PathParam("id") String id) { + public void deletePokemonType(@PathParam("id") String id) { PokemonTypeDao.INSTANCE.delete(id); } } \ No newline at end of file diff --git a/src/main/java/nl/utwente/mod4/pokemon/routes/TrainerRoute.java b/src/main/java/nl/utwente/mod4/pokemon/routes/TrainerRoute.java new file mode 100644 index 0000000000000000000000000000000000000000..41ab71ec4ae918132aceae6891bc46235780999f --- /dev/null +++ b/src/main/java/nl/utwente/mod4/pokemon/routes/TrainerRoute.java @@ -0,0 +1,57 @@ +package nl.utwente.mod4.pokemon.routes; + +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import nl.utwente.mod4.pokemon.dao.TrainerDao; +import nl.utwente.mod4.pokemon.model.ResourceCollection; +import nl.utwente.mod4.pokemon.model.Trainer; + +@Path("/trainers") +public class TrainerRoute { + + + @GET + @Produces(MediaType.APPLICATION_JSON) + public ResourceCollection<Trainer> getTrainers( + @QueryParam("pageSize") int pageSize, + @QueryParam("pageNumber") int pageNumber + ) { + int ps = pageSize > 0 ? pageSize : Integer.MAX_VALUE; + int pn = pageNumber > 0 ? pageNumber : 1; + var resources = TrainerDao.INSTANCE.getTrainers(ps, pn).toArray(new Trainer[0]); + var total = TrainerDao.INSTANCE.getTotalTrainers(); + + return new ResourceCollection<>(resources, ps, pn, total); + } + + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public Trainer createTrainer(Trainer pokemonType) { + return TrainerDao.INSTANCE.create(pokemonType); + } + + @GET + @Path("/{id}") + @Produces(MediaType.APPLICATION_JSON) + public Trainer getTrainer(@PathParam("id") String id) { + return TrainerDao.INSTANCE.getTrainer(id); + } + + @PUT + @Path("/{id}") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public Trainer updateTrainer(@PathParam("id") String id, Trainer toUpdate) { + if (id == null || !id.equals(toUpdate.id)) + throw new BadRequestException("Id mismatch."); + + return TrainerDao.INSTANCE.update(toUpdate); + } + + @DELETE + @Path("/{id}") + public void deleteTrainer(@PathParam("id") String id) { + TrainerDao.INSTANCE.delete(id); + } +} diff --git a/src/main/resources/default-trainers-dataset.json b/src/main/resources/default-trainers-dataset.json new file mode 100644 index 0000000000000000000000000000000000000000..53712364e7707b2b9060a9f302ffd0123554d7ae --- /dev/null +++ b/src/main/resources/default-trainers-dataset.json @@ -0,0 +1,30 @@ +[ + { + "name": "Red", + "id": 1, + "created": "24/04/2024", + "lastUpDate": "24/04/2024", + "profileUrl": "/pokemon/images/red.png" + }, + { + "name": "Blue", + "id": 2, + "created": "24/04/2024", + "lastUpDate": "24/04/2024", + "profileUrl": "/pokemon/images/blue.png" + }, + { + "name": "Misty", + "id": 3, + "created": "24/04/2024", + "lastUpDate": "24/04/2024", + "profileUrl": "/pokemon/images/misty.png" + }, + { + "name": "Brock", + "id": 4, + "created": "24/04/2024", + "lastUpDate": "24/04/2024", + "profileUrl": "/pokemon/images/brock.png" + } +] \ No newline at end of file diff --git a/src/main/webapp/images/blue.png b/src/main/webapp/images/blue.png new file mode 100644 index 0000000000000000000000000000000000000000..f8444899b3c0b36de8c4698be98df53bf56225bc Binary files /dev/null and b/src/main/webapp/images/blue.png differ diff --git a/src/main/webapp/images/brock.jpg b/src/main/webapp/images/brock.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9c90529e36f2fde2306bd28b5bbf872e6b387e2d Binary files /dev/null and b/src/main/webapp/images/brock.jpg differ diff --git a/src/main/webapp/images/brock.png b/src/main/webapp/images/brock.png new file mode 100644 index 0000000000000000000000000000000000000000..b234cd691880eca73250aeb310f277cefcb54235 Binary files /dev/null and b/src/main/webapp/images/brock.png differ diff --git a/src/main/webapp/images/misty.png b/src/main/webapp/images/misty.png new file mode 100644 index 0000000000000000000000000000000000000000..e4cd0ae73a752db8f1c6e532878533f9d39a3fe3 Binary files /dev/null and b/src/main/webapp/images/misty.png differ diff --git a/src/main/webapp/images/red.jpg b/src/main/webapp/images/red.jpg new file mode 100644 index 0000000000000000000000000000000000000000..58d5d78c110ea449e7c72805539afa72a2064b98 Binary files /dev/null and b/src/main/webapp/images/red.jpg differ diff --git a/src/main/webapp/images/red.png b/src/main/webapp/images/red.png new file mode 100644 index 0000000000000000000000000000000000000000..6a817dc90141b779c63cffbc57e44a51c4cb2765 Binary files /dev/null and b/src/main/webapp/images/red.png differ diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html index 297e57248edfaef7113311f75ee797268a8e56c5..07bacaf0a7cf57f28e184b0b540deec522831903 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -5,9 +5,19 @@ <title>Title</title> </head> <body> + <p>Hello there</p> -<img src="/pokemon/images/abra.png"/> + +<img src="/pokemon/images/red.png" style="height: 150px"/> +<img src="/pokemon/images/abra.png" style="height: 150px"/> + +<form action="/pokemon/api/trainers"> + <input type="submit" value="Trainers" /> +</form> + <form action="/pokemon/api/pokemonTypes"> <input type="submit" value="Pokemon Types" /> -</form></body> +</form> + +</body> </html> \ No newline at end of file