Skip to content
Snippets Groups Projects
Commit 90bb0156 authored by Emmanuel Bruno's avatar Emmanuel Bruno
Browse files

moves to full english.

parent aebc8089
Branches
No related tags found
No related merge requests found
Showing
with 242 additions and 113 deletions
### Get a Hello message ### Get a Hello message
GET http://localhost:9998/mylibrary/setup GET http://localhost:9998/mylibrary/library
### Init the database with two authors ### Init the database with two authors
PUT http://localhost:9998/mylibrary/setup/init PUT http://localhost:9998/mylibrary/library/init
### Get author 1 in JSON ### Get author 1 in JSON
GET http://localhost:9998/mylibrary/authors/1 GET http://localhost:9998/mylibrary/authors/1
...@@ -38,7 +38,7 @@ Content-type: application/json ...@@ -38,7 +38,7 @@ Content-type: application/json
{"name":"John","firstname":"Smith","biography":"My life"} {"name":"John","firstname":"Smith","biography":"My life"}
### ReInit the database with two authors ### ReInit the database with two authors
PUT http://localhost:9998/mylibrary/setup/init PUT http://localhost:9998/mylibrary/library/init
### Fully update an author ### Fully update an author
PUT http://localhost:9998/mylibrary/authors/1 PUT http://localhost:9998/mylibrary/authors/1
...@@ -51,7 +51,7 @@ Content-type: application/json ...@@ -51,7 +51,7 @@ Content-type: application/json
GET http://localhost:9998/mylibrary/authors/1000 GET http://localhost:9998/mylibrary/authors/1000
Accept: application/json Accept: application/json
### If a resource doesn't exist an exception is raised, and the 404 http status code is returned ### TODO : (FIX IT) If a resource doesn't exist an exception is raised, and the 404 http status code is returned
GET http://localhost:9998/mylibrary/authors/1000 GET http://localhost:9998/mylibrary/authors/1000
Accept: text/xml Accept: text/xml
...@@ -65,7 +65,7 @@ Accept: application/json ...@@ -65,7 +65,7 @@ Accept: application/json
sortKey: firstname sortKey: firstname
### Init the database with 10k random authors ### Init the database with 10k random authors
PUT http://localhost:9998/mylibrary/setup/init/10000 PUT http://localhost:9998/mylibrary/library/init/10000
### Get page 3 with page size of 10 authors sorted by lastname ### Get page 3 with page size of 10 authors sorted by lastname
GET http://localhost:9998/mylibrary/authors/page?pageSize=10&page=3 GET http://localhost:9998/mylibrary/authors/page?pageSize=10&page=3
......
...@@ -42,9 +42,11 @@ public class Library { ...@@ -42,9 +42,11 @@ public class Library {
@JsonIgnore @JsonIgnore
final MutableLongObjectMap<Author> authors = LongObjectMaps.mutable.empty(); final MutableLongObjectMap<Author> authors = LongObjectMaps.mutable.empty();
final MutableLongObjectMap<Book> books = LongObjectMaps.mutable.empty();
/** /**
* used mainly to provide easy XML Serialization * used mainly to provide easy XML Serialization
*
* @return the list of authors * @return the list of authors
*/ */
@XmlElementWrapper(name = "authors") @XmlElementWrapper(name = "authors")
...@@ -53,8 +55,10 @@ public class Library { ...@@ -53,8 +55,10 @@ public class Library {
public List<Author> getAuthorsAsList() { public List<Author> getAuthorsAsList() {
return authors.toList(); return authors.toList();
} }
/** /**
* used mainly to provide easy XML Serialization * used mainly to provide easy XML Serialization
*
* @return the list of books * @return the list of books
*/ */
@XmlElementWrapper(name = "books") @XmlElementWrapper(name = "books")
...@@ -64,8 +68,6 @@ public class Library { ...@@ -64,8 +68,6 @@ public class Library {
return books.toList(); return books.toList();
} }
final MutableLongObjectMap<Book> books = LongObjectMaps.mutable.empty();
/** /**
* Adds an author to the model. * Adds an author to the model.
* *
...@@ -151,13 +153,7 @@ public class Library { ...@@ -151,13 +153,7 @@ public class Library {
return authors.size(); return authors.size();
} }
/** private Stream<Author> buildSortedFilteredStream(PaginationInfo paginationInfo) {
* Returns a sorted, filtered and paginated list of authors.
*
* @param paginationInfo the pagination info
* @return the sorted, filtered page.
*/
public List<Author> getAuthorsWithFilter(PaginationInfo paginationInfo) {
//We build a author stream, first we add sorting //We build a author stream, first we add sorting
Stream<Author> authorStream = authors.stream() Stream<Author> authorStream = authors.stream()
.sorted(Comparator.comparing(auteur -> switch (valueOf(paginationInfo.getSortKey().toUpperCase())) { .sorted(Comparator.comparing(auteur -> switch (valueOf(paginationInfo.getSortKey().toUpperCase())) {
...@@ -174,6 +170,22 @@ public class Library { ...@@ -174,6 +170,22 @@ public class Library {
if (paginationInfo.getBiography() != null) if (paginationInfo.getBiography() != null)
authorStream = authorStream.filter(author -> author.getBiography().contains(paginationInfo.getBiography())); authorStream = authorStream.filter(author -> author.getBiography().contains(paginationInfo.getBiography()));
return authorStream;
}
/**
* Returns a sorted, filtered and paginated list of authors.
*
* @param paginationInfo the pagination info
* @return the sorted, filtered page.
*/
public Page<Author> getAuthorsWithFilter(PaginationInfo paginationInfo) {
//We count the total number of results before limit and offset
long elementTotal = buildSortedFilteredStream(paginationInfo).count();
Stream<Author> authorStream = buildSortedFilteredStream(paginationInfo);
//Finally add pagination instructions. //Finally add pagination instructions.
if ((paginationInfo.getPage() > 0) && (paginationInfo.getPageSize() > 0)) { if ((paginationInfo.getPage() > 0) && (paginationInfo.getPageSize() > 0)) {
authorStream = authorStream authorStream = authorStream
...@@ -181,7 +193,11 @@ public class Library { ...@@ -181,7 +193,11 @@ public class Library {
.limit(paginationInfo.getPageSize()); .limit(paginationInfo.getPageSize());
} }
return authorStream.collect(Collectors.toList()); return Page.newInstance(paginationInfo.getPageSize(),
paginationInfo.getPage(),
elementTotal,
authorStream.collect(Collectors.toList())
);
} }
/** /**
......
package fr.univtln.bruno.samples.jaxrs.model;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
import java.util.List;
@FieldDefaults(level = AccessLevel.PRIVATE)
@Getter
public class Page<T> {
final long pageSize;
final long pageNumber;
final long elementTotal;
final List<T> content;
final long pageTotal;
private Page(long pageSize, long pageNumber, long elementTotal, List<T> content) {
this.pageSize = pageSize;
this.pageNumber = pageNumber;
this.elementTotal = elementTotal;
this.content = content;
this.pageTotal = elementTotal / pageSize;
}
public static <V> Page<V> newInstance(long pageSize, long pageNumber, long elementTotal, List<V> content) {
return new Page(pageSize, pageNumber, elementTotal, content);
}
}
package fr.univtln.bruno.samples.jaxrs.resources; package fr.univtln.bruno.samples.jaxrs.resources;
import fr.univtln.bruno.samples.jaxrs.exceptions.BusinessException;
import fr.univtln.bruno.samples.jaxrs.exceptions.IllegalArgumentException;
import fr.univtln.bruno.samples.jaxrs.model.Library;
import fr.univtln.bruno.samples.jaxrs.model.Library.Author;
import fr.univtln.bruno.samples.jaxrs.model.Library.Book;
import fr.univtln.bruno.samples.jaxrs.security.InMemoryLoginModule; import fr.univtln.bruno.samples.jaxrs.security.InMemoryLoginModule;
import fr.univtln.bruno.samples.jaxrs.security.User; import fr.univtln.bruno.samples.jaxrs.security.User;
import fr.univtln.bruno.samples.jaxrs.security.annotations.BasicAuth; import fr.univtln.bruno.samples.jaxrs.security.annotations.BasicAuth;
import fr.univtln.bruno.samples.jaxrs.security.annotations.JWTAuth; import fr.univtln.bruno.samples.jaxrs.security.annotations.JWTAuth;
import fr.univtln.bruno.samples.jaxrs.security.filter.request.BasicAuthenticationFilter;
import fr.univtln.bruno.samples.jaxrs.security.filter.request.JsonWebTokenFilter;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.*; import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.*; import jakarta.ws.rs.core.*;
import lombok.extern.java.Log; import lombok.extern.java.Log;
...@@ -21,12 +20,10 @@ import java.security.SecureRandom; ...@@ -21,12 +20,10 @@ import java.security.SecureRandom;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.Set;
/** /**
* The Biblio resource. * A administration class for the libraryBiblio resource.
* A demo JAXRS class, that manages authors and offers a secured access. * A demo JAXRS class, that manages authors and offers a secured access.
*/ */
@Log @Log
...@@ -38,76 +35,6 @@ public class AdminResource { ...@@ -38,76 +35,6 @@ public class AdminResource {
//A random number generator //A random number generator
private static final SecureRandom random = new SecureRandom(); private static final SecureRandom random = new SecureRandom();
/**
* The simpliest method that just return "hello" in plain text with GET on the default path "biblio".
*
* @return the string
*/
@SuppressWarnings("SameReturnValue")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String sayHello() {
return "hello";
}
/**
* An init method that add two authors with a PUT on the default path.
*
* @return the number of generated authors.
* @throws IllegalArgumentException the illegal argument exception
*/
@PUT
@Path("init")
public int init() throws BusinessException {
Library.demoLibrary.removesAuthors();
Author author1 = Library.demoLibrary.addAuthor(Library.Author.builder().firstname("Alfred").name("Martin").build());
Library.Author author2 = Library.demoLibrary.addAuthor(Author.builder().firstname("Marie").name("Durand").build());
Library.demoLibrary.addBook(Book.builder().title("title1").authors(Set.of(author1)).build());
Library.demoLibrary.addBook(Book.builder().title("title2").authors(Set.of(author1, author2)).build());
Library.demoLibrary.addBook(Book.builder().title("title3").authors(Set.of(author2)).build());
Library.demoLibrary.addBook(Book.builder().title("title4").authors(Set.of(author2)).build());
return Library.demoLibrary.getAuthorsNumber();
}
/**
* An init method that add a given number of random authors whose names are just random letters on PUT.
* The number of authors if given in the path avec bound to the name size. The needed format (an integer) is checked with a regular expression [0-9]+
* The parameter is injected with @PathParam
*
* @param size the number of authors to add
* @return the int number of generated authors.
* @throws IllegalArgumentException the illegal argument exception
*/
@PUT
@Path("init/{size:[0-9]+}")
public int init(@PathParam("size") int size) throws BusinessException {
Library.demoLibrary.removesAuthors();
for (int i = 0; i < size; i++)
Library.demoLibrary.addAuthor(
Author.builder()
.firstname(randomString(random.nextInt(6) + 2))
.name(randomString(random.nextInt(6) + 2)).build());
return Library.demoLibrary.getAuthorsNumber();
}
/**
* A random string generator
*
* @param targetStringLength the length of the String
* @return
*/
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();
}
/** /**
* A GET method to access the context of the request : The URI, the HTTP headers, the request and the security context (needs authentication see below). * A GET method to access the context of the request : The URI, the HTTP headers, the request and the security context (needs authentication see below).
* *
...@@ -135,10 +62,10 @@ public class AdminResource { ...@@ -135,10 +62,10 @@ public class AdminResource {
/** /**
* A GET restricted to ADMIN role with basic authentication. * A GET restricted to ADMIN role with basic authentication.
* @see fr.univtln.bruno.samples.jaxrs.security.filter.BasicAuthenticationFilter
* *
* @param securityContext the security context * @param securityContext the security context
* @return the restricted to admins * @return the restricted to admins
* @see BasicAuthenticationFilter
*/ */
@GET @GET
@Path("adminsonly") @Path("adminsonly")
...@@ -150,10 +77,10 @@ public class AdminResource { ...@@ -150,10 +77,10 @@ public class AdminResource {
/** /**
* A GET restricted to USER role with basic authentication (and not ADMIN !). * A GET restricted to USER role with basic authentication (and not ADMIN !).
* @see fr.univtln.bruno.samples.jaxrs.security.filter.BasicAuthenticationFilter
* *
* @param securityContext the security context * @param securityContext the security context
* @return the restricted to users * @return the restricted to users
* @see BasicAuthenticationFilter
*/ */
@GET @GET
@Path("usersonly") @Path("usersonly")
...@@ -165,10 +92,10 @@ public class AdminResource { ...@@ -165,10 +92,10 @@ public class AdminResource {
/** /**
* A GET restricted to USER & ADMIN roles, secured with a JWT Token. * A GET restricted to USER & ADMIN roles, secured with a JWT Token.
* @see fr.univtln.bruno.samples.jaxrs.security.filter.JsonWebTokenFilter
* *
* @param securityContext the security context * @param securityContext the security context
* @return the string * @return the string
* @see JsonWebTokenFilter
*/ */
@GET @GET
@Path("secured") @Path("secured")
......
...@@ -4,13 +4,13 @@ import fr.univtln.bruno.samples.jaxrs.exceptions.BusinessException; ...@@ -4,13 +4,13 @@ import fr.univtln.bruno.samples.jaxrs.exceptions.BusinessException;
import fr.univtln.bruno.samples.jaxrs.exceptions.IllegalArgumentException; import fr.univtln.bruno.samples.jaxrs.exceptions.IllegalArgumentException;
import fr.univtln.bruno.samples.jaxrs.exceptions.NotFoundException; import fr.univtln.bruno.samples.jaxrs.exceptions.NotFoundException;
import fr.univtln.bruno.samples.jaxrs.model.Library; import fr.univtln.bruno.samples.jaxrs.model.Library;
import fr.univtln.bruno.samples.jaxrs.model.Page;
import fr.univtln.bruno.samples.jaxrs.status.Status; import fr.univtln.bruno.samples.jaxrs.status.Status;
import jakarta.ws.rs.*; import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import lombok.extern.java.Log; import lombok.extern.java.Log;
import java.util.Collection; import java.util.Collection;
import java.util.List;
@Log @Log
@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
...@@ -102,7 +102,7 @@ public class AuthorRessource { ...@@ -102,7 +102,7 @@ public class AuthorRessource {
*/ */
@GET @GET
@Path("filter") @Path("filter")
public List<Library.Author> getFilteredAuteurs(@QueryParam("name") String name, public Page<Library.Author> getFilteredAuteurs(@QueryParam("name") String name,
@QueryParam("firstname") String firstname, @QueryParam("firstname") String firstname,
@QueryParam("biography") String biography, @QueryParam("biography") String biography,
@HeaderParam("sortKey") @DefaultValue("name") String sortKey) { @HeaderParam("sortKey") @DefaultValue("name") String sortKey) {
...@@ -112,7 +112,7 @@ public class AuthorRessource { ...@@ -112,7 +112,7 @@ public class AuthorRessource {
.biography(biography) .biography(biography)
.sortKey(sortKey) .sortKey(sortKey)
.build(); .build();
log.info(paginationInfo.toString());
return Library.demoLibrary.getAuthorsWithFilter(paginationInfo); return Library.demoLibrary.getAuthorsWithFilter(paginationInfo);
} }
...@@ -124,7 +124,7 @@ public class AuthorRessource { ...@@ -124,7 +124,7 @@ public class AuthorRessource {
*/ */
@GET @GET
@Path("page") @Path("page")
public List<Library.Author> getAuteursPage(@BeanParam PaginationInfo paginationInfo) { public Page<Library.Author> getAuteursPage(@BeanParam PaginationInfo paginationInfo) {
return Library.demoLibrary.getAuthorsWithFilter(paginationInfo); return Library.demoLibrary.getAuthorsWithFilter(paginationInfo);
} }
......
package fr.univtln.bruno.samples.jaxrs.resources; package fr.univtln.bruno.samples.jaxrs.resources;
import fr.univtln.bruno.samples.jaxrs.exceptions.BusinessException;
import fr.univtln.bruno.samples.jaxrs.exceptions.IllegalArgumentException;
import fr.univtln.bruno.samples.jaxrs.model.Library; import fr.univtln.bruno.samples.jaxrs.model.Library;
import jakarta.ws.rs.GET; import jakarta.ws.rs.*;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import lombok.extern.java.Log; import lombok.extern.java.Log;
import java.security.SecureRandom;
import java.util.Set;
@Log @Log
@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
@Path("library") @Path("library")
public class LibraryRessource { public class LibraryRessource {
//A random number generator
private static final SecureRandom random = new SecureRandom();
@GET @GET
public Library getAuteurs() { public Library getLibrary() {
return Library.demoLibrary; return Library.demoLibrary;
} }
/**
* The simpliest method that just return "hello" in plain text with GET on the default path "biblio".
*
* @return the string
*/
@SuppressWarnings("SameReturnValue")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String sayHello() {
return "hello";
}
/**
* An init method that add two authors with a PUT on the default path.
*
* @return the number of generated authors.
* @throws IllegalArgumentException the illegal argument exception
*/
@PUT
@Path("init")
public int init() throws BusinessException {
Library.demoLibrary.removesAuthors();
Library.Author author1 = Library.demoLibrary.addAuthor(Library.Author.builder().firstname("Alfred").name("Martin").build());
Library.Author author2 = Library.demoLibrary.addAuthor(Library.Author.builder().firstname("Marie").name("Durand").build());
Library.demoLibrary.addBook(Library.Book.builder().title("title1").authors(Set.of(author1)).build());
Library.demoLibrary.addBook(Library.Book.builder().title("title2").authors(Set.of(author1, author2)).build());
Library.demoLibrary.addBook(Library.Book.builder().title("title3").authors(Set.of(author2)).build());
Library.demoLibrary.addBook(Library.Book.builder().title("title4").authors(Set.of(author2)).build());
return Library.demoLibrary.getAuthorsNumber();
}
/**
* An init method that add a given number of random authors whose names are just random letters on PUT.
* The number of authors if given in the path avec bound to the name size. The needed format (an integer) is checked with a regular expression [0-9]+
* The parameter is injected with @PathParam
*
* @param size the number of authors to add
* @return the int number of generated authors.
* @throws IllegalArgumentException the illegal argument exception
*/
@PUT
@Path("init/{size:[0-9]+}")
public int init(@PathParam("size") int size) throws BusinessException {
Library.demoLibrary.removesAuthors();
for (int i = 0; i < size; i++)
Library.demoLibrary.addAuthor(
Library.Author.builder()
.firstname(randomString(random.nextInt(6) + 2))
.name(randomString(random.nextInt(6) + 2)).build());
return Library.demoLibrary.getAuthorsNumber();
}
/**
* A random string generator
*
* @param targetStringLength the length of the String
* @return
*/
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();
}
} }
package fr.univtln.bruno.samples.jaxrs.security; package fr.univtln.bruno.samples.jaxrs.security;
import fr.univtln.bruno.samples.jaxrs.security.filter.request.BasicAuthenticationFilter;
import fr.univtln.bruno.samples.jaxrs.security.filter.request.JsonWebTokenFilter;
import jakarta.ws.rs.core.SecurityContext; import jakarta.ws.rs.core.SecurityContext;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
...@@ -10,8 +12,8 @@ import java.security.Principal; ...@@ -10,8 +12,8 @@ import java.security.Principal;
/** /**
* This class define a specific security context after an authentication with either the basic or the JWT filters. * This class define a specific security context after an authentication with either the basic or the JWT filters.
* *
* @see fr.univtln.bruno.samples.jaxrs.security.filter.BasicAuthenticationFilter * @see BasicAuthenticationFilter
* @see fr.univtln.bruno.samples.jaxrs.security.filter.JsonWebTokenFilter * @see JsonWebTokenFilter
*/ */
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor(staticName = "newInstance") @AllArgsConstructor(staticName = "newInstance")
......
package fr.univtln.bruno.samples.jaxrs.security.annotations; package fr.univtln.bruno.samples.jaxrs.security.annotations;
import fr.univtln.bruno.samples.jaxrs.security.filter.request.BasicAuthenticationFilter;
import jakarta.ws.rs.NameBinding; import jakarta.ws.rs.NameBinding;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
...@@ -11,7 +12,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; ...@@ -11,7 +12,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* A annotation for method to be secured with Basic Auth * A annotation for method to be secured with Basic Auth
* @see fr.univtln.bruno.samples.jaxrs.security.filter.BasicAuthenticationFilter * @see BasicAuthenticationFilter
*/ */
@NameBinding @NameBinding
@Retention(RUNTIME) @Retention(RUNTIME)
......
package fr.univtln.bruno.samples.jaxrs.security.annotations; package fr.univtln.bruno.samples.jaxrs.security.annotations;
import fr.univtln.bruno.samples.jaxrs.security.filter.request.JsonWebTokenFilter;
import jakarta.ws.rs.NameBinding; import jakarta.ws.rs.NameBinding;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
...@@ -11,7 +12,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; ...@@ -11,7 +12,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* A annotation for method to be secured with Java Web Token (JWT) * A annotation for method to be secured with Java Web Token (JWT)
* @see fr.univtln.bruno.samples.jaxrs.security.filter.JsonWebTokenFilter * @see JsonWebTokenFilter
*/ */
@NameBinding @NameBinding
@Retention(RUNTIME) @Retention(RUNTIME)
......
package fr.univtln.bruno.samples.jaxrs.security.filter; package fr.univtln.bruno.samples.jaxrs.security.filter.request;
import fr.univtln.bruno.samples.jaxrs.security.MySecurityContext; import fr.univtln.bruno.samples.jaxrs.security.MySecurityContext;
import fr.univtln.bruno.samples.jaxrs.security.annotations.BasicAuth; import fr.univtln.bruno.samples.jaxrs.security.annotations.BasicAuth;
......
package fr.univtln.bruno.samples.jaxrs.security.filter; package fr.univtln.bruno.samples.jaxrs.security.filter.request;
import fr.univtln.bruno.samples.jaxrs.security.InMemoryLoginModule; import fr.univtln.bruno.samples.jaxrs.security.InMemoryLoginModule;
import fr.univtln.bruno.samples.jaxrs.security.MySecurityContext; import fr.univtln.bruno.samples.jaxrs.security.MySecurityContext;
......
package fr.univtln.bruno.samples.jaxrs.security.filter.response;
import fr.univtln.bruno.samples.jaxrs.model.Page;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.container.ContainerResponseFilter;
import jakarta.ws.rs.core.Link;
import jakarta.ws.rs.core.UriInfo;
import jakarta.ws.rs.ext.Provider;
import java.util.ArrayList;
import java.util.List;
@Provider
public class PaginationLinkFilter implements ContainerResponseFilter {
public static final String JAXRS_SAMPLE_TOTAL_COUNT = "JAXRS_Sample-Total-Count";
public static final String JAXRS_SAMPLE_PAGE_COUNT = "JAXRS_Sample-Page-Count";
public static final String PREV_REL = "previous";
public static final String NEXT_REL = "next";
public static final String FIRST_REL = "first";
public static final String LAST_REL = "last";
public static final String PAGE_QUERY_PARAM = "page";
public static final int FIRST_PAGE = 1;
@Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext) {
//If the entity in the response is not a Page we stop here
if (!(responseContext.getEntity() instanceof Page)) {
return;
}
UriInfo uriInfo = requestContext.getUriInfo();
Page entity = (Page) responseContext.getEntity();
//We replace the entity by the content of the page (we remove the envelope).
responseContext.setEntity(entity.getContent());
List<Link> linksList = new ArrayList<>();
//We add the need semantic links in the header
//Not on the first page
if (entity.getPageSize() > FIRST_PAGE) {
linksList.add(Link.fromUriBuilder(uriInfo.getRequestUriBuilder()
.replaceQueryParam(PAGE_QUERY_PARAM,
entity.getPageNumber() - 1))
.rel(PREV_REL)
.build());
linksList.add(Link.fromUriBuilder(uriInfo.getRequestUriBuilder()
.replaceQueryParam(PAGE_QUERY_PARAM,
1))
.rel(FIRST_REL)
.build());
}
//Not on the last
if (entity.getPageSize() < entity.getPageTotal()) {
linksList.add(Link.fromUriBuilder(uriInfo.getRequestUriBuilder()
.replaceQueryParam(PAGE_QUERY_PARAM,
entity.getPageNumber() + 1))
.rel(NEXT_REL)
.build());
linksList.add(Link.fromUriBuilder(uriInfo.getRequestUriBuilder()
.replaceQueryParam(PAGE_QUERY_PARAM,
entity.getPageTotal()))
.rel(LAST_REL)
.build());
}
responseContext.getHeaders()
.addAll("Link", linksList.toArray(Link[]::new));
//We add pagination metadata in the header
responseContext.getHeaders().add(JAXRS_SAMPLE_TOTAL_COUNT, entity.getElementTotal());
responseContext.getHeaders().add(JAXRS_SAMPLE_PAGE_COUNT, entity.getPageTotal());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment