diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java index 4859aa67d8275dc68d333aeeb35742ab1d2e2b34..01db7851b67e4974d5377636c6cbaeae4e368918 100644 --- a/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java +++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java @@ -2,6 +2,7 @@ package fr.univtln.bruno.samples.jaxrs.model; import fr.univtln.bruno.samples.jaxrs.exceptions.IllegalArgumentException; import fr.univtln.bruno.samples.jaxrs.exceptions.NotFoundException; +import fr.univtln.bruno.samples.jaxrs.resources.PaginationInfo; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAttribute; @@ -14,6 +15,13 @@ import org.eclipse.collections.api.map.primitive.MutableLongObjectMap; import org.eclipse.collections.impl.factory.primitive.LongObjectMaps; import java.io.Serializable; +import java.security.InvalidParameterException; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static fr.univtln.bruno.samples.jaxrs.model.BiblioModel.Field.valueOf; @Log @Getter @@ -54,11 +62,34 @@ public class BiblioModel { return auteurs.size(); } + public List<Auteur> getWithFilter(PaginationInfo paginationInfo) { + Stream<Auteur> auteurStream = auteurs.stream(); + if (paginationInfo.getNom() != null) + auteurStream = auteurStream.filter(auteur -> auteur.getNom().equalsIgnoreCase(paginationInfo.getNom())); + if (paginationInfo.getPrenom() != null) + auteurStream = auteurStream.filter(auteur -> auteur.getPrenom().equalsIgnoreCase(paginationInfo.getPrenom())); + if (paginationInfo.getBiographie() != null) + auteurStream = auteurStream.filter(auteur -> auteur.getBiographie().contains(paginationInfo.getBiographie())); + if ((paginationInfo.getPage() > 0) && (paginationInfo.getPageSize() > 0)) { + auteurStream = auteurStream + .skip(paginationInfo.getPageSize() * (paginationInfo.getPage() - 1)) + .limit(paginationInfo.getPageSize()); + } + + return auteurStream.sorted(Comparator.comparing(auteur -> switch (valueOf(paginationInfo.getSortKey().toUpperCase())) { + case NOM -> auteur.getNom(); + case PRENOM -> auteur.getPrenom(); + default -> throw new InvalidParameterException(); + })).collect(Collectors.toList()); + } + public void supprimerAuteurs() { auteurs.clear(); lastId = 0; } + public enum Field {NOM, PRENOM, BIOGRAPHIE} + @Builder @Getter @Setter diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java index 1ec34be52876397cee81d4af754c3328f887d273..f346c4d811c898a360346689b6cba256b62b41a3 100644 --- a/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java +++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java @@ -10,11 +10,8 @@ import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import lombok.extern.java.Log; -import java.security.InvalidParameterException; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; -import java.util.stream.Collectors; +import java.security.SecureRandom; +import java.util.*; @Log // The Java class will be hosted at the URI path "/biblio" @@ -23,6 +20,8 @@ import java.util.stream.Collectors; public class BiblioResource { private static final BiblioModel modeleBibliotheque = BiblioModel.of(); + private static final SecureRandom random = new SecureRandom(); + @SuppressWarnings("SameReturnValue") @GET @Produces(MediaType.TEXT_PLAIN) @@ -39,6 +38,29 @@ public class BiblioResource { return modeleBibliotheque.getAuteurSize(); } + @PUT + @Path("init/{size:[0-9]+}") + public int init(@PathParam("size") int size) throws IllegalArgumentException { + modeleBibliotheque.supprimerAuteurs(); + for (int i = 0; i < size; i++) + modeleBibliotheque.addAuteur( + Auteur.builder() + .prenom(randomString(random.nextInt(6) + 2)) + .nom(randomString(random.nextInt(6) + 2)).build()); + return modeleBibliotheque.getAuteurSize(); + } + + private String randomString(int targetStringLength) { + int letterA = 97; + int letterZ = 122; + + + return random.ints(letterA, letterZ + 1) + .limit(targetStringLength) + .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) + .toString(); + } + @PUT @Path("auteurs/{id}") @Consumes(MediaType.APPLICATION_JSON) @@ -49,8 +71,8 @@ public class BiblioResource { /** * Status annotation is a trick to fine tune 2XX status codes (see the status package). * - * @param auteur - * @return + * @param auteur The author to be added without its id. + * @return The added author with its id. * @throws IllegalArgumentException */ @POST @@ -87,23 +109,23 @@ public class BiblioResource { @GET @Path("auteurs/filter") - public List<Auteur> getFilteredAuteurs(@QueryParam("nom") String nom, @QueryParam("prenom") String prenom, @QueryParam("biograpĥie") String biographie, + public List<Auteur> getFilteredAuteurs(@QueryParam("nom") String nom, + @QueryParam("prenom") String prenom, + @QueryParam("biographie") String biographie, @HeaderParam("sortKey") @DefaultValue("nom") String sortKey) { - log.info("Sort Key: "+sortKey); - //Demo purpose ONLY sorting have to be done in the model - return modeleBibliotheque - .stream() - .filter(auteur -> nom == null || auteur.getNom().equalsIgnoreCase(nom)) - .filter(auteur -> prenom == null || auteur.getPrenom().equalsIgnoreCase(prenom)) - .filter(auteur -> biographie == null || auteur.getBiographie().contains(biographie)) - //We use the news Java 15 switch syntax and value - .sorted(Comparator.comparing(auteur -> switch (sortKey) { - case "nom" -> auteur.getNom(); - case "prenom" -> auteur.getPrenom(); - default -> throw new InvalidParameterException(); - })) - .collect(Collectors.toList()); + PaginationInfo paginationInfo = PaginationInfo.builder() + .nom(nom) + .prenom(prenom) + .biographie(biographie) + .sortKey(sortKey) + .build(); + log.info(paginationInfo.toString()); + return modeleBibliotheque.getWithFilter(paginationInfo); } - + @GET + @Path("auteurs/page") + public List<Auteur> getAuteursPage(@BeanParam PaginationInfo paginationInfo) { + return modeleBibliotheque.getWithFilter(paginationInfo); + } } diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/PaginationInfo.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/PaginationInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..6e4c2cd65cc28d59a2153773a2b6293247b196e4 --- /dev/null +++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/PaginationInfo.java @@ -0,0 +1,36 @@ +package fr.univtln.bruno.samples.jaxrs.resources; + +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.QueryParam; +import lombok.*; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PRIVATE) +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PaginationInfo { + @HeaderParam("sortKey") + @DefaultValue("nom") + String sortKey; + + @QueryParam("page") + @Builder.Default + long page = 1; + + @QueryParam("pageSize") + @Builder.Default + long pageSize = 10; + + @QueryParam("nom") + String nom; + + @QueryParam("prenom") + String prenom; + + @QueryParam("biographie") + String biographie; +} diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/status/StatusFilter.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/status/StatusFilter.java index a7e3e040d0d71ee7449e5d14ee74485071974ca7..1e376eed8c577df65ea756842654fc9cb76384b5 100644 --- a/src/main/java/fr/univtln/bruno/samples/jaxrs/status/StatusFilter.java +++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/status/StatusFilter.java @@ -13,7 +13,7 @@ import java.lang.annotation.Annotation; public class StatusFilter implements ContainerResponseFilter { @Override - public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException { + public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) { if (containerResponseContext.getStatus() == Response.Status.OK.getStatusCode()) { for (Annotation annotation : containerResponseContext.getEntityAnnotations()) { if (annotation instanceof Status) { diff --git a/src/test/java/fr/univtln/bruno/samples/jaxrs/ServerIT.java b/src/test/java/fr/univtln/bruno/samples/jaxrs/ServerIT.java index 8d2e71437163720252a382109595ad829f3e0193..2a67e62898831ed24fa7e4ed332214022f9bb20a 100644 --- a/src/test/java/fr/univtln/bruno/samples/jaxrs/ServerIT.java +++ b/src/test/java/fr/univtln/bruno/samples/jaxrs/ServerIT.java @@ -104,7 +104,7 @@ public class ServerIT { */ @Test public void testGetAuteurs() { - Collection<Auteur> responseAuteurs = webTarget.path("biblio/auteurs").request(MediaType.APPLICATION_JSON).get(new GenericType<Collection<Auteur>>() { + Collection<Auteur> responseAuteurs = webTarget.path("biblio/auteurs").request(MediaType.APPLICATION_JSON).get(new GenericType<>() { }); assertEquals(2, responseAuteurs.size()); } @@ -115,7 +115,7 @@ public class ServerIT { @Test public void deleteAuteurs() { webTarget.path("biblio/auteurs").request().delete(); - Collection<Auteur> responseAuteurs = webTarget.path("biblio/auteurs").request(MediaType.APPLICATION_JSON).get(new GenericType<Collection<Auteur>>() { + Collection<Auteur> responseAuteurs = webTarget.path("biblio/auteurs").request(MediaType.APPLICATION_JSON).get(new GenericType<>() { }); assertEquals(0, responseAuteurs.size()); } @@ -126,7 +126,7 @@ public class ServerIT { @Test public void deleteAuteur() { webTarget.path("biblio/auteurs/1").request().delete(); - Collection<Auteur> responseAuteurs = webTarget.path("biblio/auteurs").request(MediaType.APPLICATION_JSON).get(new GenericType<Collection<Auteur>>() { + Collection<Auteur> responseAuteurs = webTarget.path("biblio/auteurs").request(MediaType.APPLICATION_JSON).get(new GenericType<>() { }); assertEquals(1, responseAuteurs.size()); assertEquals(2, responseAuteurs.iterator().next().getId()); @@ -142,7 +142,7 @@ public class ServerIT { .request(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .post(Entity.entity("{\"nom\":\"Smith\",\"prenom\":\"John\",\"biographie\":\"My life\"}", MediaType.APPLICATION_JSON)); - Collection<Auteur> responseAuteurs = webTarget.path("biblio/auteurs").request(MediaType.APPLICATION_JSON).get(new GenericType<Collection<Auteur>>() { + Collection<Auteur> responseAuteurs = webTarget.path("biblio/auteurs").request(MediaType.APPLICATION_JSON).get(new GenericType<>() { }); assertEquals(3, responseAuteurs.size()); Auteur responseAuteur = webTarget.path("biblio/auteurs/3").request(MediaType.APPLICATION_JSON).get(Auteur.class);