Paso 1: Crear Editorial - Explicación del código

Persistencia

Clase EditorialEntity

En este ejemplo simple, la clase EditorialEntity hereda de la clase BaseEntity que define el id identificador único del objeto en la base de datos. El atributo name está definido en la clase EditorialEntity. Como todas nuestras entidades tienen un identificador único lo hemos factorizado en la super clase BaseEntity. De la misma forma el método equals y hashcode que trabajan solo sobre el atributo id.

Clase EditorialPersistence

  • 1) Es un EJB sin estado por esta razón se anota con @Stateless.
  • 2) Define un EntityManager para acceder a la base de datos.
  • 3) El debe estar anotado con @PersistenceContext y tener definido el atributo unitName.
  • 4) El nombre lógico de la base de datos es "BookStorePU" (atributo unitName en línea 6) el archivo persistence.xml define las propiedades de la base de datos asociada con este nombre (localización, puerto, nombre físico, etc.).
  • 5) El método createque crea una entidad Editorial en la base de datos recibe la entidad como parámetro. La signatura es:
public EditorialEntity create(EditorialEntity entity) { ..}
  • 6) El método invoca el método persist del EntityManager. Este método recibe la entidad y devuelve la entidad con el nuevo id asignado porque así lo definimos en la clase EditorialEntity.
@Stateless public class EditorialPersistence { private static final Logger LOGGER = Logger.getLogger(EditorialPersistence.class.getName()); @PersistenceContext(unitName = "BookStorePU") protected EntityManager em; /** * Método para persisitir la entidad en la base de datos. * * @param editorialEntity objeto editorial que se creará en la base de datos * @return devuelve la entidad creada con un id dado por la base de datos. */ public EditorialEntity create(EditorialEntity editorialEntity) { LOGGER.log(Level.INFO, "Creando una editorial nueva"); /* Note que hacemos uso de un método propio de EntityManager para persistir la editorial en la base de datos. Es similar a "INSERT INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...);" en SQL. */ em.persist(editorialEntity); LOGGER.log(Level.INFO, "Saliendo de crear una editorial nueva"); return editorialEntity; } ... }
  • 7) La clase EditorialPersistence también tiene definido el método findByName que retorna null si no encuentra una editorial con el nombre pasado de argumento o retorna la entidad (la primera que encuentre) con el nombre dado.
