diff --git a/additional-material/db/xcs-sample-mysql.sql b/additional-material/db/xcs-sample-mysql.sql index ea29d6379eeadde502b63bf5afe838e1aa4705b5..be8fa8cde5f948084298f05f780cc6d63deb8f2d 100644 --- a/additional-material/db/xcs-sample-mysql.sql +++ b/additional-material/db/xcs-sample-mysql.sql @@ -1,85 +1,177 @@ CREATE DATABASE IF NOT EXISTS `xcs`; USE `xcs`; -DROP TABLE IF EXISTS `Pet`; -DROP TABLE IF EXISTS `User`; +DROP TABLE IF EXISTS `pet_vet`; +DROP TABLE IF EXISTS `vaccination`; +DROP TABLE IF EXISTS `vaccine`; +DROP TABLE IF EXISTS `identifier`; +DROP TABLE IF EXISTS `pet`; +DROP TABLE IF EXISTS `user`; -- -- Table structure for table `User` -- -CREATE TABLE `User` ( +CREATE TABLE `user` ( `role` varchar(5) NOT NULL, `login` varchar(100) NOT NULL, - `password` varchar(32) NOT NULL, + `password` varchar(128) NOT NULL, PRIMARY KEY (`login`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Table structure for table `Pet` -- -CREATE TABLE `Pet` ( - `id` int(11) NOT NULL AUTO_INCREMENT, +CREATE TABLE `pet` ( + `id` int NOT NULL AUTO_INCREMENT, `animal` varchar(4) NOT NULL, `birth` datetime NOT NULL, `name` varchar(100) NOT NULL, `owner` varchar(100) NOT NULL, - `vet` varchar(100) NOT NULL, PRIMARY KEY (`id`), KEY `FK_Pet_Owner` (`owner`), - KEY `FK_Pet_Vet` (`vet`), - CONSTRAINT `FK_Pet_Owner_login` FOREIGN KEY (`owner`) REFERENCES `User` (`login`) - CONSTRAINT `FK_Pet_Vet_login` FOREIGN KEY (`vet`) REFERENCES `User` (`login`) - CONSTRAINT `FK_Pet_Vaccination_id` FOREIGN KEY (`vaccination`) REFERENCES `Vaccination` (`id`) + CONSTRAINT `FK_Pet_Owner_login` FOREIGN KEY (`owner`) REFERENCES `user` (`login`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- --- Table structure for table `Pet` +-- Table structure for table `pet_vet` -- -CREATE TABLE `Vaccine` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(100) NOT NULL, - `owner` varchar(100) NOT NULL, - PRIMARY KEY (`id`), - KEY `FK_Pet_Owner` (`owner`), - CONSTRAINT `FK_Pet_Owner_login` FOREIGN KEY (`owner`) REFERENCES `User` (`login`) +CREATE TABLE `pet_vet` ( + `pet_id` int NOT NULL, + `vet_login` varchar(100) NOT NULL, + PRIMARY KEY (`pet_id`,`vet_login`), + CONSTRAINT `FK_PetVet_Pet` FOREIGN KEY (`pet_id`) REFERENCES `pet` (`id`), + CONSTRAINT `FK_PetVet_Vet` FOREIGN KEY (`vet_login`) REFERENCES `user` (`login`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- --- Table structure for table `Vaccination` +-- Table structure for table `identifier` -- -CREATE TABLE `Vaccination` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(100) NOT NULL, - `owner` varchar(100) NOT NULL, - `date` date NOT NULL, - PRIMARY KEY (`date`), - KEY `FK_Vaccination_Pet` (`pet`), - KEY `FK_Vaccination_Vaccine` (`owner`), - CONSTRAINT `FK_Vaccination_Pet_id` FOREIGN KEY (`petId`) REFERENCES `Pet` (`id`) - CONSTRAINT `FK_Vaccination_Vaccine_id` FOREIGN KEY (`vaccineId`) REFERENCES `Vaccine` (`id`) +CREATE TABLE `identifier` ( + `value` varchar(32) NOT NULL, + `type` varchar(4) NOT NULL, + `pet_id` int DEFAULT NULL, + PRIMARY KEY (`value`), + KEY `FK_Identifier_Pet` (`pet_id`), + CONSTRAINT `FK_Identifier_Pet` FOREIGN KEY (`pet_id`) REFERENCES `pet` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `vaccine` +-- +CREATE TABLE `vaccine` ( + `VACCINE_TYPE` varchar(31) NOT NULL, + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL, + `doses` int DEFAULT NULL, + `periode` int DEFAULT NULL, + `periodicType` varchar(6) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `vaccination` +-- +CREATE TABLE `vaccination` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `date` date DEFAULT NULL, + `pet_id` int DEFAULT NULL, + `vaccine_id` bigint DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `FK_Vacc_Pet` (`pet_id`), + KEY `FK_Vacc_Vaccine` (`vaccine_id`), + CONSTRAINT `FK_Vacc_Pet` FOREIGN KEY (`pet_id`) REFERENCES `pet` (`id`), + CONSTRAINT `FK_Vacc_Vaccine` FOREIGN KEY (`vaccine_id`) REFERENCES `vaccine` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Users +-- +INSERT INTO `user` (role, login, password) VALUES +('ADMIN','jose','a3f6f4b40b24e2fd61f08923ed452f34'), +('OWNER','owner1','a3f6f4b40b24e2fd61f08923ed452f34'), +('OWNER','owner2','a3f6f4b40b24e2fd61f08923ed452f34'), +('OWNER','owner3','a3f6f4b40b24e2fd61f08923ed452f34'), +('OWNER','owner4','a3f6f4b40b24e2fd61f08923ed452f34'), +('OWNER','owner5','a3f6f4b40b24e2fd61f08923ed452f34'), +('OWNER','owner6','a3f6f4b40b24e2fd61f08923ed452f34'), +('OWNER','owner7','a3f6f4b40b24e2fd61f08923ed452f34'), +('OWNER','owner8','a3f6f4b40b24e2fd61f08923ed452f34'), +('OWNER','owner9','a3f6f4b40b24e2fd61f08923ed452f34'), +('OWNER','owner10','a3f6f4b40b24e2fd61f08923ed452f34D'), +('VET','vet1','a3f6f4b40b24e2fd61f08923ed452f34'), +('VET','vet2','a3f6f4b40b24e2fd61f08923ed452f34'), +('VET','vet3','a3f6f4b40b24e2fd61f08923ed452f34'); + +-- +-- Pets +-- +INSERT INTO `pet` (animal,birth,name,owner) VALUES +('DOG','2020-01-01 12:00:00','Bobby','owner1'), +('CAT','2020-02-01 12:00:00','Mimi','owner1'), +('BIRD','2020-03-01 12:00:00','Paco','owner1'), +('DOG','2020-04-01 12:00:00','Rocky','owner2'), +('CAT','2020-05-01 12:00:00','Luna','owner2'), +('BIRD','2020-06-01 12:00:00','Kiwi','owner2'), +('DOG','2020-07-01 12:00:00','Max','owner3'), +('CAT','2020-08-01 12:00:00','Nala','owner3'), +('BIRD','2020-09-01 12:00:00','Sunny','owner3'), +('DOG','2020-10-01 12:00:00','Leo','owner4'), +('CAT','2020-11-01 12:00:00','Lola','owner4'), +('BIRD','2020-12-01 12:00:00','Tweety','owner4'), +('DOG','2021-01-01 12:00:00','Toby','owner5'), +('CAT','2021-02-01 12:00:00','Bella','owner5'), +('BIRD','2021-03-01 12:00:00','Angel','owner5'); + +-- +-- Identifiers +-- +INSERT INTO `identifier` (value,type,pet_id) VALUES +('ID00001','TAG',1), +('ID00002','CHIP',1), +('ID00003','TAG',2), +('ID00004','CHIP',2), +('ID00005','TAG',3), +('ID00006','CHIP',3), +('ID00007','TAG',4), +('ID00008','CHIP',4), +('ID00009','TAG',5), +('ID00010','CHIP',5), +('ID00011','TAG',6), +('ID00012','CHIP',6), +('ID00013','TAG',7), +('ID00014','CHIP',7), +('ID00015','TAG',8), +('ID00016','CHIP',8), +('ID00017','TAG',9), +('ID00018','CHIP',9); + + -- --- User creation +-- Pet-Vet relations -- -CREATE USER IF NOT EXISTS xcs@localhost IDENTIFIED BY 'xcs'; -GRANT ALL PRIVILEGES ON xcs.* TO xcs@localhost; -FLUSH PRIVILEGES; +INSERT INTO `pet_vet` (pet_id,vet_login) VALUES +(1,'vet1'),(2,'vet1'),(3,'vet1'), +(4,'vet2'),(5,'vet2'),(6,'vet2'), +(7,'vet3'),(8,'vet3'),(9,'vet3'); -- --- Data for table `User` +-- Vaccines -- -INSERT INTO `User` (role, login, password) VALUES - ('ADMIN','jose','a3f6f4b40b24e2fd61f08923ed452f34'), - ('OWNER','ana','22beeae33e9b2657f9610621502cd7a4'), - ('OWNER','juan','b4fbb95580592697dc71488a1f19277e'), - ('OWNER','lorena','05009e420932c21e5a68f5ef1aadd530'), - ('OWNER','pepe','b43b4d046860b2bd945bca2597bf9f07'); +INSERT INTO `vaccine` (VACCINE_TYPE,name,doses,periode,periodicType) VALUES +('MONODOSE','VacunaUno',NULL,NULL,NULL), +('MULTIDOSE','VacunaPeriodica',20,NULL,NULL), +('PERIODIC','Periodica',NULL,7,'DAYS'); -- --- Data for table `Pet` +-- Vaccinations -- -INSERT INTO `Pet` (animal, birth, name, owner) VALUES - ('CAT','2000-01-01 01:01:01','Pepecat','pepe'), - ('CAT','2000-01-01 01:01:01','Max','juan'), - ('DOG','2000-01-01 01:01:01','Juandog','juan'), - ('CAT','2000-01-01 01:01:01','Anacat','ana'), - ('DOG','2000-01-01 01:01:01','Max','ana'), - ('BIRD','2000-01-01 01:01:01','Anabird','ana'); +INSERT INTO `vaccination` (date,pet_id,vaccine_id) VALUES +('2025-10-01',1,1), +('2025-10-02',2,2), +('2025-10-03',3,3), +('2025-10-04',4,1), +('2025-10-05',5,2), +('2025-10-06',6,3), +('2025-10-07',7,1), +('2025-10-08',8,2), +('2025-10-09',9,3); diff --git a/rest/src/main/java/es/uvigo/esei/xcs/rest/AdministratorResource.java b/rest/src/main/java/es/uvigo/esei/xcs/rest/AdministratorResource.java index 40d696538d43e968f74fb9d4fe6073b7df0538ca..440a1cfce6dbdcd062c1979ce9778831df95c7d5 100644 --- a/rest/src/main/java/es/uvigo/esei/xcs/rest/AdministratorResource.java +++ b/rest/src/main/java/es/uvigo/esei/xcs/rest/AdministratorResource.java @@ -1,40 +1,52 @@ package es.uvigo.esei.xcs.rest; - import javax.ejb.EJB; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; +import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import es.uvigo.esei.xcs.service.AdministratorService; import es.uvigo.esei.xcs.service.EmailService; +/** + * REST resource for administrator operations. + * + * Provides endpoints for listing users and sending test emails. + * Accessible under the path "/admin". + * + * @author Breixo + */ @Path("admin") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public class AdministratorResource { @EJB - AdministratorService service; + private AdministratorService service; @EJB - EmailService emailService; - + private EmailService emailService; + + /** + * Returns a paginated list of users managed by the administrator. + * + * @param page index of the page (0-based) + * @param pageSize number of users per page + * @return HTTP 200 with the list of users + */ @GET public Response list(@QueryParam("page") int page, @QueryParam("pageSize") int pageSize) { return Response.ok(this.service.list(page, pageSize)).build(); } - + + /** + * Sends a test email for verification purposes. + * + * @return HTTP 200 if the email was sent successfully + */ @POST public Response sendEmail() { this.emailService.send("email@fake.email", "Topic", "Text Message"); return Response.ok().build(); } - - } diff --git a/rest/src/main/java/es/uvigo/esei/xcs/rest/OwnerResource.java b/rest/src/main/java/es/uvigo/esei/xcs/rest/OwnerResource.java index 3e5d5f6ae61ae8dba1b520b9d20b99e61ca35837..be1fc9dc386e344b6a5c4db0b0e5d3021b6c30b9 100644 --- a/rest/src/main/java/es/uvigo/esei/xcs/rest/OwnerResource.java +++ b/rest/src/main/java/es/uvigo/esei/xcs/rest/OwnerResource.java @@ -1,23 +1,10 @@ package es.uvigo.esei.xcs.rest; import java.net.URI; - - import javax.ejb.EJB; import javax.persistence.EntityExistsException; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; +import javax.ws.rs.*; +import javax.ws.rs.core.*; import es.uvigo.esei.xcs.domain.entities.IdentifierType; import es.uvigo.esei.xcs.domain.entities.Owner; @@ -27,135 +14,137 @@ import es.uvigo.esei.xcs.service.OwnerService; import static java.util.Objects.requireNonNull; /** - * Resource that represents the owners in the application. + * REST resource that manages owners and their related pets and vaccinations. + * Provides CRUD operations and pagination. * - * @author Miguel Reboiro Jato + * Accessible under the path "/owner". + * + * @author Breixo */ @Path("owner") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public class OwnerResource { + @EJB private OwnerService service; - + @Context private UriInfo uriInfo; /** - * Returns the owner identified by the login. + * Returns the owner identified by the given login. * - * @param login the login of an owner. - * @return an {@code OK} response containing the {@link Owner} with the - * provided login. - * @throws IllegalArgumentException if {@code login} is {@code null} or - * if it does not correspond with any owner. + * @param login unique login of the owner. + * @return HTTP 200 with the owner data. + * @throws IllegalArgumentException if the login is null or not found. */ @GET @Path("{login}") public Response get(@PathParam("login") String login) { if (login == null) throw new IllegalArgumentException("login can't be null"); - + final Owner owner = this.service.get(login); - if (owner == null) throw new IllegalArgumentException("Owner not found: " + login); - else - return Response.ok(owner).build(); + + return Response.ok(owner).build(); } /** - * Returns the list of owners stored in the application. + * Returns a paginated list of owners. * - * @return an {@code OK} response containing the list of owners stored in - * the application. + * @param page 0-based page index. + * @param pageSize number of results per page. + * @return HTTP 200 with the list of owners. */ @GET public Response list(@QueryParam("page") int page, @QueryParam("pageSize") int pageSize) { return Response.ok(this.service.list(page, pageSize)).build(); } - + /** - * Creates a new owner. This owner may include a list of pets, that will be - * also created. + * Creates a new owner (and optionally its pets). * - * @param ownerData a new owner to be stored. - * @return a {@code CREATED} response with the URI of the new owner in the - * {@code Location} header. - * @throws IllegalArgumentException if owner is {@code null} or if an owner - * with the same login already exists. + * @param ownerData data of the new owner. + * @return HTTP 201 with the URI of the created owner. + * @throws IllegalArgumentException if the data is null or already exists. */ @POST public Response create(OwnerCreationData ownerData) { - if (ownerData == null) { - throw new IllegalArgumentException("ownerData can't be null"); - } - + if (ownerData == null) + throw new IllegalArgumentException("ownerData can't be null"); + try { final Owner newOwner = this.service.create(ownerData.toOwner()); final URI ownerUri = uriInfo.getAbsolutePathBuilder() .path(newOwner.getLogin()) - .build(); - + .build(); return Response.created(ownerUri).build(); } catch (EntityExistsException eee) { throw new IllegalArgumentException("The owner already exists"); } } - + /** - * Updates an owner. This owner may include a list of pets, that will be - * also created or updated. If the owner does not exists it will be created. + * Updates an existing owner and its pets. * - * @param ownerData an owner to be updated. - * @return an empty {@code OK} response. - * @throws IllegalArgumentException if owner is {@code null}. + * @param login owner login. + * @param ownerData updated owner data. + * @return HTTP 200 when updated successfully. + * @throws IllegalArgumentException if login or data are null. */ - @Path("{login}") @PUT + @Path("{login}") public Response update(@PathParam("login") String login, OwnerEditionData ownerData) { requireNonNull(login, "login can't be null"); - requireNonNull(ownerData, "ownerData can't be null"); - final Owner owner = this.service.get(login); - ownerData.assignData(owner); - this.service.update(owner); - return Response.ok().build(); + requireNonNull(ownerData, "ownerData can't be null"); + + final Owner owner = this.service.get(login); + ownerData.assignData(owner); + this.service.update(owner); + return Response.ok().build(); } - + /** - * Deletes an owner. + * Deletes the owner identified by the given login. * - * @param login the login of the owner to be deleted. - * @return an empty {@code OK} response. - * @throws IllegalArgumentException if {@code login} is {@code null} or if - * it does not identifies a valid owner. + * @param login owner login. + * @return HTTP 200 when deletion succeeds. + * @throws IllegalArgumentException if login is null. */ - @Path("{login}") @DELETE + @Path("{login}") public Response delete(@PathParam("login") String login) { if (login == null) throw new IllegalArgumentException("login can't be null"); - this.service.remove(login); + this.service.remove(login); return Response.ok().build(); } - - - @Path("pet/{petIdentifierType}/{petIdentifierValue}/vaccination") + + /** + * Returns the vaccinations for a pet identified by type and value. + * + * @param petIdentifierType type of identifier. + * @param petIdentifierValue value of the identifier. + * @param page 0-based page index. + * @param pageSize number of results per page. + * @return HTTP 200 with the list of vaccinations. + */ @GET + @Path("pet/{petIdentifierType}/{petIdentifierValue}/vaccination") public Response listVaccinations( - @PathParam("petIdentifierType") IdentifierType petIdentifierType, - @PathParam("petIdentifierValue") String petIdentifierValue, - @QueryParam("page") int page, - @QueryParam("pageSize") int pageSize - ) { - + @PathParam("petIdentifierType") IdentifierType petIdentifierType, + @PathParam("petIdentifierValue") String petIdentifierValue, + @QueryParam("page") int page, + @QueryParam("pageSize") int pageSize) { + return Response.ok(this.service.getVaccinationsFromOwnPet( - //login, - petIdentifierType, - petIdentifierValue, - page, + petIdentifierType, + petIdentifierValue, + page, pageSize )).build(); } - } diff --git a/rest/src/main/java/es/uvigo/esei/xcs/rest/PetResource.java b/rest/src/main/java/es/uvigo/esei/xcs/rest/PetResource.java index bfdf4aeb97735d4488febdab33ec8cb07ed9a7f8..969bed3c478ad2ddc3737dd8177f7d25fee844e5 100644 --- a/rest/src/main/java/es/uvigo/esei/xcs/rest/PetResource.java +++ b/rest/src/main/java/es/uvigo/esei/xcs/rest/PetResource.java @@ -1,113 +1,103 @@ package es.uvigo.esei.xcs.rest; import java.net.URI; - import javax.ejb.EJB; import javax.ejb.EJBAccessException; import javax.persistence.EntityExistsException; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.DefaultValue; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; +import javax.ws.rs.*; +import javax.ws.rs.core.*; import es.uvigo.esei.xcs.domain.entities.Pet; import es.uvigo.esei.xcs.rest.entity.PetData; import es.uvigo.esei.xcs.service.PetService; /** - * Resource that represents the pets in the application. + * REST resource that manages pets in the application. + * Provides CRUD operations, pagination, and access control. + * Accessible under the path "/pet". + * + * Only the pet's owner or authorized roles can modify or delete a pet. + * Access violations throw SecurityException. * - * @author Miguel Reboiro Jato + * @author Breixo */ @Path("pet") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public class PetResource { + @EJB private PetService service; - + @Context private UriInfo uriInfo; /** - * Returns the owner identified by the login. + * Returns a pet by its identifier. * - * @param id the identified of a pet. - * @return an {@code OK} response containing the {@link Pet} with the - * provided identifier. - * @throws SecurityException if the current owner does not owns the pet. + * @param id pet ID. + * @return HTTP 200 with pet data. + * @throws SecurityException if current user is not the pet's owner. + * @throws IllegalArgumentException if pet not found. */ @Path("{id}") @GET public Response get(@PathParam("id") Long id) throws SecurityException { try { final Pet pet = this.service.get(id); - if (pet == null) throw new IllegalArgumentException("Pet not found: " + id); - else - return Response.ok(pet).build(); + return Response.ok(pet).build(); } catch (EJBAccessException eae) { throw new SecurityException(eae); } } /** - * Returns the complete list of pets of the current owner. - * - * @return an {@code OK} response containing the complete list of pets of - * the current owner. + * Returns a paginated list of all pets. + * + * @param page 0-based page index. + * @param pageSize number of results per page. + * @return HTTP 200 with list of pets. */ - @GET @Path("lista") - public Response getAll( - @QueryParam("page") @DefaultValue("0") int page, - @QueryParam("pageSize") @DefaultValue("10") int pageSize) { + public Response getAll(@QueryParam("page") @DefaultValue("0") int page, + @QueryParam("pageSize") @DefaultValue("10") int pageSize) { return Response.ok(this.service.getAll(page, pageSize)).build(); } - + + /** + * Returns a paginated list of pets owned by the current user. + * + * @param page 0-based page index. + * @param pageSize number of results per page. + * @return HTTP 200 with list of current owner's pets. + */ @GET - public Response list( - @QueryParam("page") @DefaultValue("0") int page, - @QueryParam("pageSize") @DefaultValue("10") int pageSize) { + public Response list(@QueryParam("page") @DefaultValue("0") int page, + @QueryParam("pageSize") @DefaultValue("10") int pageSize) { return Response.ok(this.service.list(page, pageSize)).build(); } - + /** - * Creates a new pet owned by the current user. + * Creates a new pet for the current user. * - * @param petData a new owner to be stored. - * @return a {@code CREATED} response with the URI of the new pet in the - * {@code Location} header. - * @throws IllegalArgumentException if pet is {@code null} or if a pet with - * the same identifier already exists. - * @throws SecurityException if the pet already has an owner and it is not - * the current user. If the pet has no owner, this exception will be never - * thrown. + * @param petData data for the new pet. + * @return HTTP 201 with Location header pointing to the new pet. + * @throws IllegalArgumentException if petData is null or pet already exists. + * @throws SecurityException if current user cannot own this pet. */ @POST public Response create(PetData petData) throws SecurityException { if (petData == null) throw new IllegalArgumentException("pet can't be null"); - + try { final Pet pet = this.service.create(petData.toPet()); - final URI petUri = uriInfo.getAbsolutePathBuilder() .path(String.valueOf(pet.getId())) - .build(); - + .build(); return Response.created(petUri).build(); } catch (EntityExistsException eee) { throw new IllegalArgumentException("The pet already exists"); @@ -115,51 +105,45 @@ public class PetResource { throw new SecurityException(eae); } } - + /** - * Updates the information of a pet. If the pet is not stored, it will be - * created. + * Updates an existing pet's data. * - * @param id the identifier of the pet to be modified. - * @param petData a pet to be updated. - * @return an empty {@code OK} response. - * @throws IllegalArgumentException if pet is {@code null} of it has no - * owner. - * @throws SecurityException if the pet's owner is not the current user. + * @param id pet ID. + * @param petData updated pet data. + * @return HTTP 200 when updated successfully. + * @throws IllegalArgumentException if petData is null or pet has no owner. + * @throws SecurityException if current user is not pet's owner. */ - @Path("{id}") + @Path("{id}") @PUT public Response update(@PathParam("id") Long id, PetData petData) throws SecurityException { if (petData == null) throw new IllegalArgumentException("pet can't be null"); - + try { - final Pet pet = this.service.get(id); - petData.assignData(pet); - + final Pet pet = this.service.get(id); + petData.assignData(pet); this.service.update(pet); - return Response.ok().build(); } catch (EJBAccessException eae) { throw new SecurityException(eae); } } - + /** - * Deletes a pet. + * Deletes a pet by its ID. * - * @param id the identifier of the pet to be deleted. - * @return an empty {@code OK} response. - * @throws IllegalArgumentException if there is no pet with the provided - * identifier. - * @throws SecurityException if the pet's owner is not the current user. + * @param id pet ID. + * @return HTTP 200 when deleted successfully. + * @throws IllegalArgumentException if pet does not exist. + * @throws SecurityException if current user is not pet's owner. */ @Path("{id}") @DELETE public Response delete(@PathParam("id") Long id) throws SecurityException { try { this.service.remove(id); - return Response.ok().build(); } catch (EJBAccessException eae) { throw new SecurityException(eae); diff --git a/rest/src/main/java/es/uvigo/esei/xcs/rest/VaccinationResource.java b/rest/src/main/java/es/uvigo/esei/xcs/rest/VaccinationResource.java index 099efc68fe347cb7b6984de1cf5cf77af2c7162a..1b59a471f34a833c8076f225000acfa132196fd7 100644 --- a/rest/src/main/java/es/uvigo/esei/xcs/rest/VaccinationResource.java +++ b/rest/src/main/java/es/uvigo/esei/xcs/rest/VaccinationResource.java @@ -3,21 +3,21 @@ package es.uvigo.esei.xcs.rest; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; - import javax.ejb.EJB; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; +import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import es.uvigo.esei.xcs.domain.entities.Vaccination; import es.uvigo.esei.xcs.service.VaccinationService; +/** + * REST resource for managing pet vaccinations. + * Provides endpoints to check if a vaccination can be applied and to create vaccinations. + * Accessible under the path "/vaccination". + * + * @author Breixo + */ @Path("vaccination") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @@ -26,32 +26,43 @@ public class VaccinationResource { @EJB private VaccinationService vaccinationService; + /** + * Checks if a pet can be vaccinated with a specific vaccine today. + * + * @param petId the ID of the pet. + * @param vaccineId the ID of the vaccine. + * @return HTTP 200 with a boolean indicating if vaccination is allowed. + */ @GET @Path("canVaccinate/{petId}/{vaccineId}") - public Response canVaccinate( - @PathParam("petId") Long petId, - @PathParam("vaccineId") Long vaccineId - ) { + public Response canVaccinate(@PathParam("petId") Long petId, + @PathParam("vaccineId") Long vaccineId) { Date now = new Date(); Boolean result = vaccinationService.canVaccinate(petId, vaccineId, now); return Response.ok(result).build(); } - - + + /** + * Creates a vaccination for a pet with a given vaccine. + * + * @param petId the ID of the pet. + * @param vaccineId the ID of the vaccine. + * @param textDate optional date in yyyy-MM-dd format. Defaults to today if null. + * @return HTTP 200 with the created Vaccination, or HTTP 400 if invalid input. + */ @POST @Path("create/{petId}/{vaccineId}") - public Response createVaccination( - @PathParam("petId") Long petId, - @PathParam("vaccineId") Long vaccineId, - @QueryParam("date") String textDate - ) { + public Response createVaccination(@PathParam("petId") Long petId, + @PathParam("vaccineId") Long vaccineId, + @QueryParam("date") String textDate) { Date date = new Date(); if (textDate != null) { try { date = new SimpleDateFormat("yyyy-MM-dd").parse(textDate); } catch (ParseException e) { return Response.status(Response.Status.BAD_REQUEST) - .entity("Invalid date format, expected yyyy-MM-dd").build(); + .entity("Invalid date format, expected yyyy-MM-dd") + .build(); } } @@ -60,8 +71,8 @@ public class VaccinationResource { return Response.ok(vaccination).build(); } catch (IllegalArgumentException e) { return Response.status(Response.Status.BAD_REQUEST) - .entity(e.getMessage()).build(); + .entity(e.getMessage()) + .build(); } } - } diff --git a/rest/src/main/java/es/uvigo/esei/xcs/rest/VaccineResource.java b/rest/src/main/java/es/uvigo/esei/xcs/rest/VaccineResource.java index e38b5511d1b9f46987998a8f978d37bb29eaea66..d4af229b06731d0a07ce1ee4a55e0443f9eede19 100644 --- a/rest/src/main/java/es/uvigo/esei/xcs/rest/VaccineResource.java +++ b/rest/src/main/java/es/uvigo/esei/xcs/rest/VaccineResource.java @@ -1,7 +1,6 @@ package es.uvigo.esei.xcs.rest; import static java.util.Objects.requireNonNull; - import java.net.URI; import javax.ejb.EJB; import javax.ws.rs.*; @@ -12,6 +11,10 @@ import es.uvigo.esei.xcs.rest.entity.VaccineCreationData; import es.uvigo.esei.xcs.rest.entity.VaccineEditionData; import es.uvigo.esei.xcs.service.VaccineService; +/** + * REST resource for managing vaccines. + * Provides endpoints to list, create, update, and delete vaccines. + */ @Path("vaccine") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @@ -23,12 +26,26 @@ public class VaccineResource { @Context private UriInfo uriInfo; + /** + * Returns a paginated list of vaccines. + * + * @param page 0-based page index. + * @param pageSize number of items per page. + * @return HTTP 200 with the list of vaccines. + */ @GET public Response list(@QueryParam("page") @DefaultValue("0") int page, @QueryParam("pageSize") @DefaultValue("10") int pageSize) { return Response.ok(vaccineService.list(page, pageSize)).build(); } + /** + * Creates a new vaccine. + * + * @param vaccineData data to create the vaccine. + * @return HTTP 201 with the URI of the created vaccine. + * @throws IllegalArgumentException if vaccineData is null. + */ @POST public Response create(VaccineCreationData vaccineData) { requireNonNull(vaccineData, "vaccineData can't be null"); @@ -42,7 +59,15 @@ public class VaccineResource { URI uri = uriInfo.getAbsolutePathBuilder().path(String.valueOf(vaccine.getId())).build(); return Response.created(uri).build(); } - + + /** + * Updates only the name of an existing vaccine. + * + * @param id vaccine ID. + * @param newName new name for the vaccine. + * @return HTTP 200 with the updated vaccine. + * @throws IllegalArgumentException if newName is null. + */ @PUT @Path("{id}/name") public Response updateName(@PathParam("id") Long id, String newName) { @@ -51,7 +76,14 @@ public class VaccineResource { return Response.ok(updated).build(); } - + /** + * Updates all editable fields of an existing vaccine. + * + * @param id vaccine ID. + * @param vaccineData data to update. + * @return HTTP 200 when updated successfully. + * @throws IllegalArgumentException if vaccineData is null. + */ @PUT @Path("{id}") public Response update(@PathParam("id") Long id, VaccineEditionData vaccineData) { @@ -62,6 +94,13 @@ public class VaccineResource { return Response.ok().build(); } + /** + * Deletes a vaccine by its ID. + * + * @param id vaccine ID. + * @return HTTP 200 when deleted successfully. + * @throws IllegalArgumentException if vaccine does not exist. + */ @DELETE @Path("{id}") public Response delete(@PathParam("id") Long id) { diff --git a/rest/src/main/java/es/uvigo/esei/xcs/rest/VetResource.java b/rest/src/main/java/es/uvigo/esei/xcs/rest/VetResource.java index ade0b5d42d02cc4e8b4240388b652a30226a2bde..38f3edbe5752f57d417f3ce22800e02b87493bc7 100644 --- a/rest/src/main/java/es/uvigo/esei/xcs/rest/VetResource.java +++ b/rest/src/main/java/es/uvigo/esei/xcs/rest/VetResource.java @@ -1,26 +1,12 @@ package es.uvigo.esei.xcs.rest; import static java.util.Objects.requireNonNull; - import java.net.URI; import java.util.Date; - import javax.ejb.EJB; import javax.ejb.EJBAccessException; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.DefaultValue; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; +import javax.ws.rs.*; +import javax.ws.rs.core.*; import es.uvigo.esei.xcs.domain.entities.IdentifierType; import es.uvigo.esei.xcs.domain.entities.Vaccination; @@ -39,201 +25,265 @@ import es.uvigo.esei.xcs.service.VetService; @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public class VetResource { - @EJB - private VetService vetService; - - @EJB - private PetService petService; - - @EJB - private VaccineService vaccineService; - - @EJB - private VaccinationService vaccinationService; - - @Context - private UriInfo uriInfo; - - @GET - @Path("{login}") - public Response get(@PathParam("login") String login) { - - return Response.ok(vetService.get(login)).build(); - } - - @GET - public Response list() { - - return Response.ok(vetService.list()).build(); - } - - @POST - public Response create(VetData vetData) { - requireNonNull(vetData); - - try { - final Vet vet = this.vetService.create(vetData.toVet()); - - final URI vetUri = uriInfo.getAbsolutePathBuilder() - .path(vet.getLogin()).build(); - - return Response.created(vetUri).build(); - } catch (Exception e) { - throw new SecurityException(e); - } - } - - - @Path("{login}") - @DELETE - public Response delete(@PathParam("login") String login) { - try { - this.vetService.remove(login); - - return Response.ok().build(); - } catch (EJBAccessException e) { - throw new SecurityException(e); - } - - } - - @GET - @Path("pets") - public Response listPets( - @QueryParam("page") @DefaultValue("0") int page, - @QueryParam("pageSize") @DefaultValue("10") int pageSize - ) { - return Response.ok(this.vetService.getPets(page, pageSize)).build(); - } - - - @GET - @Path("pets/{petId}") - public Response getPet(@PathParam("petId") Long petId) { - return Response.ok(this.petService.get(petId)).build(); - } - - - @GET - @Path("vaccine") - public Response listVaccines(@QueryParam("page") int page, @QueryParam("pageSize") int pageSize) { - return Response.ok(this.vaccineService.list(page, pageSize)).build(); - } - - - @POST - @Path("vaccine") - public Response createVaccine(VaccineCreationData vaccineData) { - Vaccine vaccine = this.vaccineService.create( - vaccineData.getName(), - vaccineData.getType(), - vaccineData.getDoses(), - vaccineData.getPeriodicType(), - vaccineData.getPeriode() - ); - return Response.ok(vaccine).build(); - - } - - @Path("vaccine/{id}") - @PUT - public Response updateVaccine(@PathParam("id") Long id, VaccineEditionData vaccineData) { - if (vaccineData == null) { - throw new IllegalArgumentException("vaccineData can't be null"); - } - final Vaccine vaccine = this.vaccineService.get(id); - vaccineData.assignData(vaccine); - this.vaccineService.update(vaccine); - return Response.ok().build(); - } - - @Path("vaccine/{id}") - @DELETE - public Response deleteVaccine(@PathParam("id") Long id) { - try { - this.vaccineService.remove(id); - return Response.ok().build(); - } catch (EJBAccessException e) { - throw new SecurityException(e); - } - } - - @Path("pet/{petIdentifierType}/{petIdentifierValue}/vaccination") - @GET - public Response listVaccinations( - @PathParam("petIdentifierType") IdentifierType petIdentifierType, - @PathParam("petIdentifierValue") String petIdentifierValue, - @QueryParam("page") int page, - @QueryParam("pageSize") int pageSize - ) { - - return Response.ok(this.vetService.getVaccinationsFromOwnPet( - //login, - petIdentifierType, - petIdentifierValue, - page, - pageSize - )).build(); - } - - @Path("vaccination") - @POST - public Response registerVaccination( - @QueryParam("date") Date date, - VaccinationCreationData vaccinationData - ) { - if (date == null) { - date = new Date(); - } - Vaccination vaccination = this.vaccinationService.create( - vaccinationData.getPetId(), - vaccinationData.getVaccineId(), - date - ); - - final URI vaccinationUri = uriInfo.getAbsolutePathBuilder() - .path(String.valueOf(vaccination.getId())).build(); - - return Response.created(vaccinationUri).build(); - } - - - @POST - @Path("/assign/pets/{petId}") - public Response assignVetToPet( - @PathParam("petId") Long petId - ) { - requireNonNull(petId, "petId can't be null"); - - try { - petService.assignVetToPet(petId); - return Response.ok() - .build(); - } catch (IllegalArgumentException e) { - return Response.status(Response.Status.NOT_FOUND) - .entity(e.getMessage()) - .build(); - } - } - - @DELETE - @Path("{login}/unassign/pets/{petId}") - public Response unassignVetFromPet( - @PathParam("petId") Long petId - ) { - requireNonNull(petId, "petId can't be null"); - - try { - petService.unassignVetFromPet(petId); - return Response.ok() - .build(); - } catch (IllegalArgumentException e) { - return Response.status(Response.Status.NOT_FOUND) - .entity(e.getMessage()) - .build(); - } - } - - - + @EJB + private VetService vetService; + + @EJB + private PetService petService; + + @EJB + private VaccineService vaccineService; + + @EJB + private VaccinationService vaccinationService; + + @Context + private UriInfo uriInfo; + + /** + * Returns a vet by login. + * + * @param login vet login. + * @return HTTP 200 with the vet. + */ + @GET + @Path("{login}") + public Response get(@PathParam("login") String login) { + return Response.ok(vetService.get(login)).build(); + } + + /** + * Returns the list of all vets. + * + * @return HTTP 200 with the list of vets. + */ + @GET + public Response list() { + return Response.ok(vetService.list()).build(); + } + + /** + * Creates a new vet. + * + * @param vetData data of the vet to create. + * @return HTTP 201 with the URI of the created vet. + * @throws SecurityException if creation fails. + */ + @POST + public Response create(VetData vetData) { + requireNonNull(vetData, "vetData can't be null"); + + try { + final Vet vet = this.vetService.create(vetData.toVet()); + final URI vetUri = uriInfo.getAbsolutePathBuilder() + .path(vet.getLogin()).build(); + return Response.created(vetUri).build(); + } catch (Exception e) { + throw new SecurityException(e); + } + } + + /** + * Deletes a vet by login. + * + * @param login vet login. + * @return HTTP 200 when deleted successfully. + * @throws SecurityException if deletion fails due to access control. + */ + @Path("{login}") + @DELETE + public Response delete(@PathParam("login") String login) { + try { + this.vetService.remove(login); + return Response.ok().build(); + } catch (EJBAccessException e) { + throw new SecurityException(e); + } + } + + /** + * Returns a paginated list of pets for the current vet. + * + * @param page 0-based page index. + * @param pageSize number of pets per page. + * @return HTTP 200 with the list of pets. + */ + @GET + @Path("pets") + public Response listPets(@QueryParam("page") @DefaultValue("0") int page, + @QueryParam("pageSize") @DefaultValue("10") int pageSize) { + return Response.ok(this.vetService.getPets(page, pageSize)).build(); + } + + /** + * Returns a specific pet by ID. + * + * @param petId pet ID. + * @return HTTP 200 with the pet. + */ + @GET + @Path("pets/{petId}") + public Response getPet(@PathParam("petId") Long petId) { + return Response.ok(this.petService.get(petId)).build(); + } + + /** + * Returns a paginated list of vaccines. + * + * @param page 0-based page index. + * @param pageSize number of vaccines per page. + * @return HTTP 200 with the list of vaccines. + */ + @GET + @Path("vaccine") + public Response listVaccines(@QueryParam("page") int page, + @QueryParam("pageSize") int pageSize) { + return Response.ok(this.vaccineService.list(page, pageSize)).build(); + } + + /** + * Creates a new vaccine. + * + * @param vaccineData data to create the vaccine. + * @return HTTP 200 with the created vaccine. + */ + @POST + @Path("vaccine") + public Response createVaccine(VaccineCreationData vaccineData) { + Vaccine vaccine = this.vaccineService.create( + vaccineData.getName(), + vaccineData.getType(), + vaccineData.getDoses(), + vaccineData.getPeriodicType(), + vaccineData.getPeriode() + ); + return Response.ok(vaccine).build(); + } + + /** + * Updates a vaccine. + * + * @param id vaccine ID. + * @param vaccineData data to update the vaccine. + * @return HTTP 200 when updated successfully. + * @throws IllegalArgumentException if vaccineData is null. + */ + @Path("vaccine/{id}") + @PUT + public Response updateVaccine(@PathParam("id") Long id, VaccineEditionData vaccineData) { + requireNonNull(vaccineData, "vaccineData can't be null"); + final Vaccine vaccine = this.vaccineService.get(id); + vaccineData.assignData(vaccine); + this.vaccineService.update(vaccine); + return Response.ok().build(); + } + + /** + * Deletes a vaccine by ID. + * + * @param id vaccine ID. + * @return HTTP 200 when deleted successfully. + * @throws SecurityException if deletion fails due to access control. + */ + @Path("vaccine/{id}") + @DELETE + public Response deleteVaccine(@PathParam("id") Long id) { + try { + this.vaccineService.remove(id); + return Response.ok().build(); + } catch (EJBAccessException e) { + throw new SecurityException(e); + } + } + + /** + * Returns paginated list of vaccinations of a pet owned by the current vet. + * + * @param petIdentifierType type of the pet's identifier. + * @param petIdentifierValue value of the pet's identifier. + * @param page 0-based page index. + * @param pageSize number of vaccinations per page. + * @return HTTP 200 with the list of vaccinations. + */ + @Path("pet/{petIdentifierType}/{petIdentifierValue}/vaccination") + @GET + public Response listVaccinations(@PathParam("petIdentifierType") IdentifierType petIdentifierType, + @PathParam("petIdentifierValue") String petIdentifierValue, + @QueryParam("page") int page, + @QueryParam("pageSize") int pageSize) { + return Response.ok(this.vetService.getVaccinationsFromOwnPet( + petIdentifierType, + petIdentifierValue, + page, + pageSize + )).build(); + } + + /** + * Registers a new vaccination for a pet. + * + * @param date date of vaccination, if null current date is used. + * @param vaccinationData data for the vaccination. + * @return HTTP 201 with the URI of the created vaccination. + */ + @Path("vaccination") + @POST + public Response registerVaccination(@QueryParam("date") Date date, + VaccinationCreationData vaccinationData) { + if (date == null) { + date = new Date(); + } + Vaccination vaccination = this.vaccinationService.create( + vaccinationData.getPetId(), + vaccinationData.getVaccineId(), + date + ); + final URI vaccinationUri = uriInfo.getAbsolutePathBuilder() + .path(String.valueOf(vaccination.getId())).build(); + return Response.created(vaccinationUri).build(); + } + + /** + * Assigns the current vet to a pet. + * + * @param petId pet ID. + * @return HTTP 200 when assigned successfully. + * @throws IllegalArgumentException if petId is null or pet not found. + */ + @POST + @Path("/assign/pets/{petId}") + public Response assignVetToPet(@PathParam("petId") Long petId) { + requireNonNull(petId, "petId can't be null"); + + try { + petService.assignVetToPet(petId); + return Response.ok().build(); + } catch (IllegalArgumentException e) { + return Response.status(Response.Status.NOT_FOUND) + .entity(e.getMessage()) + .build(); + } + } + + /** + * Unassigns the current vet from a pet. + * + * @param petId pet ID. + * @return HTTP 200 when unassigned successfully. + * @throws IllegalArgumentException if petId is null or pet not found. + */ + @DELETE + @Path("{login}/unassign/pets/{petId}") + public Response unassignVetFromPet(@PathParam("petId") Long petId) { + requireNonNull(petId, "petId can't be null"); + + try { + petService.unassignVetFromPet(petId); + return Response.ok().build(); + } catch (IllegalArgumentException e) { + return Response.status(Response.Status.NOT_FOUND) + .entity(e.getMessage()) + .build(); + } + } } diff --git a/service/src/main/java/es/uvigo/esei/xcs/service/AdministratorService.java b/service/src/main/java/es/uvigo/esei/xcs/service/AdministratorService.java index ee3558b6c26391d308759f031d37ec20b1b748f8..f20bb2b3c9bfd94e728acec3bbd59204a21b2c71 100644 --- a/service/src/main/java/es/uvigo/esei/xcs/service/AdministratorService.java +++ b/service/src/main/java/es/uvigo/esei/xcs/service/AdministratorService.java @@ -1,6 +1,5 @@ package es.uvigo.esei.xcs.service; - import static java.util.Objects.requireNonNull; import java.util.List; @@ -12,49 +11,62 @@ import javax.persistence.PersistenceContext; import es.uvigo.esei.xcs.domain.entities.Administrator; import es.uvigo.esei.xcs.domain.entities.User; +/** + * EJB for managing Administrator entities. + * Provides CRUD operations and paginated user listing. + * + * Accessible only to ADMIN users. + * + * @author Breixo Senra + */ @Stateless @RolesAllowed("ADMIN") public class AdministratorService { - @PersistenceContext - EntityManager em; - - - public Administrator get(int id) { - return em.find(Administrator.class, id); - } - - - public List list(int page, int pageSize){ - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return em.createQuery("SELECT DISTINCT u FROM User u", User.class) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .getResultList(); - - } - - - public Administrator create(Administrator administrator) { - requireNonNull(Administrator.class, "Administrator can't be null"); - em.persist(administrator); - - return administrator; - } - - - public Administrator update(Administrator administrator) { - requireNonNull(Administrator.class, "Administrator can't be null"); - return em.merge(administrator); - } - - - public void remove(int id) { - em.remove(this.get(id)); - } - + + @PersistenceContext + private EntityManager em; + + /** + * Returns an administrator by its ID. + */ + public Administrator get(int id) { + return em.find(Administrator.class, id); + } + + /** + * Returns a paginated list of all users. + */ + public List list(int page, int pageSize) { + if (page < 0) throw new IllegalArgumentException("The page can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero"); + + return em.createQuery("SELECT DISTINCT u FROM User u", User.class) + .setFirstResult(page * pageSize) + .setMaxResults(pageSize) + .getResultList(); + } + + /** + * Persists a new administrator entity. + */ + public Administrator create(Administrator administrator) { + requireNonNull(administrator, "Administrator can't be null"); + em.persist(administrator); + return administrator; + } + + /** + * Updates an existing administrator. + */ + public Administrator update(Administrator administrator) { + requireNonNull(administrator, "Administrator can't be null"); + return em.merge(administrator); + } + + /** + * Removes an administrator by ID. + */ + public void remove(int id) { + em.remove(this.get(id)); + } } diff --git a/service/src/main/java/es/uvigo/esei/xcs/service/CounterService.java b/service/src/main/java/es/uvigo/esei/xcs/service/CounterService.java index 9748faa745bd97647f580d2c74cb2351ff3a94f8..5ea1359c5ce6112581853e4516843abb4d61cc78 100644 --- a/service/src/main/java/es/uvigo/esei/xcs/service/CounterService.java +++ b/service/src/main/java/es/uvigo/esei/xcs/service/CounterService.java @@ -7,46 +7,64 @@ import javax.ejb.Singleton; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; +/** + * Singleton EJB that maintains counters for pets and vaccines. + * + * Counts are initialized from the database and kept in memory. + * Thread-safe access is ensured through read/write locks. + * + * @author Breixo + */ @Singleton public class CounterService { @PersistenceContext - EntityManager em; + private EntityManager em; private Long vaccineCounter; private Long petCounter; - + + /** + * Initializes counters with the current counts from the database. + */ @PostConstruct public void init() { - this.petCounter = em - .createQuery("SELECT COUNT(p) FROM Pet p", Long.class) - .getSingleResult(); - - this.vaccineCounter = em - .createQuery("SELECT COUNT(v) FROM Vaccine v", Long.class) - .getSingleResult(); + this.petCounter = em.createQuery("SELECT COUNT(p) FROM Pet p", Long.class) + .getSingleResult(); + this.vaccineCounter = em.createQuery("SELECT COUNT(v) FROM Vaccine v", Long.class) + .getSingleResult(); } + /** + * Increments the pet counter by one. + */ @Lock(LockType.WRITE) public void incrementPetCounter() { this.petCounter++; } - + + /** + * Increments the vaccine counter by one. + */ @Lock(LockType.WRITE) public void incrementVaccineCounter() { this.vaccineCounter++; } - + + /** + * Returns the current pet counter value. + */ @Lock(LockType.READ) public Long getPetCounter() { return this.petCounter; } - + + /** + * Returns the current vaccine counter value. + */ @Lock(LockType.READ) public Long getVaccineCounter() { return this.vaccineCounter; } - - } diff --git a/service/src/main/java/es/uvigo/esei/xcs/service/IdentifierService.java b/service/src/main/java/es/uvigo/esei/xcs/service/IdentifierService.java index 5a9fb316926f9959dc75a5f321c7cfd4d48db3c0..21fe4e9e0c39348be5b8f5982faa8c5589257933 100644 --- a/service/src/main/java/es/uvigo/esei/xcs/service/IdentifierService.java +++ b/service/src/main/java/es/uvigo/esei/xcs/service/IdentifierService.java @@ -7,21 +7,40 @@ import javax.persistence.PersistenceContext; import es.uvigo.esei.xcs.domain.entities.Identifier; import static java.util.Objects.requireNonNull; +/** + * EJB for managing Identifier entities. + * Provides basic operations for creation and removal. + * + * @author Breixo Senra + */ @Stateless public class IdentifierService { - @PersistenceContext - EntityManager em; - - - public Identifier create(Identifier identifier) { - requireNonNull(identifier, "Identifier can't be null"); - em.persist(identifier); - return identifier; - } - - public void remove(String value) { - Identifier identifier = em.find(Identifier.class, value); - em.remove(identifier); - } - + + @PersistenceContext + private EntityManager em; + + /** + * Persists a new identifier. + * + * @param identifier the Identifier entity to persist. + * @return the persisted Identifier entity. + * @throws NullPointerException if {@code identifier} is null. + */ + public Identifier create(Identifier identifier) { + requireNonNull(identifier, "Identifier can't be null"); + em.persist(identifier); + return identifier; + } + + /** + * Removes an identifier by its value. + * + * @param value the identifier value. + */ + public void remove(String value) { + Identifier identifier = em.find(Identifier.class, value); + if (identifier != null) { + em.remove(identifier); + } + } } diff --git a/service/src/main/java/es/uvigo/esei/xcs/service/OwnerService.java b/service/src/main/java/es/uvigo/esei/xcs/service/OwnerService.java index 2b7b847a42ae07841f949af033a17f504216d855..bb3592fb7f80770859590ebfcd2c4f7d3d012ca4 100644 --- a/service/src/main/java/es/uvigo/esei/xcs/service/OwnerService.java +++ b/service/src/main/java/es/uvigo/esei/xcs/service/OwnerService.java @@ -5,7 +5,6 @@ import static java.util.Objects.requireNonNull; import java.security.Principal; import java.util.List; -import javax.annotation.security.PermitAll; import javax.annotation.security.RolesAllowed; import javax.ejb.Stateless; import javax.inject.Inject; @@ -13,183 +12,179 @@ import javax.persistence.EntityExistsException; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; -import es.uvigo.esei.xcs.domain.entities.Identifier; import es.uvigo.esei.xcs.domain.entities.IdentifierType; import es.uvigo.esei.xcs.domain.entities.Owner; import es.uvigo.esei.xcs.domain.entities.Pet; import es.uvigo.esei.xcs.domain.entities.Vaccination; /** - * EJB for the Owners. Only administrators have access to this class. + * EJB for managing Owners and their pets. Access is restricted to ADMIN and OWNER roles. * - * @author Miguel Reboiro Jato + * @author Breixo Senra */ @Stateless @RolesAllowed({"ADMIN", "OWNER"}) public class OwnerService { - @PersistenceContext - private EntityManager em; - - @Inject - private Principal currentUser; - - - public int countAll() { - Long count = em.createQuery("SELECT COUNT(o) FROM Owner o", Long.class) - .getSingleResult(); - return count.intValue(); - } - - - /** - * Returns the owner identified by {@code login}. If there is no owner with - * the specified login, {@code null} will be returned. - * - * @param login the login of an owner. - * @return the owner with the provided login or {@code null} if there is no - * owner with the specified login. - * @throws IllegalArgumentException if {@code login} is {@code null} or it - * does not identifies a valid owner. - */ - public Owner get(String login) { - return em.find(Owner.class, login); - } - - /** - * Returns the complete list of owners. - * - * @return the complete list of owners. - */ - public List list(int first, int pageSize) { - if (first < 0) throw new IllegalArgumentException("First can't be negative"); - if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); - - return em.createQuery("SELECT o FROM Owner o", Owner.class) - .setFirstResult(first) - .setMaxResults(pageSize) - .getResultList(); - } - - /** - * Returns the list of owners that have a pet with the specified name. - * - * @param petName a pet's name. - * @return the list of owners that have a pet with the specified name. The - * list may be empty if any owner has a pet with the specified name. - * @throws IllegalArgumentException if {@code petName} is {@code null}. - */ - public List findByPetName(String petName) { - if (petName == null) - throw new IllegalArgumentException("petName can't be null"); - - final String query = "SELECT o FROM Owner o JOIN o.pets p " + - "WHERE p.name = :petName"; - - return em.createQuery(query, Owner.class) - .setParameter("petName", petName) - .getResultList(); - } - - /** - * Creates a new owner. If the owner already has pets, they will be created - * too. - * - * @param owner a new owner to be stored. - * @return the persistent version of the owner created. - * @throws IllegalArgumentException if {@code owner} is {@code null}. - * @throws EntityExistsException if an owner with the same login already - * exists. - */ - public Owner create(Owner owner) { - if (owner == null) - throw new IllegalArgumentException("owner can't be null"); - - this.em.persist(owner); - - return owner; - } - - /** - * Updates a new owner. If the owner is not stored, it will be persisted. - * - * @param owner an owner to be updated. - * @return the updated owner. - * @throws IllegalArgumentException if {@code owner} is {@code null}. - */ - public Owner update(Owner owner) { - if (owner == null) - throw new IllegalArgumentException("owner can't be null"); - - return em.merge(owner); - } - - /** - * Deletes an owner. - * - * @param login the login of the owner to be deleted. - * @throws IllegalArgumentException if {@code login} is {@code null} or if - * it does not identifies a valid owner. - */ - public void remove(String login) { - Owner owner = this.get(login); - em.remove(owner); - } - - /** - * Returns the list of pets of an owner. - * - * @param login the login of the owner that owns the pets. - * @return the list of pets of an owner. - * @throws IllegalArgumentException if {@code login} is {@code null} or it - * does not identifies a valid owner. - */ - public List getPets(String login, int first, int pageSize) { - if (first < 0) throw new IllegalArgumentException("First can't be negative"); - if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); - - return em.createQuery("SELECT p FROM Owner o " - + "JOIN o.pets p " - + "WHERE " - + "o.login = :login", - Pet.class) - .setFirstResult(first) - .setMaxResults(pageSize) - .setParameter("login", login) - .getResultList(); - } - - - public List getVaccinationsFromOwnPet( - IdentifierType identifierType, - String identifierValue, - int page, - int pageSize - ){ - requireNonNull(identifierType, "pet's identifier type can't be null"); - requireNonNull(identifierValue, "pet's identifier value can't be null"); - - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return em.createQuery( - "SELECT v FROM Owner o " - + "JOIN o.pets p " - + "JOIN p.identifiers i " - + "JOIN p.vaccinations v " - + "WHERE " - + "o.login = :login AND " - + "i.type = :identifierType AND " - + "i.value = :identifierValue", - Vaccination.class) - .setParameter("login", currentUser.getName()) - .setParameter("identifierType", identifierType) - .setParameter("identifierValue", identifierValue) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .getResultList(); - } - + + @PersistenceContext + private EntityManager em; + + @Inject + private Principal currentUser; + + /** + * Counts all owners in the system. + * + * @return the total number of owners. + */ + public int countAll() { + Long count = em.createQuery("SELECT COUNT(o) FROM Owner o", Long.class) + .getSingleResult(); + return count.intValue(); + } + + /** + * Returns the owner identified by {@code login}. + * + * @param login the login of an owner. + * @return the owner with the provided login or {@code null} if not found. + * @throws IllegalArgumentException if {@code login} is {@code null}. + */ + public Owner get(String login) { + return em.find(Owner.class, login); + } + + /** + * Returns a paginated list of owners. + * + * @param first the starting index (0-based) of the first owner. + * @param pageSize the maximum number of owners to return. + * @return the list of owners in the specified page. + * @throws IllegalArgumentException if {@code first} is negative or {@code pageSize} is not positive. + */ + public List list(int first, int pageSize) { + if (first < 0) throw new IllegalArgumentException("First can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); + + return em.createQuery("SELECT o FROM Owner o", Owner.class) + .setFirstResult(first) + .setMaxResults(pageSize) + .getResultList(); + } + + /** + * Returns the list of owners that have a pet with the specified name. + * + * @param petName the name of the pet. + * @return the list of owners with a pet matching the name. + * @throws IllegalArgumentException if {@code petName} is {@code null}. + */ + public List findByPetName(String petName) { + if (petName == null) + throw new IllegalArgumentException("petName can't be null"); + + final String query = "SELECT o FROM Owner o JOIN o.pets p WHERE p.name = :petName"; + return em.createQuery(query, Owner.class) + .setParameter("petName", petName) + .getResultList(); + } + + /** + * Creates a new owner along with any pets associated. + * + * @param owner the owner to create. + * @return the persistent version of the created owner. + * @throws IllegalArgumentException if {@code owner} is {@code null}. + * @throws EntityExistsException if an owner with the same login already exists. + */ + public Owner create(Owner owner) { + if (owner == null) + throw new IllegalArgumentException("owner can't be null"); + + this.em.persist(owner); + return owner; + } + + /** + * Updates an existing owner. If the owner does not exist, it will be persisted. + * + * @param owner the owner to update. + * @return the updated owner. + * @throws IllegalArgumentException if {@code owner} is {@code null}. + */ + public Owner update(Owner owner) { + if (owner == null) + throw new IllegalArgumentException("owner can't be null"); + + return em.merge(owner); + } + + /** + * Deletes an owner by login. + * + * @param login the login of the owner to delete. + * @throws IllegalArgumentException if {@code login} is {@code null}. + */ + public void remove(String login) { + Owner owner = this.get(login); + em.remove(owner); + } + + /** + * Returns a paginated list of pets of the specified owner. + * + * @param login the login of the owner. + * @param first the starting index (0-based). + * @param pageSize the maximum number of pets to return. + * @return the list of pets for the owner. + * @throws IllegalArgumentException if {@code login} is {@code null}, {@code first} is negative, or {@code pageSize} is not positive. + */ + public List getPets(String login, int first, int pageSize) { + if (first < 0) throw new IllegalArgumentException("First can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); + + return em.createQuery("SELECT p FROM Owner o JOIN o.pets p WHERE o.login = :login", Pet.class) + .setFirstResult(first) + .setMaxResults(pageSize) + .setParameter("login", login) + .getResultList(); + } + + /** + * Returns a paginated list of vaccinations for a pet of the current user, identified by an identifier type and value. + * + * @param identifierType the type of the pet's identifier. + * @param identifierValue the value of the pet's identifier. + * @param page the 0-based page index. + * @param pageSize the maximum number of vaccinations per page. + * @return the list of vaccinations. + * @throws NullPointerException if {@code identifierType} or {@code identifierValue} is {@code null}. + * @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive. + */ + public List getVaccinationsFromOwnPet( + IdentifierType identifierType, + String identifierValue, + int page, + int pageSize + ) { + requireNonNull(identifierType, "pet's identifier type can't be null"); + requireNonNull(identifierValue, "pet's identifier value can't be null"); + + if (page < 0) throw new IllegalArgumentException("The page can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero"); + + return em.createQuery( + "SELECT v FROM Owner o " + + "JOIN o.pets p " + + "JOIN p.identifiers i " + + "JOIN p.vaccinations v " + + "WHERE o.login = :login AND i.type = :identifierType AND i.value = :identifierValue", + Vaccination.class) + .setParameter("login", currentUser.getName()) + .setParameter("identifierType", identifierType) + .setParameter("identifierValue", identifierValue) + .setFirstResult(page * pageSize) + .setMaxResults(pageSize) + .getResultList(); + } } diff --git a/service/src/main/java/es/uvigo/esei/xcs/service/PetService.java b/service/src/main/java/es/uvigo/esei/xcs/service/PetService.java index 924e818fbcb7abdd4118ac243688ef1c777bd780..8cc366162379bed35168c9f8668decee6fdfcbde 100644 --- a/service/src/main/java/es/uvigo/esei/xcs/service/PetService.java +++ b/service/src/main/java/es/uvigo/esei/xcs/service/PetService.java @@ -2,12 +2,10 @@ package es.uvigo.esei.xcs.service; import static java.util.Objects.requireNonNull; -import java.io.Console; import java.security.Principal; import java.util.Date; import java.util.List; -import javax.annotation.security.PermitAll; import javax.annotation.security.RolesAllowed; import javax.ejb.EJB; import javax.ejb.EJBAccessException; @@ -19,242 +17,245 @@ import javax.persistence.PersistenceContext; import es.uvigo.esei.xcs.domain.entities.AnimalType; import es.uvigo.esei.xcs.domain.entities.Owner; import es.uvigo.esei.xcs.domain.entities.Pet; -import es.uvigo.esei.xcs.domain.entities.Vaccination; import es.uvigo.esei.xcs.domain.entities.Vaccine; import es.uvigo.esei.xcs.domain.entities.Vet; /** - * EJB for the Pets. Only owners have access to this class, and only to their - * own pets. + * EJB for managing Pets. Access is restricted to VET and OWNER roles. + * Owners can only access their own pets. * - * @author Miguel Reboiro Jato + * @author Breixo Senra */ @Stateless @RolesAllowed({"VET", "OWNER"}) public class PetService { - @Inject - private Principal currentUser; - - @EJB - private EmailService emailService; - - @PersistenceContext - private EntityManager em; - - /** - * Returns a pet identified by the provided id. If an owner tries to access - * a pet that does now own, an {@link EJBAccessException} will be thrown. - * - * @param id the identified of a pet. - * @return a pet identified by the provided identifier or {@code null} if no - * pet exists with the provided identifier. - * @throws EJBAccessException if the current owner does not owns the pet. - */ - /*public Pet get(Long id) { - final Pet pet = em.find(Pet.class, id); - - if (pet == null) { - return null; - } else if (pet.getOwner().getLogin().equals(this.currentOwner.getName())) { - return pet; - } else { - throw new EJBAccessException("Pet's owner is not the current principal"); - } - }*/ - public int countAll() { - Long count = em.createQuery("SELECT COUNT(p) FROM Pet p", Long.class) - .getSingleResult(); - return count.intValue(); - } - - - public Pet get(Long id) { - return em.find(Pet.class, id); - } - - /*public List getAll(int page, int pageSize) { - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return em.createQuery("SELECT p FROM Pet p", Pet.class) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .getResultList(); - }*/ - - public List getAll(int first, int pageSize) { - if (first < 0) throw new IllegalArgumentException("First can't be negative"); - if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); - - return em.createQuery("SELECT p FROM Pet p", Pet.class) - .setFirstResult(first) // no multiplicar por pageSize - .setMaxResults(pageSize) - .getResultList(); - } - - - - /** - * Returns the complete list of pets of the current owner. - * - * @return the complete list of pets of the current owner. - */ - public List list(int page, int pageSize) { - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return em.createQuery("SELECT p FROM Pet p WHERE p.owner.login = :login", Pet.class) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .setParameter("login", currentUser.getName()) - .getResultList(); - } - - /** - * Creates a new pet owned by the current user. - * - * @param pet a new pet to be stored. - * @return the persistent version of the pet created. - * @throws EJBAccessException if the pet already has an owner and it is not - * the current user. If the pet has no owner, this exception will be never - * thrown. - * @throws IllegalArgumentException if a pet with the same identifier - * already exists. - */ - public Pet create(Pet pet) { - requireNonNull(pet, "Pet can't be null"); - - final Owner owner = em.find(Owner.class, currentUser.getName()); - - if (pet.getOwner() != null && !pet.getOwner().getLogin().equals(owner.getLogin())) { - throw new EJBAccessException("Pet's owner is not the current principal"); - } else { - pet.setOwner(owner); - - this.em.persist(pet); - - return pet; - } - } - - public Pet createPet(String name, AnimalType animal, Date birth) { - Owner owner = em.find(Owner.class, currentUser.getName()); - Pet pet = new Pet(name, animal, birth, owner); - this.em.persist(pet); - return pet; - - } - + + @Inject + private Principal currentUser; + + @EJB + private EmailService emailService; + + @PersistenceContext + private EntityManager em; + + /** + * Counts all pets in the system. + * + * @return the total number of pets. + */ + public int countAll() { + Long count = em.createQuery("SELECT COUNT(p) FROM Pet p", Long.class) + .getSingleResult(); + return count.intValue(); + } + + /** + * Returns a pet identified by the provided id. + * + * @param id the identifier of the pet. + * @return the pet or {@code null} if not found. + */ + public Pet get(Long id) { + return em.find(Pet.class, id); + } + + /** + * Returns a paginated list of all pets (0-based first index). + * + * @param first the starting index of the first pet. + * @param pageSize the maximum number of pets to return. + * @return a list of pets. + * @throws IllegalArgumentException if {@code first} is negative or {@code pageSize} is not positive. + */ + public List getAll(int first, int pageSize) { + if (first < 0) throw new IllegalArgumentException("First can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); + + return em.createQuery("SELECT p FROM Pet p", Pet.class) + .setFirstResult(first) + .setMaxResults(pageSize) + .getResultList(); + } + + /** + * Returns a paginated list of pets belonging to the current owner (0-based page index). + * + * @param page the 0-based page index. + * @param pageSize the maximum number of pets per page. + * @return the list of pets of the current owner. + * @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive. + */ + public List list(int page, int pageSize) { + if (page < 0) throw new IllegalArgumentException("The page can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("The page size must be negative or zero"); + + return em.createQuery("SELECT p FROM Pet p WHERE p.owner.login = :login", Pet.class) + .setFirstResult(page * pageSize) + .setMaxResults(pageSize) + .setParameter("login", currentUser.getName()) + .getResultList(); + } + + /** + * Creates a new pet for the current owner. + * + * @param pet the pet to create. + * @return the persistent version of the pet. + * @throws IllegalArgumentException if {@code pet} is null. + * @throws EJBAccessException if the pet already has an owner different from the current user. + */ + public Pet create(Pet pet) { + requireNonNull(pet, "Pet can't be null"); + + final Owner owner = em.find(Owner.class, currentUser.getName()); + + if (pet.getOwner() != null && !pet.getOwner().getLogin().equals(owner.getLogin())) { + throw new EJBAccessException("Pet's owner is not the current principal"); + } else { + pet.setOwner(owner); + em.persist(pet); + return pet; + } + } + + /** + * Convenience method to create a new pet with basic attributes. + */ + public Pet createPet(String name, AnimalType animal, Date birth) { + Owner owner = em.find(Owner.class, currentUser.getName()); + Pet pet = new Pet(name, animal, birth, owner); + em.persist(pet); + return pet; + } + + /** + * Updates an existing pet. If the pet does not exist, it will be persisted. + * + * @param pet the pet to update. + * @return the updated pet. + * @throws IllegalArgumentException if the pet has no owner. + * @throws EJBAccessException if the pet's owner is not the current user. + */ + public Pet update(Pet pet) { + if (pet.getOwner() == null) + throw new IllegalArgumentException("Pet must have an owner"); + + if (pet.getOwner().getLogin().equals(currentUser.getName())) { + return em.merge(pet); + } else { + throw new EJBAccessException("Pet's owner is not the current principal"); + } + } + + /** + * Deletes a pet. + * + * @param id the identifier of the pet. + * @throws IllegalArgumentException if no pet exists with the provided id. + * @throws EJBAccessException if the pet's owner is not the current user. + */ + public void remove(Long id) { + final Pet pet = this.get(id); + pet.setOwner(null); + em.remove(pet); + } + + /** + * Returns a paginated list of vaccines for a given pet. + * + * @param id the identifier of the pet. + * @param page the 0-based page index. + * @param pageSize the maximum number of vaccines per page. + * @return the list of vaccines associated with the pet. + * @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive. + */ + public List getVaccinesByPetId(Long id, int page, int pageSize) { + if (page < 0) throw new IllegalArgumentException("The page can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero"); + + return em.createQuery("SELECT v.pet FROM Vaccination v WHERE v.pet.id = :id", Vaccine.class) + .setFirstResult(page * pageSize) + .setMaxResults(pageSize) + .setParameter("id", id) + .getResultList(); + } + + /** + * Assigns the current vet to a pet. + * + * @param petId the identifier of the pet. + * @throws NullPointerException if {@code petId} is null. + * @throws IllegalArgumentException if the pet or vet does not exist. + */ + @RolesAllowed("VET") + public void assignVetToPet(Long petId) { + requireNonNull(petId, "Pet ID can't be null"); + + Pet pet = em.find(Pet.class, petId); + if (pet == null) throw new IllegalArgumentException("Pet not found"); + + Vet vet = em.find(Vet.class, currentUser.getName()); + if (vet == null) throw new IllegalArgumentException("Vet not found"); + + pet.addVet(vet); + pet.internalAddVet(vet); + em.merge(pet); + } + + /** - * Updates the information of a pet. If the pet is not stored, it will be - * created. + * Unassigns the current vet from a pet. * - * @param pet a pet to be updated. - * @return the updated pet. - * @throws IllegalArgumentException if the pet has no owner. - * @throws EJBAccessException if the pet's owner is not the current user. + * @param petId the identifier of the pet. + * @throws NullPointerException if {@code petId} is null. + * @throws IllegalArgumentException if the pet or vet does not exist. */ - public Pet update(Pet pet) { - if (pet.getOwner() == null) - throw new IllegalArgumentException("Pet must have an owner"); - - if (pet.getOwner().getLogin().equals(this.currentUser.getName())) { - return em.merge(pet); - } else { - throw new EJBAccessException("Pet's owner is not the current principal"); - } - } - + @RolesAllowed("VET") + public void unassignVetFromPet(Long petId) { + requireNonNull(petId, "Pet ID can't be null"); + + Pet pet = em.find(Pet.class, petId); + if (pet == null) throw new IllegalArgumentException("Pet not found"); + + Vet vet = em.find(Vet.class, currentUser.getName()); + if (vet == null) throw new IllegalArgumentException("Vet not found"); + + pet.removeVet(vet); + pet.internalRemoveVet(vet); + em.merge(pet); + } + + /** - * Deletes a pet. + * Returns the current authenticated user (Principal). * - * @param id the identifier of the pet to be deleted. - * @throws IllegalArgumentException if there is no pet with the provided - * identifier. - * @throws EJBAccessException if the pet's owner is not the current user. + * @return the current Principal. */ - public void remove(Long id) { - final Pet pet = this.get(id); - pet.setOwner(null); - - em.remove(pet); - } - - public List getVaccinesByPetId(Long id, int page, int pageSize){ - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return em.createQuery("SELECT v.pet FROM Vaccination v WHERE v.pet.id = :id", Vaccine.class) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .getResultList(); - } - - - @RolesAllowed("VET") - public void assignVetToPet(Long petId) { - requireNonNull(petId, "Pet ID can't be null"); - //requireNonNull(vetLogin, "Vet login can't be null"); - - Pet pet = em.find(Pet.class, petId); - if (pet == null) - throw new IllegalArgumentException("Pet not found"); - - Vet vet = em.find(Vet.class, currentUser.getName()); - if (vet == null) - throw new IllegalArgumentException("Vet not found"); - - pet.addVet(vet); - pet.internalAddVet(vet); - em.merge(pet); - } - - - @RolesAllowed("VET") - public void unassignVetFromPet(Long petId) { - requireNonNull(petId, "Pet ID can't be null"); - //requireNonNull(vetLogin, "Vet login can't be null"); - - Pet pet = em.find(Pet.class, petId); - if (pet == null) - throw new IllegalArgumentException("Pet not found"); - - Vet vet = em.find(Vet.class, currentUser.getName()); - if (vet == null) - throw new IllegalArgumentException("Vet not found"); - - pet.removeVet(vet); - pet.internalRemoveVet(vet); - em.merge(pet); - } - - public Principal getCurrentUser() { - return this.currentUser; - } - - @RolesAllowed("VET") - public boolean isAssignedToCurrentVet(Long petId) { - requireNonNull(petId, "Pet ID can't be null"); - - - Long count = em.createQuery( - "SELECT COUNT(p) FROM Pet p JOIN p.vets v WHERE p.id = :petId AND v.login = :login", - Long.class - ) - .setParameter("petId", petId) - .setParameter("login", currentUser.getName()) - .getSingleResult(); - - return count > 0; - } - + public Principal getCurrentUser() { + return this.currentUser; + } + + + /** + * Checks if the current vet is assigned to a given pet. + * + * @param petId the identifier of the pet. + * @return {@code true} if the current vet is assigned to the pet, {@code false} otherwise. + * @throws NullPointerException if {@code petId} is null. + */ + @RolesAllowed("VET") + public boolean isAssignedToCurrentVet(Long petId) { + requireNonNull(petId, "Pet ID can't be null"); + + Long count = em.createQuery( + "SELECT COUNT(p) FROM Pet p JOIN p.vets v WHERE p.id = :petId AND v.login = :login", + Long.class + ) + .setParameter("petId", petId) + .setParameter("login", currentUser.getName()) + .getSingleResult(); + + return count > 0; + } } diff --git a/service/src/main/java/es/uvigo/esei/xcs/service/UserService.java b/service/src/main/java/es/uvigo/esei/xcs/service/UserService.java index 2ce7dc29f422ad492fcf27043ab6cc83a65bceb8..30185b62e525db72f9d07168a47c9053ce00e346 100644 --- a/service/src/main/java/es/uvigo/esei/xcs/service/UserService.java +++ b/service/src/main/java/es/uvigo/esei/xcs/service/UserService.java @@ -13,52 +13,80 @@ import javax.persistence.PersistenceContext; import es.uvigo.esei.xcs.domain.entities.User; +/** + * EJB for managing users. Access is restricted to OWNER, ADMIN, and VET roles. + * Provides basic CRUD operations with paginated listing. + * + * @author Breixo Senra + */ @Stateless @RolesAllowed({"OWNER", "ADMIN", "VET"}) public class UserService { - @PersistenceContext - private EntityManager em; - - @Inject - private Principal principal; - /** - * Returns the current user entity. - * - * @return the entity with the information of the current user. - */ - public User getCurrentUser() { - return this.em.find(User.class, this.principal.getName()); - } - - public User get(String login) { - return this.em.find(User.class, login); - } - - public List list(int page, int pageSize){ - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return this.em.createQuery("SELECT DISTINCT u FROM User u", User.class) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .getResultList(); - } - - public User create(User user) { - requireNonNull(user, "User can't be null"); - this.em.persist(user); - return user; - } - - public void remove(String login) { - User user = this.get(login); - this.em.remove(user); - } - - - + @PersistenceContext + private EntityManager em; + + @Inject + private Principal principal; + + /** + * Returns the entity of the currently authenticated user. + * + * @return the current User entity. + */ + public User getCurrentUser() { + return this.em.find(User.class, this.principal.getName()); + } + + /** + * Returns a user by login. + * + * @param login the login of the user. + * @return the User entity, or {@code null} if not found. + */ + public User get(String login) { + return this.em.find(User.class, login); + } + + /** + * Returns a paginated list of users (0-based page index). + * + * @param page the 0-based page index. + * @param pageSize the maximum number of users per page. + * @return a list of users. + * @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive. + */ + public List list(int page, int pageSize) { + if (page < 0) throw new IllegalArgumentException("The page can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero"); + + return this.em.createQuery("SELECT DISTINCT u FROM User u", User.class) + .setFirstResult(page * pageSize) + .setMaxResults(pageSize) + .getResultList(); + } + + /** + * Persists a new user. + * + * @param user the User entity to create. + * @return the persisted User. + * @throws NullPointerException if {@code user} is null. + */ + public User create(User user) { + requireNonNull(user, "User can't be null"); + this.em.persist(user); + return user; + } + + /** + * Removes a user by login. + * + * @param login the login of the user to remove. + * @throws IllegalArgumentException if no user exists with the provided login. + */ + public void remove(String login) { + User user = this.get(login); + this.em.remove(user); + } } diff --git a/service/src/main/java/es/uvigo/esei/xcs/service/VaccinationService.java b/service/src/main/java/es/uvigo/esei/xcs/service/VaccinationService.java index b33abf9bd0bb8a224bb22519b465bb68ae903b79..ca82dbc17b958e4f3f1deebbd71703dfa0775cf4 100644 --- a/service/src/main/java/es/uvigo/esei/xcs/service/VaccinationService.java +++ b/service/src/main/java/es/uvigo/esei/xcs/service/VaccinationService.java @@ -4,11 +4,8 @@ import java.util.Date; import static java.util.Objects.requireNonNull; import java.security.Principal; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.List; -import javax.annotation.security.PermitAll; import javax.annotation.security.RolesAllowed; import javax.ejb.EJB; import javax.ejb.Stateless; @@ -22,120 +19,154 @@ import es.uvigo.esei.xcs.domain.entities.Pet; import es.uvigo.esei.xcs.domain.entities.Vaccination; import es.uvigo.esei.xcs.domain.entities.Vaccine; +/** + * EJB for managing Vaccinations. Access is restricted to VET role. + * Provides CRUD operations and rules to check if a pet can be vaccinated. + * + * @author Breixo Senra + */ @Stateless @RolesAllowed("VET") -//@PermitAll public class VaccinationService { - @Inject - private Principal currentUser; - - @PersistenceContext - EntityManager em; - - @EJB - private EmailService emailService; - - public Vaccination get(int vaccinationId) { - return em.find(Vaccination.class, vaccinationId); - } - - - public List list(int page, int pageSize){ - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return em.createQuery("SELECT DISTINCT v FROM Vaccination v", Vaccination.class) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .getResultList(); - } - - - public Vaccination create(Long petId, Long vaccineId, Date date) { - Pet pet = requireNonNull(em.find(Pet.class, petId), "Pet can't be null"); - Vaccine vaccine = requireNonNull(em.find(Vaccine.class, vaccineId), "Vaccine can't be null"); - - if (!canVaccinate(petId, vaccineId, date)) { - throw new IllegalArgumentException("This vaccination cannot be created due to vaccine rules"); - } - - Vaccination vaccination = new Vaccination(pet, vaccine, date); - em.persist(vaccination); - emailService.send( - pet.getOwner().getLogin(), - pet.getName() + " ha sido vacunado con " + vaccine.getName(), - pet.getName() + " ha sido vacunado con " + vaccine.getName() - ); - return vaccination; - } - - - - public Vaccination updateDate(int vaccinationId, Date date) { - Vaccination vaccination = em.find(Vaccination.class, vaccinationId); - requireNonNull(vaccination, "Vaccination can't be null"); - vaccination.setDate(date); - return em.merge(vaccination); - } - - - public void remove(int vaccinationId) { - Vaccination vaccination = this.get(vaccinationId); - requireNonNull(vaccination, "Vaccination can't be null"); - em.remove(vaccination); - } - - - public Boolean canVaccinate(Long petId, Long vaccineId, Date date) { - Pet pet = em.find(Pet.class, petId); - Vaccine vaccine = em.find(Vaccine.class, vaccineId); - if (pet == null || vaccine == null) return false; - - List prevVaccinations = em.createQuery( - "SELECT v FROM Vaccination v WHERE v.pet.id = :petId AND v.vaccine.id = :vaccineId ORDER BY v.date DESC", - Vaccination.class) - .setParameter("petId", petId) - .setParameter("vaccineId", vaccineId) - .getResultList(); - - if (vaccine instanceof MultidoseVaccine) { - MultidoseVaccine multi = (MultidoseVaccine) vaccine; - Integer doses = multi.getDoses(); - if (doses == null) return false; - return prevVaccinations.size() < doses; - - } else if (vaccine instanceof PeriodicVaccine) { - PeriodicVaccine periodic = (PeriodicVaccine) vaccine; - if (prevVaccinations.isEmpty()) return true; - Vaccination last = prevVaccinations.get(0); - if (last.getDate() == null || date == null) return false; - - long diffDays; - switch (periodic.getPeriodicType()) { - case YEARS: - diffDays = periodic.getPeriode() * 365L; - break; - case MONTHS: - diffDays = periodic.getPeriode() * 30L; - break; - case DAYS: - diffDays = periodic.getPeriode(); - break; - default: - return false; - } - - long diffMillis = date.getTime() - last.getDate().getTime(); - return diffMillis >= diffDays * 24L * 60L * 60L * 1000L; - - } else { // MONODOSE - return prevVaccinations.isEmpty(); - } - } - - - + + @Inject + private Principal currentUser; + + @PersistenceContext + private EntityManager em; + + @EJB + private EmailService emailService; + + /** + * Returns a vaccination by its ID. + * + * @param vaccinationId the identifier of the vaccination. + * @return the Vaccination entity, or {@code null} if not found. + */ + public Vaccination get(int vaccinationId) { + return em.find(Vaccination.class, vaccinationId); + } + + /** + * Returns a paginated list of vaccinations (0-based page index). + * + * @param page the 0-based page index. + * @param pageSize the maximum number of vaccinations per page. + * @return a list of Vaccination entities. + * @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive. + */ + public List list(int page, int pageSize) { + if (page < 0) throw new IllegalArgumentException("The page can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero"); + + return em.createQuery("SELECT DISTINCT v FROM Vaccination v", Vaccination.class) + .setFirstResult(page * pageSize) + .setMaxResults(pageSize) + .getResultList(); + } + + /** + * Creates a new vaccination for a pet with a given vaccine and date. + * Sends an email notification to the pet's owner. + * + * @param petId the identifier of the pet. + * @param vaccineId the identifier of the vaccine. + * @param date the date of the vaccination. + * @return the persisted Vaccination entity. + * @throws NullPointerException if {@code pet} or {@code vaccine} is null. + * @throws IllegalArgumentException if the vaccination cannot be created due to vaccine rules. + */ + public Vaccination create(Long petId, Long vaccineId, Date date) { + Pet pet = requireNonNull(em.find(Pet.class, petId), "Pet can't be null"); + Vaccine vaccine = requireNonNull(em.find(Vaccine.class, vaccineId), "Vaccine can't be null"); + + if (!canVaccinate(petId, vaccineId, date)) { + throw new IllegalArgumentException("This vaccination cannot be created due to vaccine rules"); + } + + Vaccination vaccination = new Vaccination(pet, vaccine, date); + em.persist(vaccination); + emailService.send( + pet.getOwner().getLogin(), + pet.getName() + " ha sido vacunado con " + vaccine.getName(), + pet.getName() + " ha sido vacunado con " + vaccine.getName() + ); + return vaccination; + } + + /** + * Updates the date of an existing vaccination. + * + * @param vaccinationId the identifier of the vaccination. + * @param date the new date. + * @return the updated Vaccination entity. + * @throws NullPointerException if the vaccination does not exist. + */ + public Vaccination updateDate(int vaccinationId, Date date) { + Vaccination vaccination = em.find(Vaccination.class, vaccinationId); + requireNonNull(vaccination, "Vaccination can't be null"); + vaccination.setDate(date); + return em.merge(vaccination); + } + + /** + * Removes a vaccination by its ID. + * + * @param vaccinationId the identifier of the vaccination. + * @throws NullPointerException if the vaccination does not exist. + */ + public void remove(int vaccinationId) { + Vaccination vaccination = this.get(vaccinationId); + requireNonNull(vaccination, "Vaccination can't be null"); + em.remove(vaccination); + } + + /** + * Checks whether a pet can be vaccinated with a given vaccine on a given date. + * + * @param petId the identifier of the pet. + * @param vaccineId the identifier of the vaccine. + * @param date the intended vaccination date. + * @return {@code true} if vaccination is allowed, {@code false} otherwise. + */ + public Boolean canVaccinate(Long petId, Long vaccineId, Date date) { + Pet pet = em.find(Pet.class, petId); + Vaccine vaccine = em.find(Vaccine.class, vaccineId); + if (pet == null || vaccine == null) return false; + + List prevVaccinations = em.createQuery( + "SELECT v FROM Vaccination v WHERE v.pet.id = :petId AND v.vaccine.id = :vaccineId ORDER BY v.date DESC", + Vaccination.class) + .setParameter("petId", petId) + .setParameter("vaccineId", vaccineId) + .getResultList(); + + if (vaccine instanceof MultidoseVaccine) { + MultidoseVaccine multi = (MultidoseVaccine) vaccine; + Integer doses = multi.getDoses(); + if (doses == null) return false; + return prevVaccinations.size() < doses; + + } else if (vaccine instanceof PeriodicVaccine) { + PeriodicVaccine periodic = (PeriodicVaccine) vaccine; + if (prevVaccinations.isEmpty()) return true; + Vaccination last = prevVaccinations.get(0); + if (last.getDate() == null || date == null) return false; + + long diffDays; + switch (periodic.getPeriodicType()) { + case YEARS: diffDays = periodic.getPeriode() * 365L; break; + case MONTHS: diffDays = periodic.getPeriode() * 30L; break; + case DAYS: diffDays = periodic.getPeriode(); break; + default: return false; + } + + long diffMillis = date.getTime() - last.getDate().getTime(); + return diffMillis >= diffDays * 24L * 60L * 60L * 1000L; + + } else { // Monodose + return prevVaccinations.isEmpty(); + } + } } diff --git a/service/src/main/java/es/uvigo/esei/xcs/service/VaccineService.java b/service/src/main/java/es/uvigo/esei/xcs/service/VaccineService.java index 1d20eda3268b8798cd3353713fcdda7a6d5e15f0..0d37e52cc9a844fbcefecbc691d0b7bbafed01d5 100644 --- a/service/src/main/java/es/uvigo/esei/xcs/service/VaccineService.java +++ b/service/src/main/java/es/uvigo/esei/xcs/service/VaccineService.java @@ -1,10 +1,7 @@ package es.uvigo.esei.xcs.service; - - import java.util.List; -import javax.annotation.security.PermitAll; import javax.annotation.security.RolesAllowed; import javax.ejb.Stateless; import javax.persistence.EntityManager; @@ -17,114 +14,157 @@ import es.uvigo.esei.xcs.domain.entities.PeriodicVaccine; import es.uvigo.esei.xcs.domain.entities.Pet; import es.uvigo.esei.xcs.domain.entities.Vaccine; +/** + * EJB for managing Vaccines. Access is restricted to VET role. + * Provides CRUD operations, creation of different vaccine types, + * and retrieval of vaccinated pets with pagination. + * + * @author Breixo Senra + */ @Stateless @RolesAllowed("VET") public class VaccineService { - @PersistenceContext - private EntityManager em; - - public Vaccine get(Long id) { - final Vaccine vaccine = em.find(Vaccine.class, id); - - return vaccine; - } - - - public List list(int page, int pageSize){ - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return em.createQuery("SELECT v FROM Vaccine v", Vaccine.class) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .getResultList(); - } - - - public Vaccine create(String name, String type, Integer doses, String periodicTypeString, Integer periode) { - switch(type) { - case "MONODOSE": - MonodoseVaccine monodoseVaccine = new MonodoseVaccine(name); - em.persist(monodoseVaccine); - return monodoseVaccine; - case "MULTIDOSE": - MultidoseVaccine multidoseVaccine = new MultidoseVaccine(name, doses); - em.persist(multidoseVaccine); - return multidoseVaccine; - case "PERIODIC": - PeriodicType periodicType = null; - if (periodicTypeString != null) { - periodicType = PeriodicType.valueOf(periodicTypeString); - } - PeriodicVaccine periodicVaccine = new PeriodicVaccine(name, periodicType, periode); - em.persist(periodicVaccine); - return periodicVaccine; - default: throw new IllegalArgumentException("Tipo de vacuna desconocido"); - } - - } - - - public Vaccine update(Vaccine vaccine) { - if (vaccine == null) - throw new IllegalArgumentException("vaccine can't be null"); - - return em.merge(vaccine); - } - - public Vaccine updateName(Long id, String newName) { - if (id == null || newName == null || newName.trim().isEmpty()) - throw new IllegalArgumentException("Id o nombre inválido"); - - Vaccine vaccine = em.find(Vaccine.class, id); - if (vaccine == null) - throw new IllegalArgumentException("Vacuna no encontrada"); - - vaccine.setName(newName); - return em.merge(vaccine); - } - - - - public void remove(Long id) { - final Vaccine vaccine = this.get(id); - em.remove(vaccine); - } - - - public List getVaccinatedPetsByVaccine(int vaccineId, int page, int pageSize){ - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return em.createQuery("SELECT v.pet FROM Vaccination v " - + "WHERE v.vaccine.id = :vaccineId", Pet.class) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .setParameter("vaccineId", vaccineId) - .getResultList(); - } - - - public List getVaccinatedPetsByVaccineName(String vaccineName, int page, int pageSize){ - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return em.createQuery("SELECT v.pet FROM Vaccination v\r\n" - + "WHERE v.vaccine.name = :vaccineName", Pet.class) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .setParameter("vaccineName", vaccineName) - .getResultList(); - } - - + + @PersistenceContext + private EntityManager em; + + /** + * Returns a vaccine by its ID. + * + * @param id the identifier of the vaccine. + * @return the Vaccine entity, or {@code null} if not found. + */ + public Vaccine get(Long id) { + return em.find(Vaccine.class, id); + } + + /** + * Returns a paginated list of vaccines (0-based page index). + * + * @param page the 0-based page index. + * @param pageSize the maximum number of vaccines per page. + * @return a list of Vaccine entities. + * @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive. + */ + public List list(int page, int pageSize) { + if (page < 0) throw new IllegalArgumentException("The page can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero"); + + return em.createQuery("SELECT v FROM Vaccine v", Vaccine.class) + .setFirstResult(page * pageSize) + .setMaxResults(pageSize) + .getResultList(); + } + + /** + * Creates a vaccine of a specific type. + * + * @param name the name of the vaccine. + * @param type the type of vaccine ("MONODOSE", "MULTIDOSE", "PERIODIC"). + * @param doses the number of doses (for MULTIDOSE). + * @param periodicTypeString the periodic type string (for PERIODIC). + * @param periode the period length (for PERIODIC). + * @return the created Vaccine entity. + * @throws IllegalArgumentException if the type is unknown. + */ + public Vaccine create(String name, String type, Integer doses, String periodicTypeString, Integer periode) { + switch(type) { + case "MONODOSE": + MonodoseVaccine monodoseVaccine = new MonodoseVaccine(name); + em.persist(monodoseVaccine); + return monodoseVaccine; + case "MULTIDOSE": + MultidoseVaccine multidoseVaccine = new MultidoseVaccine(name, doses); + em.persist(multidoseVaccine); + return multidoseVaccine; + case "PERIODIC": + PeriodicType periodicType = null; + if (periodicTypeString != null) { + periodicType = PeriodicType.valueOf(periodicTypeString); + } + PeriodicVaccine periodicVaccine = new PeriodicVaccine(name, periodicType, periode); + em.persist(periodicVaccine); + return periodicVaccine; + default: throw new IllegalArgumentException("Unknown vaccine type"); + } + } + + /** + * Updates an existing vaccine. + * + * @param vaccine the Vaccine entity to update. + * @return the updated Vaccine entity. + * @throws IllegalArgumentException if {@code vaccine} is null. + */ + public Vaccine update(Vaccine vaccine) { + if (vaccine == null) throw new IllegalArgumentException("vaccine can't be null"); + return em.merge(vaccine); + } + + /** + * Updates the name of a vaccine. + * + * @param id the identifier of the vaccine. + * @param newName the new name. + * @return the updated Vaccine entity. + * @throws IllegalArgumentException if the id or name is invalid or the vaccine is not found. + */ + public Vaccine updateName(Long id, String newName) { + if (id == null || newName == null || newName.trim().isEmpty()) + throw new IllegalArgumentException("Id or name invalid"); + + Vaccine vaccine = em.find(Vaccine.class, id); + if (vaccine == null) throw new IllegalArgumentException("Vaccine not found"); + + vaccine.setName(newName); + return em.merge(vaccine); + } + + /** + * Removes a vaccine by its ID. + * + * @param id the identifier of the vaccine. + */ + public void remove(Long id) { + final Vaccine vaccine = this.get(id); + em.remove(vaccine); + } + + /** + * Returns a paginated list of pets vaccinated with a specific vaccine ID. + * + * @param vaccineId the identifier of the vaccine. + * @param page the 0-based page index. + * @param pageSize the maximum number of pets per page. + * @return a list of Pet entities. + */ + public List getVaccinatedPetsByVaccine(int vaccineId, int page, int pageSize) { + if (page < 0) throw new IllegalArgumentException("The page can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero"); + + return em.createQuery("SELECT v.pet FROM Vaccination v WHERE v.vaccine.id = :vaccineId", Pet.class) + .setFirstResult(page * pageSize) + .setMaxResults(pageSize) + .setParameter("vaccineId", vaccineId) + .getResultList(); + } + + /** + * Returns a paginated list of pets vaccinated with a specific vaccine name. + * + * @param vaccineName the name of the vaccine. + * @param page the 0-based page index. + * @param pageSize the maximum number of pets per page. + * @return a list of Pet entities. + */ + public List getVaccinatedPetsByVaccineName(String vaccineName, int page, int pageSize) { + if (page < 0) throw new IllegalArgumentException("The page can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero"); + + return em.createQuery("SELECT v.pet FROM Vaccination v WHERE v.vaccine.name = :vaccineName", Pet.class) + .setFirstResult(page * pageSize) + .setMaxResults(pageSize) + .setParameter("vaccineName", vaccineName) + .getResultList(); + } } diff --git a/service/src/main/java/es/uvigo/esei/xcs/service/VetService.java b/service/src/main/java/es/uvigo/esei/xcs/service/VetService.java index fb5f2cf16890112bbc986557e2b137aced3e86e2..50db800ec9e1ad1428bdccd2d4b7afa9dfc4ef12 100644 --- a/service/src/main/java/es/uvigo/esei/xcs/service/VetService.java +++ b/service/src/main/java/es/uvigo/esei/xcs/service/VetService.java @@ -5,7 +5,6 @@ import static java.util.Objects.requireNonNull; import java.security.Principal; import java.util.List; -import javax.annotation.security.PermitAll; import javax.annotation.security.RolesAllowed; import javax.ejb.Stateless; import javax.inject.Inject; @@ -17,113 +16,155 @@ import es.uvigo.esei.xcs.domain.entities.Pet; import es.uvigo.esei.xcs.domain.entities.Vaccination; import es.uvigo.esei.xcs.domain.entities.Vet; +/** + * EJB for managing Vet entities. Access is restricted to VET role. + * Provides CRUD operations, retrieval of assigned pets and vaccinations + * with pagination support. + * + * @author Breixo Senra + */ @Stateless @RolesAllowed("VET") public class VetService { - @Inject - private Principal currentUser; - - @PersistenceContext - EntityManager em; - - public int countPets() { - Long count = em.createQuery( - "SELECT COUNT(p) FROM Vet v JOIN v.pets p WHERE v.login = :login", Long.class) - .setParameter("login", currentUser.getName()) - .getSingleResult(); - return count.intValue(); - } - - - public Vet get(String login) { - return em.find(Vet.class, login); - } - - - public List list(){ - return em.createQuery("SELECT DISTINCT v FROM Vet v", Vet.class) - .getResultList(); - } - - - public List findByPetName(String petName, int page, int pageSize){ - requireNonNull(petName, "Pet's name can't be null"); - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return this.em.createQuery("SELECT DISTINCT v FROM Vet v JOIN v.pets p " - + "WHERE p.name = :petName", Vet.class) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .setParameter("petName", petName) - .getResultList(); - } - - - public Vet create(Vet vet) { - requireNonNull(Vet.class, "Vet can't be null"); - em.persist(vet); - return vet; - } - - - public Vet update(Vet vet) { - requireNonNull(Vet.class, "Vet can't be null"); - return em.merge(vet); - } - - - public void remove(String login) { - em.remove(this.get(login)); - } - - - public List getPets(int first , int pageSize) { - if (first < 0) throw new IllegalArgumentException("First can't be negative"); - if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); - - return this.em.createQuery("SELECT DISTINCT p FROM Vet v JOIN v.pets p " - + "WHERE v.login = :login", Pet.class) - .setFirstResult(first) - .setMaxResults(pageSize) - .setParameter("login", currentUser.getName()) - .getResultList(); - } - - public List getVaccinationsFromOwnPet( - IdentifierType identifierType, - String identifierValue, - int page, - int pageSize - ){ - requireNonNull(identifierType, "pet's identifier type can't be null"); - requireNonNull(identifierValue, "pet's identifier value can't be null"); - if (page < 0) { - throw new IllegalArgumentException("The page can't be negative"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("The page size can't be negative or zero"); - } - return em.createQuery( - "SELECT v FROM Vet vet " - + "JOIN vet.pets p " - + "JOIN p.identifiers i " - + "JOIN p.vaccinations v " - + "WHERE " - + "vet.login = :login AND " - + "i.type = :identifierType AND " - + "i.value = :identifierValue", - Vaccination.class) - .setParameter("login", currentUser.getName()) - .setParameter("identifierType", identifierType) - .setParameter("identifierValue", identifierValue) - .setFirstResult(page * pageSize) - .setMaxResults(pageSize) - .getResultList(); - } - - + + @Inject + private Principal currentUser; + + @PersistenceContext + private EntityManager em; + + /** + * Counts the number of pets assigned to the current vet. + * + * @return the number of pets assigned to the current vet. + */ + public int countPets() { + Long count = em.createQuery( + "SELECT COUNT(p) FROM Vet v JOIN v.pets p WHERE v.login = :login", Long.class) + .setParameter("login", currentUser.getName()) + .getSingleResult(); + return count.intValue(); + } + + /** + * Returns a vet by login. + * + * @param login the login of the vet. + * @return the Vet entity, or {@code null} if not found. + */ + public Vet get(String login) { + return em.find(Vet.class, login); + } + + /** + * Returns a list of all vets. + * + * @return a list of Vet entities. + */ + public List list() { + return em.createQuery("SELECT DISTINCT v FROM Vet v", Vet.class) + .getResultList(); + } + + /** + * Returns a paginated list of vets that have a pet with the given name. + * + * @param petName the name of the pet. + * @param page the 0-based page index. + * @param pageSize the maximum number of vets per page. + * @return a list of Vet entities. + */ + public List findByPetName(String petName, int page, int pageSize) { + requireNonNull(petName, "Pet's name can't be null"); + if (page < 0) throw new IllegalArgumentException("The page can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero"); + + return em.createQuery("SELECT DISTINCT v FROM Vet v JOIN v.pets p WHERE p.name = :petName", Vet.class) + .setFirstResult(page * pageSize) + .setMaxResults(pageSize) + .setParameter("petName", petName) + .getResultList(); + } + + /** + * Creates a new vet. + * + * @param vet the Vet entity to create. + * @return the persisted Vet entity. + */ + public Vet create(Vet vet) { + requireNonNull(vet, "Vet can't be null"); + em.persist(vet); + return vet; + } + + /** + * Updates an existing vet. + * + * @param vet the Vet entity to update. + * @return the updated Vet entity. + */ + public Vet update(Vet vet) { + requireNonNull(vet, "Vet can't be null"); + return em.merge(vet); + } + + /** + * Removes a vet by login. + * + * @param login the login of the vet to remove. + */ + public void remove(String login) { + em.remove(this.get(login)); + } + + /** + * Returns a paginated list of pets assigned to the current vet. + * + * @param first the index of the first pet (0-based). + * @param pageSize the maximum number of pets per page. + * @return a list of Pet entities. + */ + public List getPets(int first, int pageSize) { + if (first < 0) throw new IllegalArgumentException("First can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); + + return em.createQuery("SELECT DISTINCT p FROM Vet v JOIN v.pets p WHERE v.login = :login", Pet.class) + .setFirstResult(first) + .setMaxResults(pageSize) + .setParameter("login", currentUser.getName()) + .getResultList(); + } + + /** + * Returns a paginated list of vaccinations for a pet owned by the current vet. + * + * @param identifierType the type of the pet's identifier. + * @param identifierValue the value of the pet's identifier. + * @param page the 0-based page index. + * @param pageSize the maximum number of vaccinations per page. + * @return a list of Vaccination entities. + */ + public List getVaccinationsFromOwnPet( + IdentifierType identifierType, + String identifierValue, + int page, + int pageSize) { + + requireNonNull(identifierType, "Pet's identifier type can't be null"); + requireNonNull(identifierValue, "Pet's identifier value can't be null"); + if (page < 0) throw new IllegalArgumentException("The page can't be negative"); + if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero"); + + return em.createQuery( + "SELECT v FROM Vet vet JOIN vet.pets p JOIN p.identifiers i JOIN p.vaccinations v " + + "WHERE vet.login = :login AND i.type = :identifierType AND i.value = :identifierValue", + Vaccination.class) + .setParameter("login", currentUser.getName()) + .setParameter("identifierType", identifierType) + .setParameter("identifierValue", identifierValue) + .setFirstResult(page * pageSize) + .setMaxResults(pageSize) + .getResultList(); + } }