Relación entre Libro y Autores
Traer todos los autores de un libro dado su bookId
Servicio | Rest | BookResource | BookLogic |
---|---|---|---|
Traer todos los autores de un libro dado su idBook | GET /books/{bookId}/authors | public List<AuthorDTO> listAuthors(@PathParam("bookId") Long bookId) |
public List<AuthorEntity> getAuthors(Long bookId) |
El siguiente diagrama de secuencia muestra la interacción entre los objetos para que el recurso book retorne una lista de autores en representación básica:
Paso 1: Desde el cliente hace el llamado rest:
GET /books/{booksId}/authors
Paso 2: BookResource debe tener un método anotado con @GET y que identifique el path dado. El método es:
public
List<AuthorDTO> listAuthors(@PathParam("bookId") Long bookId)
Note que el método recibe de parámetro el id del book del cual se quiere obtener quiénes son sus autores
Paso 3: Llamado a la lógica: La lógica de BookLogic tiene un método getAuthors que devuelve una lista de dtos de autores:
public List<AuthorEntity> getAuthors(Long bookId)
Note que el método también recibe de parámetro el id del book del cual se quiere obtener quiénes son sus autores.
La lógica primero busca si efectivamente hay un BookEntity que corresponda con el bookId dado por parámetro. Para esto llama ala persistencia para que haga un find en la base de datos utilizando el BookId. Si no existe el libro se debe disparar una exception. Esto no está en el diagrama de secuencia pero a continuación se muestra el código:
@Stateless
public class BookLogic implements IBookLogic {
...
@Override
public BookEntity getBook(Long id) {
logger.log(Level.INFO, "Inicia proceso de consultar libro con id={0}", id);
BookEntity book = persistence.find(id);
if (book == null) {
logger.log(Level.SEVERE, "El libro con el id {0} no existe", id);
throw new IllegalArgumentException("El libro solicitado no existe");
}
logger.log(Level.INFO, "Termina proceso de consultar libro con id={0}", id);
return book;
}
...
El resultado del find es un book entity que contiene toda su información, es decir, todos los atributos de BookEntity:
@Entity
public class BookEntity extends BaseEntity implements Serializable {
private String isbn;
private String image;
@PodamStrategyValue(DateStrategy.class)
@Temporal(TemporalType.DATE)
private Date publishDate;
private String description;
@ManyToMany
@PodamExclude
private List<AuthorEntity> authors = new ArrayList<>();
@ManyToOne
@PodamExclude
private EditorialEntity editorial;
@OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ReviewEntity> reviews = new ArrayList<>();
...
En particular, el atributo authors
contiene la lista de los autores (AuthorEntity) del libro encontrado a través de su id. De esta forma, la lógica puede invocar el método getAuthors()
sobre el objeto BookEntity.
Paso 4: Cuando se termina la ejecución de la lógica, el recurso book debe convertir la lista de autores entity en una lista de autores dtos. Para esto invoca listEntity2DTO que devuelve los dtos en representación basic:
public abstract class AuthorConverter {
...
public static List<AuthorDTO> listEntity2DTO(List<AuthorEntity> entities) {
List<AuthorDTO> dtos = new ArrayList<AuthorDTO>();
if (entities != null) {
for (AuthorEntity entity : entities) {
dtos.add(basicEntity2DTO(entity));
}
}
return dtos;
}
...
}
Agregar a un libro dado su bookId un author dado su authorId
Servicio | Rest | BookResource | BookLogic |
---|---|---|---|
Agregar a un libro dado su bookId un author dado su authorId | POST /books/{booksId}/authors/authorId | public AuthorDTO addAuthors(@PathParam("bookId") Long bookId, @PathParam("authorId") Long authorId) |
public AuthorEntity addAuthor(Long authorId, Long bookId) throws BusinessLogicException |
El siguiente diagrama de secuencia muestra la interacción entre los objetos para que el recurso book agregue a su colección de autores un nuevo autor:
Paso 1: Desde el cliente hace el llamado rest:
POST /books/{booksId}/authors/{authorId}
Paso 2: BookResource debe tener un método anotado con @POST y que identifique el path dado. El método es:
/**
* Asocia un Author existente a un Book
*
* @param bookId Identificador del objeto de Book
* @param authorId Identificador del objeto de Author
* @return Objeto de AuthorDTO en representación full que fue asociado a Book
* @generated
*/
@POST
@Path("{bookId: \\d+}/authors/{authorId: \\d+}")
public AuthorDTO addAuthors(@PathParam("bookId") Long bookId, @PathParam("authorId") Long authorId) {
try {
AuthorEntity author = bookLogic.addAuthor(bookId, authorId);
return AuthorConverter.fullEntity2DTO(author);
} catch (BusinessLogicException ex) {
logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
throw new WebApplicationException(ex.getLocalizedMessage(), ex, Response.Status.BAD_REQUEST);
}
}
Paso 3: Llamado a la lógica: La lógica de BookLogic tiene un método addAuthor que devuelve el autor dto en representación full. El método recibe los dos ids: el de book y el de author:
public AuthorEntity addAuthor(Long authorId, Long bookId) throws BusinessLogicException
La exception BusinessLogicException
se dispara si sucede que la fecha del libro es inferior a la fecha del nacimiento del autor.
La lógica primero busca si efectivamente hay un BookEntity que corresponda con el bookId dado por parámetro. Para esto llama ala persistencia para que haga un find en la base de datos utilizando el BookId y el BookPersistence. Si no existe el libro se debe disparar una exception. También busca si efectivamente hay un AuthorEntity que corresponda con el authorId dado por parámetro. Para esto llama ala persistencia para que haga un find en la base de datos utilizando el authorId y el AuthorPersistence. Si no existe el author se debe disparar una exception. Esto no está en el diagrama de secuencia pero a continuación se muestra el código:
@Override
public AuthorEntity addAuthor(Long authorId, Long bookId) throws BusinessLogicException {
BookEntity bookEntity = getBook(bookId);
AuthorEntity authorEntity = authorPersistence.find(authorId);
if (authorEntity == null) {
throw new IllegalArgumentException("El autor no existe");
}
if (!bornBeforePublishDate(authorEntity.getBirthDate(), bookEntity.getPublishDate())) {
throw new BusinessLogicException("La fecha de publicación no puede ser anterior a la fecha de nacimiento del autor");
}
bookEntity.getAuthors().add(authorEntity);
return authorEntity;
}
Si tanto el libro como el autor existen, a la colección de entities de autores del libro dado se le agrega el entity autor correspondiente con el authorId que se pasó como parámetro.