/** * Busca si hay alguna editorial con el nombre que se envía de argumento * * @param name: Nombre de la editorial que se está buscando * @return null si no existe ninguna editorial con el nombre del argumento. * Si existe alguna devuelve la primera. */ public EditorialEntity findByName(String name) { LOGGER.log(Level.INFO, "Consultando editorial por nombre ", name); // Se crea un query para buscar editoriales con el nombre que recibe el método como argumento. ":name" es un placeholder que debe ser remplazado TypedQuery query = em.createQuery("Select e From EditorialEntity e where e.name = :name", EditorialEntity.class); // Se remplaza el placeholder ":name" con el valor del argumento query = query.setParameter("name", name); // Se invoca el query se obtiene la lista resultado List<EditorialEntity> sameName = query.getResultList(); EditorialEntity result; if (sameName == null) { result = null; } else if (sameName.isEmpty()) { result = null; } else { result = sameName.get(0); } LOGGER.log(Level.INFO, "Saliendo de consultar editorial por nombre ", name); return result; }

Lógica

Clase EditorialLogic

Tiene el método createEditorial que recibe una EditorialEntity y devuelve la misma EditorialEntity solo que le ha asignado un id único (la persistencia).

El método primero valida la regla de negocio y si ya existe una editorial con el nombre igual al que se va a crear, dispara BusinessLogicException (línea 13 y 14). El mensaje es el que recibirá quien invocó el servicio.

Si no existe, llama a la capa de persistencia para que efectivamente cree la entidad en la base de datos (línea 16).

@Stateless public class EditorialLogic { private static final Logger LOGGER = Logger.getLogger(EditorialLogic.class.getName()); @Inject private EditorialPersistence persistence; // Variable para acceder a la persistencia de la aplicación. Es una inyección de dependencias. public EditorialEntity createEditorial(EditorialEntity entity) throws BusinessLogicException { LOGGER.info("Inicia proceso de creación de editorial"); // Verifica la regla de negocio que dice que no puede haber dos editoriales con el mismo nombre if (persistence.findByName(entity.getName())!= null) throw new BusinessLogicException("Ya existe una Editorial con el nombre \"" + entity.getName()+"\""); // Invoca la persistencia para crear la editorial persistence.create(entity); LOGGER.info("Termina proceso de creación de editorial"); return entity; } }

Clase BusinessLogicException

En nuestro diseño, cuando una regla de negocio validada por la capa de lógica no se cumple, disparamos la excepción BusinessLogicException con el mensaje adecuado para que sea entendido por el usuario final.

Para que JAX-RS pueda transformar esta excepción a un código HTTP definimos la clase BusinessLogicExceptionMapper que implementa la interface definida en JAX-RS ExceptionMapper<T>, donde T es la excepción que queremos procesar. ExceptionMapper<T> tiene por misión transformar una excepción en java en una respuesta HTTP (Response object) que viajará de regreso a quien invocó el servicio.

La clase debe tener definida la anotación @Provider para que JAX-RS la pueda procesar. El manual de referencia de JAX-RS, para más detalles, lo puede encontrar aquí.

@Provider
public class BusinessLogicExceptionMapper implements ExceptionMapper<BusinessLogicException> { ...}

La interface ExceptionMapper<T>define un único método que debe ser implementado:

Response toResponse(T exception)

En nuestro código la implementación del método, devuelve el objeto Response al que le asigna el código HTTP (412 PRECONDITION_FAILED) y devuelve el mensaje inicial que se envió cuando se disparó la excepción BusinessLogicException.

@Override public Response toResponse(BusinessLogicException exception) { // retorna una respuesta return Response.status(Response.Status.PRECONDITION_FAILED) .entity(getInitCause(exception).getLocalizedMessage()) .type(MediaType.TEXT_PLAIN_TYPE) .build(); //To change body of generated methods, choose Tools | Templates. }

API Rest

Clase EditorialResource

Para implementar los servicios de acceso a los recursos Editorial, definimos la clase EditorialResource.

Cada clase recurso debe tener tres anotaciones:

  • 1) @Path: indica como completar la url para acceder a los servicios asociados con este recurso (línea 1).
  • 2) @Produces: que indica el tipo de datos que devolverán los servicios de este recurso. EN nuetsr ejemplo son JSON (línea 2).
  • 3) @RequestScoped: Significa que se va a iniciar una transacción al comienzo de la ejecución de cualquier método definido en esta clase.

Adicionalmente, de acuerdo con nuestro diseño, los objetos de la clase recurso utilizan la capa de la lógica. En este caso definimos una variable EditorialLogic editorialLogic. Queremos que el objeto asociado con esta variable sea asignado por el contenedor, por esto anotamos esta variable con@Inject.

@Path("editorials") @Produces("application/json") @RequestScoped public class EditorialResource { @Inject EditorialLogic editorialLogic; ... }

El método de creación de una editorial debe estar anotado con @POST. El método recibe el json enviado desde la invocación solo que aqui ya fue transformado por JAX-RS en un objeto de la clase EditorialDetailDTO. Note también que el método reenvia BusinessLogicException.

Este método debe invocar la capa de lógica a través de la variable editorialLogic. Como, de acuerdo con nuestro diseño, la capa de lógica solo sabe de objetos entities, antes de la invocación transformaos el DTO a Entity (línea 4) y después de la invocación transformamos el Entity a DTO (línea 4).

@POST public EditorialDTO createEditorial(EditorialDTO editorial) throws BusinessLogicException { LOGGER.log(Level.INFO, "EditorialResource createEditorial: input: {0}", editorial.toString()); // Convierte el DTO (json) en un objeto Entity para ser manejado por la lógica. EditorialEntity editorialEntity = editorial.toEntity(); // Invoca la lógica para crear la editorial nueva EditorialEntity nuevoEditorialEntity = editorialLogic.createEditorial(editorialEntity); // Como debe retornar un DTO (json) se invoca el constructor del DTO con argumento el entity nuevo EditorialDTO nuevoEditorialDTO = new EditorialDTO(nuevoEditorialEntity); LOGGER.log(Level.INFO, "EditorialResource createEditorial: output: {0}", nuevoEditorialDTO.toString()); return nuevoEditorialDTO; }

results matching ""

    No results matching ""