Commit 5ff6ed34 authored by Breixo Senra's avatar Breixo Senra

Falta menu de vet

parent 3ef867d3
CREATE DATABASE IF NOT EXISTS `xcs`; CREATE DATABASE IF NOT EXISTS `xcs`;
USE `xcs`; USE `xcs`;
DROP TABLE IF EXISTS `Pet`; DROP TABLE IF EXISTS `pet_vet`;
DROP TABLE IF EXISTS `User`; 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` -- Table structure for table `User`
-- --
CREATE TABLE `User` ( CREATE TABLE `user` (
`role` varchar(5) NOT NULL, `role` varchar(5) NOT NULL,
`login` varchar(100) NOT NULL, `login` varchar(100) NOT NULL,
`password` varchar(32) NOT NULL, `password` varchar(128) NOT NULL,
PRIMARY KEY (`login`) PRIMARY KEY (`login`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --
-- Table structure for table `Pet` -- Table structure for table `Pet`
-- --
CREATE TABLE `Pet` ( CREATE TABLE `pet` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`animal` varchar(4) NOT NULL, `animal` varchar(4) NOT NULL,
`birth` datetime NOT NULL, `birth` datetime NOT NULL,
`name` varchar(100) NOT NULL, `name` varchar(100) NOT NULL,
`owner` varchar(100) NOT NULL, `owner` varchar(100) NOT NULL,
`vet` varchar(100) NOT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `FK_Pet_Owner` (`owner`), KEY `FK_Pet_Owner` (`owner`),
KEY `FK_Pet_Vet` (`vet`), CONSTRAINT `FK_Pet_Owner_login` FOREIGN KEY (`owner`) REFERENCES `user` (`login`)
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`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --
-- Table structure for table `Pet` -- Table structure for table `pet_vet`
-- --
CREATE TABLE `Vaccine` ( CREATE TABLE `pet_vet` (
`id` int(11) NOT NULL AUTO_INCREMENT, `pet_id` int NOT NULL,
`name` varchar(100) NOT NULL, `vet_login` varchar(100) NOT NULL,
`owner` varchar(100) NOT NULL, PRIMARY KEY (`pet_id`,`vet_login`),
PRIMARY KEY (`id`), CONSTRAINT `FK_PetVet_Pet` FOREIGN KEY (`pet_id`) REFERENCES `pet` (`id`),
KEY `FK_Pet_Owner` (`owner`), CONSTRAINT `FK_PetVet_Vet` FOREIGN KEY (`vet_login`) REFERENCES `user` (`login`)
CONSTRAINT `FK_Pet_Owner_login` FOREIGN KEY (`owner`) REFERENCES `User` (`login`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --
-- Table structure for table `Vaccination` -- Table structure for table `identifier`
-- --
CREATE TABLE `Vaccination` ( CREATE TABLE `identifier` (
`id` int(11) NOT NULL AUTO_INCREMENT, `value` varchar(32) NOT NULL,
`name` varchar(100) NOT NULL, `type` varchar(4) NOT NULL,
`owner` varchar(100) NOT NULL, `pet_id` int DEFAULT NULL,
`date` date NOT NULL, PRIMARY KEY (`value`),
PRIMARY KEY (`date`), KEY `FK_Identifier_Pet` (`pet_id`),
KEY `FK_Vaccination_Pet` (`pet`), CONSTRAINT `FK_Identifier_Pet` FOREIGN KEY (`pet_id`) REFERENCES `pet` (`id`)
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`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) 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'; INSERT INTO `pet_vet` (pet_id,vet_login) VALUES
GRANT ALL PRIVILEGES ON xcs.* TO xcs@localhost; (1,'vet1'),(2,'vet1'),(3,'vet1'),
FLUSH PRIVILEGES; (4,'vet2'),(5,'vet2'),(6,'vet2'),
(7,'vet3'),(8,'vet3'),(9,'vet3');
-- --
-- Data for table `User` -- Vaccines
-- --
INSERT INTO `User` (role, login, password) VALUES INSERT INTO `vaccine` (VACCINE_TYPE,name,doses,periode,periodicType) VALUES
('ADMIN','jose','a3f6f4b40b24e2fd61f08923ed452f34'), ('MONODOSE','VacunaUno',NULL,NULL,NULL),
('OWNER','ana','22beeae33e9b2657f9610621502cd7a4'), ('MULTIDOSE','VacunaPeriodica',20,NULL,NULL),
('OWNER','juan','b4fbb95580592697dc71488a1f19277e'), ('PERIODIC','Periodica',NULL,7,'DAYS');
('OWNER','lorena','05009e420932c21e5a68f5ef1aadd530'),
('OWNER','pepe','b43b4d046860b2bd945bca2597bf9f07');
-- --
-- Data for table `Pet` -- Vaccinations
-- --
INSERT INTO `Pet` (animal, birth, name, owner) VALUES INSERT INTO `vaccination` (date,pet_id,vaccine_id) VALUES
('CAT','2000-01-01 01:01:01','Pepecat','pepe'), ('2025-10-01',1,1),
('CAT','2000-01-01 01:01:01','Max','juan'), ('2025-10-02',2,2),
('DOG','2000-01-01 01:01:01','Juandog','juan'), ('2025-10-03',3,3),
('CAT','2000-01-01 01:01:01','Anacat','ana'), ('2025-10-04',4,1),
('DOG','2000-01-01 01:01:01','Max','ana'), ('2025-10-05',5,2),
('BIRD','2000-01-01 01:01:01','Anabird','ana'); ('2025-10-06',6,3),
('2025-10-07',7,1),
('2025-10-08',8,2),
('2025-10-09',9,3);
package es.uvigo.esei.xcs.rest; package es.uvigo.esei.xcs.rest;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.ws.rs.Consumes; import javax.ws.rs.*;
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.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import es.uvigo.esei.xcs.service.AdministratorService; import es.uvigo.esei.xcs.service.AdministratorService;
import es.uvigo.esei.xcs.service.EmailService; 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") @Path("admin")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public class AdministratorResource { public class AdministratorResource {
@EJB @EJB
AdministratorService service; private AdministratorService service;
@EJB @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 @GET
public Response list(@QueryParam("page") int page, @QueryParam("pageSize") int pageSize) { public Response list(@QueryParam("page") int page, @QueryParam("pageSize") int pageSize) {
return Response.ok(this.service.list(page, pageSize)).build(); 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 @POST
public Response sendEmail() { public Response sendEmail() {
this.emailService.send("email@fake.email", "Topic", "Text Message"); this.emailService.send("email@fake.email", "Topic", "Text Message");
return Response.ok().build(); return Response.ok().build();
} }
} }
package es.uvigo.esei.xcs.rest; package es.uvigo.esei.xcs.rest;
import java.net.URI; import java.net.URI;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.persistence.EntityExistsException; import javax.persistence.EntityExistsException;
import javax.ws.rs.Consumes; import javax.ws.rs.*;
import javax.ws.rs.DELETE; import javax.ws.rs.core.*;
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 es.uvigo.esei.xcs.domain.entities.IdentifierType; import es.uvigo.esei.xcs.domain.entities.IdentifierType;
import es.uvigo.esei.xcs.domain.entities.Owner; import es.uvigo.esei.xcs.domain.entities.Owner;
...@@ -27,135 +14,137 @@ import es.uvigo.esei.xcs.service.OwnerService; ...@@ -27,135 +14,137 @@ import es.uvigo.esei.xcs.service.OwnerService;
import static java.util.Objects.requireNonNull; 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") @Path("owner")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public class OwnerResource { public class OwnerResource {
@EJB @EJB
private OwnerService service; private OwnerService service;
@Context @Context
private UriInfo uriInfo; 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. * @param login unique login of the owner.
* @return an {@code OK} response containing the {@link Owner} with the * @return HTTP 200 with the owner data.
* provided login. * @throws IllegalArgumentException if the login is null or not found.
* @throws IllegalArgumentException if {@code login} is {@code null} or
* if it does not correspond with any owner.
*/ */
@GET @GET
@Path("{login}") @Path("{login}")
public Response get(@PathParam("login") String login) { public Response get(@PathParam("login") String login) {
if (login == null) if (login == null)
throw new IllegalArgumentException("login can't be null"); throw new IllegalArgumentException("login can't be null");
final Owner owner = this.service.get(login); final Owner owner = this.service.get(login);
if (owner == null) if (owner == null)
throw new IllegalArgumentException("Owner not found: " + login); 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 * @param page 0-based page index.
* the application. * @param pageSize number of results per page.
* @return HTTP 200 with the list of owners.
*/ */
@GET @GET
public Response list(@QueryParam("page") int page, @QueryParam("pageSize") int pageSize) { public Response list(@QueryParam("page") int page, @QueryParam("pageSize") int pageSize) {
return Response.ok(this.service.list(page, pageSize)).build(); return Response.ok(this.service.list(page, pageSize)).build();
} }
/** /**
* Creates a new owner. This owner may include a list of pets, that will be * Creates a new owner (and optionally its pets).
* also created.
* *
* @param ownerData a new owner to be stored. * @param ownerData data of the new owner.
* @return a {@code CREATED} response with the URI of the new owner in the * @return HTTP 201 with the URI of the created owner.
* {@code Location} header. * @throws IllegalArgumentException if the data is null or already exists.
* @throws IllegalArgumentException if owner is {@code null} or if an owner
* with the same login already exists.
*/ */
@POST @POST
public Response create(OwnerCreationData ownerData) { public Response create(OwnerCreationData ownerData) {
if (ownerData == null) { if (ownerData == null)
throw new IllegalArgumentException("ownerData can't be null"); throw new IllegalArgumentException("ownerData can't be null");
}
try { try {
final Owner newOwner = this.service.create(ownerData.toOwner()); final Owner newOwner = this.service.create(ownerData.toOwner());
final URI ownerUri = uriInfo.getAbsolutePathBuilder() final URI ownerUri = uriInfo.getAbsolutePathBuilder()
.path(newOwner.getLogin()) .path(newOwner.getLogin())
.build(); .build();
return Response.created(ownerUri).build(); return Response.created(ownerUri).build();
} catch (EntityExistsException eee) { } catch (EntityExistsException eee) {
throw new IllegalArgumentException("The owner already exists"); throw new IllegalArgumentException("The owner already exists");
} }
} }
/** /**
* Updates an owner. This owner may include a list of pets, that will be * Updates an existing owner and its pets.
* also created or updated. If the owner does not exists it will be created.
* *
* @param ownerData an owner to be updated. * @param login owner login.
* @return an empty {@code OK} response. * @param ownerData updated owner data.
* @throws IllegalArgumentException if owner is {@code null}. * @return HTTP 200 when updated successfully.
* @throws IllegalArgumentException if login or data are null.
*/ */
@Path("{login}")
@PUT @PUT
@Path("{login}")
public Response update(@PathParam("login") String login, OwnerEditionData ownerData) { public Response update(@PathParam("login") String login, OwnerEditionData ownerData) {
requireNonNull(login, "login can't be null"); requireNonNull(login, "login can't be null");
requireNonNull(ownerData, "ownerData can't be null"); requireNonNull(ownerData, "ownerData can't be null");
final Owner owner = this.service.get(login);
ownerData.assignData(owner); final Owner owner = this.service.get(login);
this.service.update(owner); ownerData.assignData(owner);
return Response.ok().build(); 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. * @param login owner login.
* @return an empty {@code OK} response. * @return HTTP 200 when deletion succeeds.
* @throws IllegalArgumentException if {@code login} is {@code null} or if * @throws IllegalArgumentException if login is null.
* it does not identifies a valid owner.
*/ */
@Path("{login}")
@DELETE @DELETE
@Path("{login}")
public Response delete(@PathParam("login") String login) { public Response delete(@PathParam("login") String login) {
if (login == null) if (login == null)
throw new IllegalArgumentException("login can't be null"); throw new IllegalArgumentException("login can't be null");
this.service.remove(login); this.service.remove(login);
return Response.ok().build(); 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 @GET
@Path("pet/{petIdentifierType}/{petIdentifierValue}/vaccination")
public Response listVaccinations( public Response listVaccinations(
@PathParam("petIdentifierType") IdentifierType petIdentifierType, @PathParam("petIdentifierType") IdentifierType petIdentifierType,
@PathParam("petIdentifierValue") String petIdentifierValue, @PathParam("petIdentifierValue") String petIdentifierValue,
@QueryParam("page") int page, @QueryParam("page") int page,
@QueryParam("pageSize") int pageSize @QueryParam("pageSize") int pageSize) {
) {
return Response.ok(this.service.getVaccinationsFromOwnPet( return Response.ok(this.service.getVaccinationsFromOwnPet(
//login, petIdentifierType,
petIdentifierType, petIdentifierValue,
petIdentifierValue, page,
page,
pageSize pageSize
)).build(); )).build();
} }
} }
package es.uvigo.esei.xcs.rest; package es.uvigo.esei.xcs.rest;
import java.net.URI; import java.net.URI;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.ejb.EJBAccessException; import javax.ejb.EJBAccessException;
import javax.persistence.EntityExistsException; import javax.persistence.EntityExistsException;
import javax.ws.rs.Consumes; import javax.ws.rs.*;
import javax.ws.rs.DELETE; import javax.ws.rs.core.*;
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 es.uvigo.esei.xcs.domain.entities.Pet; import es.uvigo.esei.xcs.domain.entities.Pet;
import es.uvigo.esei.xcs.rest.entity.PetData; import es.uvigo.esei.xcs.rest.entity.PetData;
import es.uvigo.esei.xcs.service.PetService; 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") @Path("pet")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public class PetResource { public class PetResource {
@EJB @EJB
private PetService service; private PetService service;
@Context @Context
private UriInfo uriInfo; private UriInfo uriInfo;
/** /**
* Returns the owner identified by the login. * Returns a pet by its identifier.
* *
* @param id the identified of a pet. * @param id pet ID.
* @return an {@code OK} response containing the {@link Pet} with the * @return HTTP 200 with pet data.
* provided identifier. * @throws SecurityException if current user is not the pet's owner.
* @throws SecurityException if the current owner does not owns the pet. * @throws IllegalArgumentException if pet not found.
*/ */
@Path("{id}") @Path("{id}")
@GET @GET
public Response get(@PathParam("id") Long id) throws SecurityException { public Response get(@PathParam("id") Long id) throws SecurityException {
try { try {
final Pet pet = this.service.get(id); final Pet pet = this.service.get(id);
if (pet == null) if (pet == null)
throw new IllegalArgumentException("Pet not found: " + id); throw new IllegalArgumentException("Pet not found: " + id);
else return Response.ok(pet).build();
return Response.ok(pet).build();
} catch (EJBAccessException eae) { } catch (EJBAccessException eae) {
throw new SecurityException(eae); throw new SecurityException(eae);
} }
} }
/** /**
* Returns the complete list of pets of the current owner. * Returns a paginated list of all pets.
* *
* @return an {@code OK} response containing the complete list of pets of * @param page 0-based page index.
* the current owner. * @param pageSize number of results per page.
* @return HTTP 200 with list of pets.
*/ */
@GET @GET
@Path("lista") @Path("lista")
public Response getAll( public Response getAll(@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("page") @DefaultValue("0") int page, @QueryParam("pageSize") @DefaultValue("10") int pageSize) {
@QueryParam("pageSize") @DefaultValue("10") int pageSize) {
return Response.ok(this.service.getAll(page, pageSize)).build(); 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 @GET
public Response list( public Response list(@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("page") @DefaultValue("0") int page, @QueryParam("pageSize") @DefaultValue("10") int pageSize) {
@QueryParam("pageSize") @DefaultValue("10") int pageSize) {
return Response.ok(this.service.list(page, pageSize)).build(); 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. * @param petData data for the new pet.
* @return a {@code CREATED} response with the URI of the new pet in the * @return HTTP 201 with Location header pointing to the new pet.
* {@code Location} header. * @throws IllegalArgumentException if petData is null or pet already exists.
* @throws IllegalArgumentException if pet is {@code null} or if a pet with * @throws SecurityException if current user cannot own this pet.
* 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.
*/ */
@POST @POST
public Response create(PetData petData) throws SecurityException { public Response create(PetData petData) throws SecurityException {
if (petData == null) if (petData == null)
throw new IllegalArgumentException("pet can't be null"); throw new IllegalArgumentException("pet can't be null");
try { try {
final Pet pet = this.service.create(petData.toPet()); final Pet pet = this.service.create(petData.toPet());
final URI petUri = uriInfo.getAbsolutePathBuilder() final URI petUri = uriInfo.getAbsolutePathBuilder()
.path(String.valueOf(pet.getId())) .path(String.valueOf(pet.getId()))
.build(); .build();
return Response.created(petUri).build(); return Response.created(petUri).build();
} catch (EntityExistsException eee) { } catch (EntityExistsException eee) {
throw new IllegalArgumentException("The pet already exists"); throw new IllegalArgumentException("The pet already exists");
...@@ -115,51 +105,45 @@ public class PetResource { ...@@ -115,51 +105,45 @@ public class PetResource {
throw new SecurityException(eae); throw new SecurityException(eae);
} }
} }
/** /**
* Updates the information of a pet. If the pet is not stored, it will be * Updates an existing pet's data.
* created.
* *
* @param id the identifier of the pet to be modified. * @param id pet ID.
* @param petData a pet to be updated. * @param petData updated pet data.
* @return an empty {@code OK} response. * @return HTTP 200 when updated successfully.
* @throws IllegalArgumentException if pet is {@code null} of it has no * @throws IllegalArgumentException if petData is null or pet has no owner.
* owner. * @throws SecurityException if current user is not pet's owner.
* @throws SecurityException if the pet's owner is not the current user.
*/ */
@Path("{id}") @Path("{id}")
@PUT @PUT
public Response update(@PathParam("id") Long id, PetData petData) throws SecurityException { public Response update(@PathParam("id") Long id, PetData petData) throws SecurityException {
if (petData == null) if (petData == null)
throw new IllegalArgumentException("pet can't be null"); throw new IllegalArgumentException("pet can't be null");
try { try {
final Pet pet = this.service.get(id); final Pet pet = this.service.get(id);
petData.assignData(pet); petData.assignData(pet);
this.service.update(pet); this.service.update(pet);
return Response.ok().build(); return Response.ok().build();
} catch (EJBAccessException eae) { } catch (EJBAccessException eae) {
throw new SecurityException(eae); throw new SecurityException(eae);
} }
} }
/** /**
* Deletes a pet. * Deletes a pet by its ID.
* *
* @param id the identifier of the pet to be deleted. * @param id pet ID.
* @return an empty {@code OK} response. * @return HTTP 200 when deleted successfully.
* @throws IllegalArgumentException if there is no pet with the provided * @throws IllegalArgumentException if pet does not exist.
* identifier. * @throws SecurityException if current user is not pet's owner.
* @throws SecurityException if the pet's owner is not the current user.
*/ */
@Path("{id}") @Path("{id}")
@DELETE @DELETE
public Response delete(@PathParam("id") Long id) throws SecurityException { public Response delete(@PathParam("id") Long id) throws SecurityException {
try { try {
this.service.remove(id); this.service.remove(id);
return Response.ok().build(); return Response.ok().build();
} catch (EJBAccessException eae) { } catch (EJBAccessException eae) {
throw new SecurityException(eae); throw new SecurityException(eae);
......
...@@ -3,21 +3,21 @@ package es.uvigo.esei.xcs.rest; ...@@ -3,21 +3,21 @@ package es.uvigo.esei.xcs.rest;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.ws.rs.Consumes; import javax.ws.rs.*;
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.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import es.uvigo.esei.xcs.domain.entities.Vaccination; import es.uvigo.esei.xcs.domain.entities.Vaccination;
import es.uvigo.esei.xcs.service.VaccinationService; 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") @Path("vaccination")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
...@@ -26,32 +26,43 @@ public class VaccinationResource { ...@@ -26,32 +26,43 @@ public class VaccinationResource {
@EJB @EJB
private VaccinationService vaccinationService; 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 @GET
@Path("canVaccinate/{petId}/{vaccineId}") @Path("canVaccinate/{petId}/{vaccineId}")
public Response canVaccinate( public Response canVaccinate(@PathParam("petId") Long petId,
@PathParam("petId") Long petId, @PathParam("vaccineId") Long vaccineId) {
@PathParam("vaccineId") Long vaccineId
) {
Date now = new Date(); Date now = new Date();
Boolean result = vaccinationService.canVaccinate(petId, vaccineId, now); Boolean result = vaccinationService.canVaccinate(petId, vaccineId, now);
return Response.ok(result).build(); 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 @POST
@Path("create/{petId}/{vaccineId}") @Path("create/{petId}/{vaccineId}")
public Response createVaccination( public Response createVaccination(@PathParam("petId") Long petId,
@PathParam("petId") Long petId, @PathParam("vaccineId") Long vaccineId,
@PathParam("vaccineId") Long vaccineId, @QueryParam("date") String textDate) {
@QueryParam("date") String textDate
) {
Date date = new Date(); Date date = new Date();
if (textDate != null) { if (textDate != null) {
try { try {
date = new SimpleDateFormat("yyyy-MM-dd").parse(textDate); date = new SimpleDateFormat("yyyy-MM-dd").parse(textDate);
} catch (ParseException e) { } catch (ParseException e) {
return Response.status(Response.Status.BAD_REQUEST) 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 { ...@@ -60,8 +71,8 @@ public class VaccinationResource {
return Response.ok(vaccination).build(); return Response.ok(vaccination).build();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return Response.status(Response.Status.BAD_REQUEST) return Response.status(Response.Status.BAD_REQUEST)
.entity(e.getMessage()).build(); .entity(e.getMessage())
.build();
} }
} }
} }
package es.uvigo.esei.xcs.rest; package es.uvigo.esei.xcs.rest;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import java.net.URI; import java.net.URI;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.ws.rs.*; import javax.ws.rs.*;
...@@ -12,6 +11,10 @@ import es.uvigo.esei.xcs.rest.entity.VaccineCreationData; ...@@ -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.rest.entity.VaccineEditionData;
import es.uvigo.esei.xcs.service.VaccineService; import es.uvigo.esei.xcs.service.VaccineService;
/**
* REST resource for managing vaccines.
* Provides endpoints to list, create, update, and delete vaccines.
*/
@Path("vaccine") @Path("vaccine")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
...@@ -23,12 +26,26 @@ public class VaccineResource { ...@@ -23,12 +26,26 @@ public class VaccineResource {
@Context @Context
private UriInfo uriInfo; 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 @GET
public Response list(@QueryParam("page") @DefaultValue("0") int page, public Response list(@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("pageSize") @DefaultValue("10") int pageSize) { @QueryParam("pageSize") @DefaultValue("10") int pageSize) {
return Response.ok(vaccineService.list(page, pageSize)).build(); 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 @POST
public Response create(VaccineCreationData vaccineData) { public Response create(VaccineCreationData vaccineData) {
requireNonNull(vaccineData, "vaccineData can't be null"); requireNonNull(vaccineData, "vaccineData can't be null");
...@@ -42,7 +59,15 @@ public class VaccineResource { ...@@ -42,7 +59,15 @@ public class VaccineResource {
URI uri = uriInfo.getAbsolutePathBuilder().path(String.valueOf(vaccine.getId())).build(); URI uri = uriInfo.getAbsolutePathBuilder().path(String.valueOf(vaccine.getId())).build();
return Response.created(uri).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 @PUT
@Path("{id}/name") @Path("{id}/name")
public Response updateName(@PathParam("id") Long id, String newName) { public Response updateName(@PathParam("id") Long id, String newName) {
...@@ -51,7 +76,14 @@ public class VaccineResource { ...@@ -51,7 +76,14 @@ public class VaccineResource {
return Response.ok(updated).build(); 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 @PUT
@Path("{id}") @Path("{id}")
public Response update(@PathParam("id") Long id, VaccineEditionData vaccineData) { public Response update(@PathParam("id") Long id, VaccineEditionData vaccineData) {
...@@ -62,6 +94,13 @@ public class VaccineResource { ...@@ -62,6 +94,13 @@ public class VaccineResource {
return Response.ok().build(); 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 @DELETE
@Path("{id}") @Path("{id}")
public Response delete(@PathParam("id") Long id) { public Response delete(@PathParam("id") Long id) {
......
package es.uvigo.esei.xcs.rest; package es.uvigo.esei.xcs.rest;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import java.net.URI; import java.net.URI;
import java.util.Date; import java.util.Date;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.ejb.EJBAccessException; import javax.ejb.EJBAccessException;
import javax.ws.rs.Consumes; import javax.ws.rs.*;
import javax.ws.rs.DELETE; import javax.ws.rs.core.*;
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 es.uvigo.esei.xcs.domain.entities.IdentifierType; import es.uvigo.esei.xcs.domain.entities.IdentifierType;
import es.uvigo.esei.xcs.domain.entities.Vaccination; import es.uvigo.esei.xcs.domain.entities.Vaccination;
...@@ -39,201 +25,265 @@ import es.uvigo.esei.xcs.service.VetService; ...@@ -39,201 +25,265 @@ import es.uvigo.esei.xcs.service.VetService;
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public class VetResource { public class VetResource {
@EJB @EJB
private VetService vetService; private VetService vetService;
@EJB @EJB
private PetService petService; private PetService petService;
@EJB @EJB
private VaccineService vaccineService; private VaccineService vaccineService;
@EJB @EJB
private VaccinationService vaccinationService; private VaccinationService vaccinationService;
@Context @Context
private UriInfo uriInfo; private UriInfo uriInfo;
@GET /**
@Path("{login}") * Returns a vet by login.
public Response get(@PathParam("login") String login) { *
* @param login vet login.
return Response.ok(vetService.get(login)).build(); * @return HTTP 200 with the vet.
} */
@GET
@GET @Path("{login}")
public Response list() { public Response get(@PathParam("login") String login) {
return Response.ok(vetService.get(login)).build();
return Response.ok(vetService.list()).build(); }
}
/**
@POST * Returns the list of all vets.
public Response create(VetData vetData) { *
requireNonNull(vetData); * @return HTTP 200 with the list of vets.
*/
try { @GET
final Vet vet = this.vetService.create(vetData.toVet()); public Response list() {
return Response.ok(vetService.list()).build();
final URI vetUri = uriInfo.getAbsolutePathBuilder() }
.path(vet.getLogin()).build();
/**
return Response.created(vetUri).build(); * Creates a new vet.
} catch (Exception e) { *
throw new SecurityException(e); * @param vetData data of the vet to create.
} * @return HTTP 201 with the URI of the created vet.
} * @throws SecurityException if creation fails.
*/
@POST
@Path("{login}") public Response create(VetData vetData) {
@DELETE requireNonNull(vetData, "vetData can't be null");
public Response delete(@PathParam("login") String login) {
try { try {
this.vetService.remove(login); final Vet vet = this.vetService.create(vetData.toVet());
final URI vetUri = uriInfo.getAbsolutePathBuilder()
return Response.ok().build(); .path(vet.getLogin()).build();
} catch (EJBAccessException e) { return Response.created(vetUri).build();
throw new SecurityException(e); } catch (Exception e) {
} throw new SecurityException(e);
}
} }
@GET /**
@Path("pets") * Deletes a vet by login.
public Response listPets( *
@QueryParam("page") @DefaultValue("0") int page, * @param login vet login.
@QueryParam("pageSize") @DefaultValue("10") int pageSize * @return HTTP 200 when deleted successfully.
) { * @throws SecurityException if deletion fails due to access control.
return Response.ok(this.vetService.getPets(page, pageSize)).build(); */
} @Path("{login}")
@DELETE
public Response delete(@PathParam("login") String login) {
@GET try {
@Path("pets/{petId}") this.vetService.remove(login);
public Response getPet(@PathParam("petId") Long petId) { return Response.ok().build();
return Response.ok(this.petService.get(petId)).build(); } catch (EJBAccessException e) {
} throw new SecurityException(e);
}
}
@GET
@Path("vaccine") /**
public Response listVaccines(@QueryParam("page") int page, @QueryParam("pageSize") int pageSize) { * Returns a paginated list of pets for the current vet.
return Response.ok(this.vaccineService.list(page, pageSize)).build(); *
} * @param page 0-based page index.
* @param pageSize number of pets per page.
* @return HTTP 200 with the list of pets.
@POST */
@Path("vaccine") @GET
public Response createVaccine(VaccineCreationData vaccineData) { @Path("pets")
Vaccine vaccine = this.vaccineService.create( public Response listPets(@QueryParam("page") @DefaultValue("0") int page,
vaccineData.getName(), @QueryParam("pageSize") @DefaultValue("10") int pageSize) {
vaccineData.getType(), return Response.ok(this.vetService.getPets(page, pageSize)).build();
vaccineData.getDoses(), }
vaccineData.getPeriodicType(),
vaccineData.getPeriode() /**
); * Returns a specific pet by ID.
return Response.ok(vaccine).build(); *
* @param petId pet ID.
} * @return HTTP 200 with the pet.
*/
@Path("vaccine/{id}") @GET
@PUT @Path("pets/{petId}")
public Response updateVaccine(@PathParam("id") Long id, VaccineEditionData vaccineData) { public Response getPet(@PathParam("petId") Long petId) {
if (vaccineData == null) { return Response.ok(this.petService.get(petId)).build();
throw new IllegalArgumentException("vaccineData can't be null"); }
}
final Vaccine vaccine = this.vaccineService.get(id); /**
vaccineData.assignData(vaccine); * Returns a paginated list of vaccines.
this.vaccineService.update(vaccine); *
return Response.ok().build(); * @param page 0-based page index.
} * @param pageSize number of vaccines per page.
* @return HTTP 200 with the list of vaccines.
@Path("vaccine/{id}") */
@DELETE @GET
public Response deleteVaccine(@PathParam("id") Long id) { @Path("vaccine")
try { public Response listVaccines(@QueryParam("page") int page,
this.vaccineService.remove(id); @QueryParam("pageSize") int pageSize) {
return Response.ok().build(); return Response.ok(this.vaccineService.list(page, pageSize)).build();
} catch (EJBAccessException e) { }
throw new SecurityException(e);
} /**
} * Creates a new vaccine.
*
@Path("pet/{petIdentifierType}/{petIdentifierValue}/vaccination") * @param vaccineData data to create the vaccine.
@GET * @return HTTP 200 with the created vaccine.
public Response listVaccinations( */
@PathParam("petIdentifierType") IdentifierType petIdentifierType, @POST
@PathParam("petIdentifierValue") String petIdentifierValue, @Path("vaccine")
@QueryParam("page") int page, public Response createVaccine(VaccineCreationData vaccineData) {
@QueryParam("pageSize") int pageSize Vaccine vaccine = this.vaccineService.create(
) { vaccineData.getName(),
vaccineData.getType(),
return Response.ok(this.vetService.getVaccinationsFromOwnPet( vaccineData.getDoses(),
//login, vaccineData.getPeriodicType(),
petIdentifierType, vaccineData.getPeriode()
petIdentifierValue, );
page, return Response.ok(vaccine).build();
pageSize }
)).build();
} /**
* Updates a vaccine.
@Path("vaccination") *
@POST * @param id vaccine ID.
public Response registerVaccination( * @param vaccineData data to update the vaccine.
@QueryParam("date") Date date, * @return HTTP 200 when updated successfully.
VaccinationCreationData vaccinationData * @throws IllegalArgumentException if vaccineData is null.
) { */
if (date == null) { @Path("vaccine/{id}")
date = new Date(); @PUT
} public Response updateVaccine(@PathParam("id") Long id, VaccineEditionData vaccineData) {
Vaccination vaccination = this.vaccinationService.create( requireNonNull(vaccineData, "vaccineData can't be null");
vaccinationData.getPetId(), final Vaccine vaccine = this.vaccineService.get(id);
vaccinationData.getVaccineId(), vaccineData.assignData(vaccine);
date this.vaccineService.update(vaccine);
); return Response.ok().build();
}
final URI vaccinationUri = uriInfo.getAbsolutePathBuilder()
.path(String.valueOf(vaccination.getId())).build(); /**
* Deletes a vaccine by ID.
return Response.created(vaccinationUri).build(); *
} * @param id vaccine ID.
* @return HTTP 200 when deleted successfully.
* @throws SecurityException if deletion fails due to access control.
@POST */
@Path("/assign/pets/{petId}") @Path("vaccine/{id}")
public Response assignVetToPet( @DELETE
@PathParam("petId") Long petId public Response deleteVaccine(@PathParam("id") Long id) {
) { try {
requireNonNull(petId, "petId can't be null"); this.vaccineService.remove(id);
return Response.ok().build();
try { } catch (EJBAccessException e) {
petService.assignVetToPet(petId); throw new SecurityException(e);
return Response.ok() }
.build(); }
} catch (IllegalArgumentException e) {
return Response.status(Response.Status.NOT_FOUND) /**
.entity(e.getMessage()) * Returns paginated list of vaccinations of a pet owned by the current vet.
.build(); *
} * @param petIdentifierType type of the pet's identifier.
} * @param petIdentifierValue value of the pet's identifier.
* @param page 0-based page index.
@DELETE * @param pageSize number of vaccinations per page.
@Path("{login}/unassign/pets/{petId}") * @return HTTP 200 with the list of vaccinations.
public Response unassignVetFromPet( */
@PathParam("petId") Long petId @Path("pet/{petIdentifierType}/{petIdentifierValue}/vaccination")
) { @GET
requireNonNull(petId, "petId can't be null"); public Response listVaccinations(@PathParam("petIdentifierType") IdentifierType petIdentifierType,
@PathParam("petIdentifierValue") String petIdentifierValue,
try { @QueryParam("page") int page,
petService.unassignVetFromPet(petId); @QueryParam("pageSize") int pageSize) {
return Response.ok() return Response.ok(this.vetService.getVaccinationsFromOwnPet(
.build(); petIdentifierType,
} catch (IllegalArgumentException e) { petIdentifierValue,
return Response.status(Response.Status.NOT_FOUND) page,
.entity(e.getMessage()) pageSize
.build(); )).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();
}
}
} }
package es.uvigo.esei.xcs.service; package es.uvigo.esei.xcs.service;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import java.util.List; import java.util.List;
...@@ -12,49 +11,62 @@ import javax.persistence.PersistenceContext; ...@@ -12,49 +11,62 @@ import javax.persistence.PersistenceContext;
import es.uvigo.esei.xcs.domain.entities.Administrator; import es.uvigo.esei.xcs.domain.entities.Administrator;
import es.uvigo.esei.xcs.domain.entities.User; 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 @Stateless
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public class AdministratorService { public class AdministratorService {
@PersistenceContext
EntityManager em; @PersistenceContext
private EntityManager em;
public Administrator get(int id) { /**
return em.find(Administrator.class, id); * Returns an administrator by its ID.
} */
public Administrator get(int id) {
return em.find(Administrator.class, id);
public List<User> list(int page, int pageSize){ }
if (page < 0) {
throw new IllegalArgumentException("The page can't be negative"); /**
} * Returns a paginated list of all users.
if (pageSize <= 0) { */
throw new IllegalArgumentException("The page size can't be negative or zero"); public List<User> list(int page, int pageSize) {
} if (page < 0) throw new IllegalArgumentException("The page can't be negative");
return em.createQuery("SELECT DISTINCT u FROM User u", User.class) if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero");
.setFirstResult(page * pageSize)
.setMaxResults(pageSize) return em.createQuery("SELECT DISTINCT u FROM User u", User.class)
.getResultList(); .setFirstResult(page * pageSize)
.setMaxResults(pageSize)
} .getResultList();
}
public Administrator create(Administrator administrator) { /**
requireNonNull(Administrator.class, "Administrator can't be null"); * Persists a new administrator entity.
em.persist(administrator); */
public Administrator create(Administrator administrator) {
return administrator; requireNonNull(administrator, "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); * Updates an existing administrator.
} */
public Administrator update(Administrator administrator) {
requireNonNull(administrator, "Administrator can't be null");
public void remove(int id) { return em.merge(administrator);
em.remove(this.get(id)); }
}
/**
* Removes an administrator by ID.
*/
public void remove(int id) {
em.remove(this.get(id));
}
} }
...@@ -7,46 +7,64 @@ import javax.ejb.Singleton; ...@@ -7,46 +7,64 @@ import javax.ejb.Singleton;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext; 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 @Singleton
public class CounterService { public class CounterService {
@PersistenceContext @PersistenceContext
EntityManager em; private EntityManager em;
private Long vaccineCounter; private Long vaccineCounter;
private Long petCounter; private Long petCounter;
/**
* Initializes counters with the current counts from the database.
*/
@PostConstruct @PostConstruct
public void init() { public void init() {
this.petCounter = em this.petCounter = em.createQuery("SELECT COUNT(p) FROM Pet p", Long.class)
.createQuery("SELECT COUNT(p) FROM Pet p", Long.class) .getSingleResult();
.getSingleResult();
this.vaccineCounter = em
.createQuery("SELECT COUNT(v) FROM Vaccine v", 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) @Lock(LockType.WRITE)
public void incrementPetCounter() { public void incrementPetCounter() {
this.petCounter++; this.petCounter++;
} }
/**
* Increments the vaccine counter by one.
*/
@Lock(LockType.WRITE) @Lock(LockType.WRITE)
public void incrementVaccineCounter() { public void incrementVaccineCounter() {
this.vaccineCounter++; this.vaccineCounter++;
} }
/**
* Returns the current pet counter value.
*/
@Lock(LockType.READ) @Lock(LockType.READ)
public Long getPetCounter() { public Long getPetCounter() {
return this.petCounter; return this.petCounter;
} }
/**
* Returns the current vaccine counter value.
*/
@Lock(LockType.READ) @Lock(LockType.READ)
public Long getVaccineCounter() { public Long getVaccineCounter() {
return this.vaccineCounter; return this.vaccineCounter;
} }
} }
...@@ -7,21 +7,40 @@ import javax.persistence.PersistenceContext; ...@@ -7,21 +7,40 @@ import javax.persistence.PersistenceContext;
import es.uvigo.esei.xcs.domain.entities.Identifier; import es.uvigo.esei.xcs.domain.entities.Identifier;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
/**
* EJB for managing Identifier entities.
* Provides basic operations for creation and removal.
*
* @author Breixo Senra
*/
@Stateless @Stateless
public class IdentifierService { public class IdentifierService {
@PersistenceContext
EntityManager em; @PersistenceContext
private EntityManager em;
public Identifier create(Identifier identifier) { /**
requireNonNull(identifier, "Identifier can't be null"); * Persists a new identifier.
em.persist(identifier); *
return identifier; * @param identifier the Identifier entity to persist.
} * @return the persisted Identifier entity.
* @throws NullPointerException if {@code identifier} is null.
public void remove(String value) { */
Identifier identifier = em.find(Identifier.class, value); public Identifier create(Identifier identifier) {
em.remove(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);
}
}
} }
...@@ -5,7 +5,6 @@ import static java.util.Objects.requireNonNull; ...@@ -5,7 +5,6 @@ import static java.util.Objects.requireNonNull;
import java.security.Principal; import java.security.Principal;
import java.util.List; import java.util.List;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed; import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless; import javax.ejb.Stateless;
import javax.inject.Inject; import javax.inject.Inject;
...@@ -13,183 +12,179 @@ import javax.persistence.EntityExistsException; ...@@ -13,183 +12,179 @@ import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext; 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.IdentifierType;
import es.uvigo.esei.xcs.domain.entities.Owner; import es.uvigo.esei.xcs.domain.entities.Owner;
import es.uvigo.esei.xcs.domain.entities.Pet; import es.uvigo.esei.xcs.domain.entities.Pet;
import es.uvigo.esei.xcs.domain.entities.Vaccination; 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 @Stateless
@RolesAllowed({"ADMIN", "OWNER"}) @RolesAllowed({"ADMIN", "OWNER"})
public class OwnerService { public class OwnerService {
@PersistenceContext
private EntityManager em; @PersistenceContext
private EntityManager em;
@Inject
private Principal currentUser; @Inject
private Principal currentUser;
public int countAll() { /**
Long count = em.createQuery("SELECT COUNT(o) FROM Owner o", Long.class) * Counts all owners in the system.
.getSingleResult(); *
return count.intValue(); * @return the total number of owners.
} */
public int countAll() {
Long count = em.createQuery("SELECT COUNT(o) FROM Owner o", Long.class)
/** .getSingleResult();
* Returns the owner identified by {@code login}. If there is no owner with return count.intValue();
* 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 * Returns the owner identified by {@code login}.
* owner with the specified login. *
* @throws IllegalArgumentException if {@code login} is {@code null} or it * @param login the login of an owner.
* does not identifies a valid 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); public Owner get(String login) {
} return em.find(Owner.class, login);
}
/**
* Returns the complete list of owners. /**
* * Returns a paginated list of owners.
* @return the complete list of owners. *
*/ * @param first the starting index (0-based) of the first owner.
public List<Owner> list(int first, int pageSize) { * @param pageSize the maximum number of owners to return.
if (first < 0) throw new IllegalArgumentException("First can't be negative"); * @return the list of owners in the specified page.
if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); * @throws IllegalArgumentException if {@code first} is negative or {@code pageSize} is not positive.
*/
return em.createQuery("SELECT o FROM Owner o", Owner.class) public List<Owner> list(int first, int pageSize) {
.setFirstResult(first) if (first < 0) throw new IllegalArgumentException("First can't be negative");
.setMaxResults(pageSize) if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive");
.getResultList();
} return em.createQuery("SELECT o FROM Owner o", Owner.class)
.setFirstResult(first)
/** .setMaxResults(pageSize)
* Returns the list of owners that have a pet with the specified name. .getResultList();
* }
* @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. * Returns the list of owners that have a pet with the specified name.
* @throws IllegalArgumentException if {@code petName} is {@code null}. *
*/ * @param petName the name of the pet.
public List<Owner> findByPetName(String petName) { * @return the list of owners with a pet matching the name.
if (petName == null) * @throws IllegalArgumentException if {@code petName} is {@code null}.
throw new IllegalArgumentException("petName can't be null"); */
public List<Owner> findByPetName(String petName) {
final String query = "SELECT o FROM Owner o JOIN o.pets p " + if (petName == null)
"WHERE p.name = :petName"; throw new IllegalArgumentException("petName can't be null");
return em.createQuery(query, Owner.class) final String query = "SELECT o FROM Owner o JOIN o.pets p WHERE p.name = :petName";
.setParameter("petName", petName) return em.createQuery(query, Owner.class)
.getResultList(); .setParameter("petName", petName)
} .getResultList();
}
/**
* Creates a new owner. If the owner already has pets, they will be created /**
* too. * Creates a new owner along with any pets associated.
* *
* @param owner a new owner to be stored. * @param owner the owner to create.
* @return the persistent version of the owner created. * @return the persistent version of the created owner.
* @throws IllegalArgumentException if {@code owner} is {@code null}. * @throws IllegalArgumentException if {@code owner} is {@code null}.
* @throws EntityExistsException if an owner with the same login already * @throws EntityExistsException if an owner with the same login already exists.
* exists. */
*/ public Owner create(Owner owner) {
public Owner create(Owner owner) { if (owner == null)
if (owner == null) throw new IllegalArgumentException("owner can't be null");
throw new IllegalArgumentException("owner can't be null");
this.em.persist(owner);
this.em.persist(owner); return owner;
}
return owner;
} /**
* Updates an existing owner. If the owner does not exist, it will be persisted.
/** *
* Updates a new owner. If the owner is not stored, it will be persisted. * @param owner the owner to update.
* * @return the updated owner.
* @param owner an owner to be updated. * @throws IllegalArgumentException if {@code owner} is {@code null}.
* @return the updated owner. */
* @throws IllegalArgumentException if {@code owner} is {@code null}. public Owner update(Owner owner) {
*/ if (owner == null)
public Owner update(Owner owner) { throw new IllegalArgumentException("owner can't be null");
if (owner == null)
throw new IllegalArgumentException("owner can't be null"); return em.merge(owner);
}
return em.merge(owner);
} /**
* Deletes an owner by login.
/** *
* Deletes an owner. * @param login the login of the owner to delete.
* * @throws IllegalArgumentException if {@code login} is {@code null}.
* @param login the login of the owner to be deleted. */
* @throws IllegalArgumentException if {@code login} is {@code null} or if public void remove(String login) {
* it does not identifies a valid owner. Owner owner = this.get(login);
*/ em.remove(owner);
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.
* Returns the list of pets of an owner. * @param first the starting index (0-based).
* * @param pageSize the maximum number of pets to return.
* @param login the login of the owner that owns the pets. * @return the list of pets for the owner.
* @return the list of pets of an owner. * @throws IllegalArgumentException if {@code login} is {@code null}, {@code first} is negative, or {@code pageSize} is not positive.
* @throws IllegalArgumentException if {@code login} is {@code null} or it */
* does not identifies a valid owner. public List<Pet> getPets(String login, int first, int pageSize) {
*/ if (first < 0) throw new IllegalArgumentException("First can't be negative");
public List<Pet> getPets(String login, int first, int pageSize) { if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive");
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)
return em.createQuery("SELECT p FROM Owner o " .setMaxResults(pageSize)
+ "JOIN o.pets p " .setParameter("login", login)
+ "WHERE " .getResultList();
+ "o.login = :login", }
Pet.class)
.setFirstResult(first) /**
.setMaxResults(pageSize) * Returns a paginated list of vaccinations for a pet of the current user, identified by an identifier type and value.
.setParameter("login", login) *
.getResultList(); * @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.
public List<Vaccination> getVaccinationsFromOwnPet( * @return the list of vaccinations.
IdentifierType identifierType, * @throws NullPointerException if {@code identifierType} or {@code identifierValue} is {@code null}.
String identifierValue, * @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive.
int page, */
int pageSize public List<Vaccination> getVaccinationsFromOwnPet(
){ IdentifierType identifierType,
requireNonNull(identifierType, "pet's identifier type can't be null"); String identifierValue,
requireNonNull(identifierValue, "pet's identifier value can't be null"); int page,
int pageSize
if (page < 0) { ) {
throw new IllegalArgumentException("The page can't be negative"); requireNonNull(identifierType, "pet's identifier type can't be null");
} requireNonNull(identifierValue, "pet's identifier value can't be null");
if (pageSize <= 0) {
throw new IllegalArgumentException("The page size can't be negative or zero"); 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 " return em.createQuery(
+ "JOIN o.pets p " "SELECT v FROM Owner o " +
+ "JOIN p.identifiers i " "JOIN o.pets p " +
+ "JOIN p.vaccinations v " "JOIN p.identifiers i " +
+ "WHERE " "JOIN p.vaccinations v " +
+ "o.login = :login AND " "WHERE o.login = :login AND i.type = :identifierType AND i.value = :identifierValue",
+ "i.type = :identifierType AND " Vaccination.class)
+ "i.value = :identifierValue", .setParameter("login", currentUser.getName())
Vaccination.class) .setParameter("identifierType", identifierType)
.setParameter("login", currentUser.getName()) .setParameter("identifierValue", identifierValue)
.setParameter("identifierType", identifierType) .setFirstResult(page * pageSize)
.setParameter("identifierValue", identifierValue) .setMaxResults(pageSize)
.setFirstResult(page * pageSize) .getResultList();
.setMaxResults(pageSize) }
.getResultList();
}
} }
...@@ -2,12 +2,10 @@ package es.uvigo.esei.xcs.service; ...@@ -2,12 +2,10 @@ package es.uvigo.esei.xcs.service;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import java.io.Console;
import java.security.Principal; import java.security.Principal;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed; import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.ejb.EJBAccessException; import javax.ejb.EJBAccessException;
...@@ -19,242 +17,245 @@ import javax.persistence.PersistenceContext; ...@@ -19,242 +17,245 @@ import javax.persistence.PersistenceContext;
import es.uvigo.esei.xcs.domain.entities.AnimalType; import es.uvigo.esei.xcs.domain.entities.AnimalType;
import es.uvigo.esei.xcs.domain.entities.Owner; import es.uvigo.esei.xcs.domain.entities.Owner;
import es.uvigo.esei.xcs.domain.entities.Pet; 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.Vaccine;
import es.uvigo.esei.xcs.domain.entities.Vet; import es.uvigo.esei.xcs.domain.entities.Vet;
/** /**
* EJB for the Pets. Only owners have access to this class, and only to their * EJB for managing Pets. Access is restricted to VET and OWNER roles.
* own pets. * Owners can only access their own pets.
* *
* @author Miguel Reboiro Jato * @author Breixo Senra
*/ */
@Stateless @Stateless
@RolesAllowed({"VET", "OWNER"}) @RolesAllowed({"VET", "OWNER"})
public class PetService { public class PetService {
@Inject
private Principal currentUser; @Inject
private Principal currentUser;
@EJB
private EmailService emailService; @EJB
private EmailService emailService;
@PersistenceContext
private EntityManager em; @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. * Counts all pets in the system.
* *
* @param id the identified of a pet. * @return the total number of pets.
* @return a pet identified by the provided identifier or {@code null} if no */
* pet exists with the provided identifier. public int countAll() {
* @throws EJBAccessException if the current owner does not owns the pet. Long count = em.createQuery("SELECT COUNT(p) FROM Pet p", Long.class)
*/ .getSingleResult();
/*public Pet get(Long id) { return count.intValue();
final Pet pet = em.find(Pet.class, id); }
if (pet == null) { /**
return null; * Returns a pet identified by the provided id.
} else if (pet.getOwner().getLogin().equals(this.currentOwner.getName())) { *
return pet; * @param id the identifier of the pet.
} else { * @return the pet or {@code null} if not found.
throw new EJBAccessException("Pet's owner is not the current principal"); */
} public Pet get(Long id) {
}*/ return em.find(Pet.class, id);
public int countAll() { }
Long count = em.createQuery("SELECT COUNT(p) FROM Pet p", Long.class)
.getSingleResult(); /**
return count.intValue(); * 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.
public Pet get(Long id) { * @return a list of pets.
return em.find(Pet.class, id); * @throws IllegalArgumentException if {@code first} is negative or {@code pageSize} is not positive.
} */
public List<Pet> getAll(int first, int pageSize) {
/*public List<Pet> getAll(int page, int pageSize) { if (first < 0) throw new IllegalArgumentException("First can't be negative");
if (page < 0) { if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive");
throw new IllegalArgumentException("The page can't be negative");
} return em.createQuery("SELECT p FROM Pet p", Pet.class)
if (pageSize <= 0) { .setFirstResult(first)
throw new IllegalArgumentException("The page size can't be negative or zero"); .setMaxResults(pageSize)
} .getResultList();
return em.createQuery("SELECT p FROM Pet p", Pet.class) }
.setFirstResult(page * pageSize)
.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.
public List<Pet> getAll(int first, int pageSize) { * @param pageSize the maximum number of pets per page.
if (first < 0) throw new IllegalArgumentException("First can't be negative"); * @return the list of pets of the current owner.
if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); * @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive.
*/
return em.createQuery("SELECT p FROM Pet p", Pet.class) public List<Pet> list(int page, int pageSize) {
.setFirstResult(first) // no multiplicar por pageSize if (page < 0) throw new IllegalArgumentException("The page can't be negative");
.setMaxResults(pageSize) if (pageSize <= 0) throw new IllegalArgumentException("The page size must be negative or zero");
.getResultList();
} 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();
* Returns the complete list of pets of the current owner. }
*
* @return the complete list of pets of the current owner. /**
*/ * Creates a new pet for the current owner.
public List<Pet> list(int page, int pageSize) { *
if (page < 0) { * @param pet the pet to create.
throw new IllegalArgumentException("The page can't be negative"); * @return the persistent version of the pet.
} * @throws IllegalArgumentException if {@code pet} is null.
if (pageSize <= 0) { * @throws EJBAccessException if the pet already has an owner different from the current user.
throw new IllegalArgumentException("The page size can't be negative or zero"); */
} public Pet create(Pet pet) {
return em.createQuery("SELECT p FROM Pet p WHERE p.owner.login = :login", Pet.class) requireNonNull(pet, "Pet can't be null");
.setFirstResult(page * pageSize)
.setMaxResults(pageSize) final Owner owner = em.find(Owner.class, currentUser.getName());
.setParameter("login", currentUser.getName())
.getResultList(); 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);
* Creates a new pet owned by the current user. em.persist(pet);
* return pet;
* @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. * Convenience method to create a new pet with basic attributes.
* @throws IllegalArgumentException if a pet with the same identifier */
* already exists. public Pet createPet(String name, AnimalType animal, Date birth) {
*/ Owner owner = em.find(Owner.class, currentUser.getName());
public Pet create(Pet pet) { Pet pet = new Pet(name, animal, birth, owner);
requireNonNull(pet, "Pet can't be null"); em.persist(pet);
return pet;
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"); * Updates an existing pet. If the pet does not exist, it will be persisted.
} else { *
pet.setOwner(owner); * @param pet the pet to update.
* @return the updated pet.
this.em.persist(pet); * @throws IllegalArgumentException if the pet has no owner.
* @throws EJBAccessException if the pet's owner is not the current user.
return pet; */
} public Pet update(Pet pet) {
} if (pet.getOwner() == null)
throw new IllegalArgumentException("Pet must have an owner");
public Pet createPet(String name, AnimalType animal, Date birth) {
Owner owner = em.find(Owner.class, currentUser.getName()); if (pet.getOwner().getLogin().equals(currentUser.getName())) {
Pet pet = new Pet(name, animal, birth, owner); return em.merge(pet);
this.em.persist(pet); } else {
return pet; 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<Vaccine> 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 * Unassigns the current vet from a pet.
* created.
* *
* @param pet a pet to be updated. * @param petId the identifier of the pet.
* @return the updated pet. * @throws NullPointerException if {@code petId} is null.
* @throws IllegalArgumentException if the pet has no owner. * @throws IllegalArgumentException if the pet or vet does not exist.
* @throws EJBAccessException if the pet's owner is not the current user.
*/ */
public Pet update(Pet pet) { @RolesAllowed("VET")
if (pet.getOwner() == null) public void unassignVetFromPet(Long petId) {
throw new IllegalArgumentException("Pet must have an owner"); requireNonNull(petId, "Pet ID can't be null");
if (pet.getOwner().getLogin().equals(this.currentUser.getName())) { Pet pet = em.find(Pet.class, petId);
return em.merge(pet); if (pet == null) throw new IllegalArgumentException("Pet not found");
} else {
throw new EJBAccessException("Pet's owner is not the current principal"); 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. * @return the current Principal.
* @throws IllegalArgumentException if there is no pet with the provided
* identifier.
* @throws EJBAccessException if the pet's owner is not the current user.
*/ */
public void remove(Long id) { public Principal getCurrentUser() {
final Pet pet = this.get(id); return this.currentUser;
pet.setOwner(null); }
em.remove(pet);
} /**
* Checks if the current vet is assigned to a given pet.
public List<Vaccine> getVaccinesByPetId(Long id, int page, int pageSize){ *
if (page < 0) { * @param petId the identifier of the pet.
throw new IllegalArgumentException("The page can't be negative"); * @return {@code true} if the current vet is assigned to the pet, {@code false} otherwise.
} * @throws NullPointerException if {@code petId} is null.
if (pageSize <= 0) { */
throw new IllegalArgumentException("The page size can't be negative or zero"); @RolesAllowed("VET")
} public boolean isAssignedToCurrentVet(Long petId) {
return em.createQuery("SELECT v.pet FROM Vaccination v WHERE v.pet.id = :id", Vaccine.class) requireNonNull(petId, "Pet ID can't be null");
.setFirstResult(page * pageSize)
.setMaxResults(pageSize) Long count = em.createQuery(
.getResultList(); "SELECT COUNT(p) FROM Pet p JOIN p.vets v WHERE p.id = :petId AND v.login = :login",
} Long.class
)
.setParameter("petId", petId)
@RolesAllowed("VET") .setParameter("login", currentUser.getName())
public void assignVetToPet(Long petId) { .getSingleResult();
requireNonNull(petId, "Pet ID can't be null");
//requireNonNull(vetLogin, "Vet login can't be null"); return count > 0;
}
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;
}
} }
...@@ -13,52 +13,80 @@ import javax.persistence.PersistenceContext; ...@@ -13,52 +13,80 @@ import javax.persistence.PersistenceContext;
import es.uvigo.esei.xcs.domain.entities.User; 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 @Stateless
@RolesAllowed({"OWNER", "ADMIN", "VET"}) @RolesAllowed({"OWNER", "ADMIN", "VET"})
public class UserService { public class UserService {
@PersistenceContext
private EntityManager em;
@Inject
private Principal principal;
/** @PersistenceContext
* Returns the current user entity. private EntityManager em;
*
* @return the entity with the information of the current user. @Inject
*/ private Principal principal;
public User getCurrentUser() {
return this.em.find(User.class, this.principal.getName()); /**
} * Returns the entity of the currently authenticated user.
*
public User get(String login) { * @return the current User entity.
return this.em.find(User.class, login); */
} public User getCurrentUser() {
return this.em.find(User.class, this.principal.getName());
public List<User> list(int page, int pageSize){ }
if (page < 0) {
throw new IllegalArgumentException("The page can't be negative"); /**
} * Returns a user by login.
if (pageSize <= 0) { *
throw new IllegalArgumentException("The page size can't be negative or zero"); * @param login the login of the user.
} * @return the User entity, or {@code null} if not found.
return this.em.createQuery("SELECT DISTINCT u FROM User u", User.class) */
.setFirstResult(page * pageSize) public User get(String login) {
.setMaxResults(pageSize) return this.em.find(User.class, login);
.getResultList(); }
}
/**
public User create(User user) { * Returns a paginated list of users (0-based page index).
requireNonNull(user, "User can't be null"); *
this.em.persist(user); * @param page the 0-based page index.
return user; * @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 void remove(String login) { */
User user = this.get(login); public List<User> list(int page, int pageSize) {
this.em.remove(user); 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);
}
} }
...@@ -4,11 +4,8 @@ import java.util.Date; ...@@ -4,11 +4,8 @@ import java.util.Date;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import java.security.Principal; import java.security.Principal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List; import java.util.List;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed; import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.ejb.Stateless; import javax.ejb.Stateless;
...@@ -22,120 +19,154 @@ import es.uvigo.esei.xcs.domain.entities.Pet; ...@@ -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.Vaccination;
import es.uvigo.esei.xcs.domain.entities.Vaccine; 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 @Stateless
@RolesAllowed("VET") @RolesAllowed("VET")
//@PermitAll
public class VaccinationService { public class VaccinationService {
@Inject
private Principal currentUser; @Inject
private Principal currentUser;
@PersistenceContext
EntityManager em; @PersistenceContext
private EntityManager em;
@EJB
private EmailService emailService; @EJB
private EmailService emailService;
public Vaccination get(int vaccinationId) {
return em.find(Vaccination.class, vaccinationId); /**
} * Returns a vaccination by its ID.
*
* @param vaccinationId the identifier of the vaccination.
public List<Vaccination> list(int page, int pageSize){ * @return the Vaccination entity, or {@code null} if not found.
if (page < 0) { */
throw new IllegalArgumentException("The page can't be negative"); public Vaccination get(int vaccinationId) {
} return em.find(Vaccination.class, vaccinationId);
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) * Returns a paginated list of vaccinations (0-based page index).
.setFirstResult(page * pageSize) *
.setMaxResults(pageSize) * @param page the 0-based page index.
.getResultList(); * @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 Vaccination create(Long petId, Long vaccineId, Date date) { public List<Vaccination> list(int page, int pageSize) {
Pet pet = requireNonNull(em.find(Pet.class, petId), "Pet can't be null"); if (page < 0) throw new IllegalArgumentException("The page can't be negative");
Vaccine vaccine = requireNonNull(em.find(Vaccine.class, vaccineId), "Vaccine can't be null"); if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero");
if (!canVaccinate(petId, vaccineId, date)) { return em.createQuery("SELECT DISTINCT v FROM Vaccination v", Vaccination.class)
throw new IllegalArgumentException("This vaccination cannot be created due to vaccine rules"); .setFirstResult(page * pageSize)
} .setMaxResults(pageSize)
.getResultList();
Vaccination vaccination = new Vaccination(pet, vaccine, date); }
em.persist(vaccination);
emailService.send( /**
pet.getOwner().getLogin(), * Creates a new vaccination for a pet with a given vaccine and date.
pet.getName() + " ha sido vacunado con " + vaccine.getName(), * Sends an email notification to the pet's owner.
pet.getName() + " ha sido vacunado con " + vaccine.getName() *
); * @param petId the identifier of the pet.
return vaccination; * @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 updateDate(int vaccinationId, Date date) { */
Vaccination vaccination = em.find(Vaccination.class, vaccinationId); public Vaccination create(Long petId, Long vaccineId, Date date) {
requireNonNull(vaccination, "Vaccination can't be null"); Pet pet = requireNonNull(em.find(Pet.class, petId), "Pet can't be null");
vaccination.setDate(date); Vaccine vaccine = requireNonNull(em.find(Vaccine.class, vaccineId), "Vaccine can't be null");
return em.merge(vaccination);
} if (!canVaccinate(petId, vaccineId, date)) {
throw new IllegalArgumentException("This vaccination cannot be created due to vaccine rules");
}
public void remove(int vaccinationId) {
Vaccination vaccination = this.get(vaccinationId); Vaccination vaccination = new Vaccination(pet, vaccine, date);
requireNonNull(vaccination, "Vaccination can't be null"); em.persist(vaccination);
em.remove(vaccination); emailService.send(
} pet.getOwner().getLogin(),
pet.getName() + " ha sido vacunado con " + vaccine.getName(),
pet.getName() + " ha sido vacunado con " + vaccine.getName()
public Boolean canVaccinate(Long petId, Long vaccineId, Date date) { );
Pet pet = em.find(Pet.class, petId); return vaccination;
Vaccine vaccine = em.find(Vaccine.class, vaccineId); }
if (pet == null || vaccine == null) return false;
/**
List<Vaccination> prevVaccinations = em.createQuery( * Updates the date of an existing vaccination.
"SELECT v FROM Vaccination v WHERE v.pet.id = :petId AND v.vaccine.id = :vaccineId ORDER BY v.date DESC", *
Vaccination.class) * @param vaccinationId the identifier of the vaccination.
.setParameter("petId", petId) * @param date the new date.
.setParameter("vaccineId", vaccineId) * @return the updated Vaccination entity.
.getResultList(); * @throws NullPointerException if the vaccination does not exist.
*/
if (vaccine instanceof MultidoseVaccine) { public Vaccination updateDate(int vaccinationId, Date date) {
MultidoseVaccine multi = (MultidoseVaccine) vaccine; Vaccination vaccination = em.find(Vaccination.class, vaccinationId);
Integer doses = multi.getDoses(); requireNonNull(vaccination, "Vaccination can't be null");
if (doses == null) return false; vaccination.setDate(date);
return prevVaccinations.size() < doses; return em.merge(vaccination);
}
} else if (vaccine instanceof PeriodicVaccine) {
PeriodicVaccine periodic = (PeriodicVaccine) vaccine; /**
if (prevVaccinations.isEmpty()) return true; * Removes a vaccination by its ID.
Vaccination last = prevVaccinations.get(0); *
if (last.getDate() == null || date == null) return false; * @param vaccinationId the identifier of the vaccination.
* @throws NullPointerException if the vaccination does not exist.
long diffDays; */
switch (periodic.getPeriodicType()) { public void remove(int vaccinationId) {
case YEARS: Vaccination vaccination = this.get(vaccinationId);
diffDays = periodic.getPeriode() * 365L; requireNonNull(vaccination, "Vaccination can't be null");
break; em.remove(vaccination);
case MONTHS: }
diffDays = periodic.getPeriode() * 30L;
break; /**
case DAYS: * Checks whether a pet can be vaccinated with a given vaccine on a given date.
diffDays = periodic.getPeriode(); *
break; * @param petId the identifier of the pet.
default: * @param vaccineId the identifier of the vaccine.
return false; * @param date the intended vaccination date.
} * @return {@code true} if vaccination is allowed, {@code false} otherwise.
*/
long diffMillis = date.getTime() - last.getDate().getTime(); public Boolean canVaccinate(Long petId, Long vaccineId, Date date) {
return diffMillis >= diffDays * 24L * 60L * 60L * 1000L; Pet pet = em.find(Pet.class, petId);
Vaccine vaccine = em.find(Vaccine.class, vaccineId);
} else { // MONODOSE if (pet == null || vaccine == null) return false;
return prevVaccinations.isEmpty();
} List<Vaccination> 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();
}
}
} }
package es.uvigo.esei.xcs.service; package es.uvigo.esei.xcs.service;
import java.util.List; import java.util.List;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed; import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless; import javax.ejb.Stateless;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
...@@ -17,114 +14,157 @@ import es.uvigo.esei.xcs.domain.entities.PeriodicVaccine; ...@@ -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.Pet;
import es.uvigo.esei.xcs.domain.entities.Vaccine; 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 @Stateless
@RolesAllowed("VET") @RolesAllowed("VET")
public class VaccineService { public class VaccineService {
@PersistenceContext
private EntityManager em; @PersistenceContext
private EntityManager em;
public Vaccine get(Long id) {
final Vaccine vaccine = em.find(Vaccine.class, id); /**
* Returns a vaccine by its ID.
return vaccine; *
} * @param id the identifier of the vaccine.
* @return the Vaccine entity, or {@code null} if not found.
*/
public List<Vaccine> list(int page, int pageSize){ public Vaccine get(Long id) {
if (page < 0) { return em.find(Vaccine.class, id);
throw new IllegalArgumentException("The page can't be negative"); }
}
if (pageSize <= 0) { /**
throw new IllegalArgumentException("The page size can't be negative or zero"); * Returns a paginated list of vaccines (0-based page index).
} *
return em.createQuery("SELECT v FROM Vaccine v", Vaccine.class) * @param page the 0-based page index.
.setFirstResult(page * pageSize) * @param pageSize the maximum number of vaccines per page.
.setMaxResults(pageSize) * @return a list of Vaccine entities.
.getResultList(); * @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive.
} */
public List<Vaccine> list(int page, int pageSize) {
if (page < 0) throw new IllegalArgumentException("The page can't be negative");
public Vaccine create(String name, String type, Integer doses, String periodicTypeString, Integer periode) { if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero");
switch(type) {
case "MONODOSE": return em.createQuery("SELECT v FROM Vaccine v", Vaccine.class)
MonodoseVaccine monodoseVaccine = new MonodoseVaccine(name); .setFirstResult(page * pageSize)
em.persist(monodoseVaccine); .setMaxResults(pageSize)
return monodoseVaccine; .getResultList();
case "MULTIDOSE": }
MultidoseVaccine multidoseVaccine = new MultidoseVaccine(name, doses);
em.persist(multidoseVaccine); /**
return multidoseVaccine; * Creates a vaccine of a specific type.
case "PERIODIC": *
PeriodicType periodicType = null; * @param name the name of the vaccine.
if (periodicTypeString != null) { * @param type the type of vaccine ("MONODOSE", "MULTIDOSE", "PERIODIC").
periodicType = PeriodicType.valueOf(periodicTypeString); * @param doses the number of doses (for MULTIDOSE).
} * @param periodicTypeString the periodic type string (for PERIODIC).
PeriodicVaccine periodicVaccine = new PeriodicVaccine(name, periodicType, periode); * @param periode the period length (for PERIODIC).
em.persist(periodicVaccine); * @return the created Vaccine entity.
return periodicVaccine; * @throws IllegalArgumentException if the type is unknown.
default: throw new IllegalArgumentException("Tipo de vacuna desconocido"); */
} 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);
public Vaccine update(Vaccine vaccine) { return monodoseVaccine;
if (vaccine == null) case "MULTIDOSE":
throw new IllegalArgumentException("vaccine can't be null"); MultidoseVaccine multidoseVaccine = new MultidoseVaccine(name, doses);
em.persist(multidoseVaccine);
return em.merge(vaccine); return multidoseVaccine;
} case "PERIODIC":
PeriodicType periodicType = null;
public Vaccine updateName(Long id, String newName) { if (periodicTypeString != null) {
if (id == null || newName == null || newName.trim().isEmpty()) periodicType = PeriodicType.valueOf(periodicTypeString);
throw new IllegalArgumentException("Id o nombre inválido"); }
PeriodicVaccine periodicVaccine = new PeriodicVaccine(name, periodicType, periode);
Vaccine vaccine = em.find(Vaccine.class, id); em.persist(periodicVaccine);
if (vaccine == null) return periodicVaccine;
throw new IllegalArgumentException("Vacuna no encontrada"); default: throw new IllegalArgumentException("Unknown vaccine type");
}
vaccine.setName(newName); }
return em.merge(vaccine);
} /**
* Updates an existing vaccine.
*
* @param vaccine the Vaccine entity to update.
public void remove(Long id) { * @return the updated Vaccine entity.
final Vaccine vaccine = this.get(id); * @throws IllegalArgumentException if {@code vaccine} is null.
em.remove(vaccine); */
} public Vaccine update(Vaccine vaccine) {
if (vaccine == null) throw new IllegalArgumentException("vaccine can't be null");
return em.merge(vaccine);
public List<Pet> getVaccinatedPetsByVaccine(int vaccineId, int page, int pageSize){ }
if (page < 0) {
throw new IllegalArgumentException("The page can't be negative"); /**
} * Updates the name of a vaccine.
if (pageSize <= 0) { *
throw new IllegalArgumentException("The page size can't be negative or zero"); * @param id the identifier of the vaccine.
} * @param newName the new name.
return em.createQuery("SELECT v.pet FROM Vaccination v " * @return the updated Vaccine entity.
+ "WHERE v.vaccine.id = :vaccineId", Pet.class) * @throws IllegalArgumentException if the id or name is invalid or the vaccine is not found.
.setFirstResult(page * pageSize) */
.setMaxResults(pageSize) public Vaccine updateName(Long id, String newName) {
.setParameter("vaccineId", vaccineId) if (id == null || newName == null || newName.trim().isEmpty())
.getResultList(); throw new IllegalArgumentException("Id or name invalid");
}
Vaccine vaccine = em.find(Vaccine.class, id);
if (vaccine == null) throw new IllegalArgumentException("Vaccine not found");
public List<Pet> getVaccinatedPetsByVaccineName(String vaccineName, int page, int pageSize){
if (page < 0) { vaccine.setName(newName);
throw new IllegalArgumentException("The page can't be negative"); return em.merge(vaccine);
} }
if (pageSize <= 0) {
throw new IllegalArgumentException("The page size can't be negative or zero"); /**
} * Removes a vaccine by its ID.
return em.createQuery("SELECT v.pet FROM Vaccination v\r\n" *
+ "WHERE v.vaccine.name = :vaccineName", Pet.class) * @param id the identifier of the vaccine.
.setFirstResult(page * pageSize) */
.setMaxResults(pageSize) public void remove(Long id) {
.setParameter("vaccineName", vaccineName) final Vaccine vaccine = this.get(id);
.getResultList(); 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<Pet> 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<Pet> 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();
}
} }
...@@ -5,7 +5,6 @@ import static java.util.Objects.requireNonNull; ...@@ -5,7 +5,6 @@ import static java.util.Objects.requireNonNull;
import java.security.Principal; import java.security.Principal;
import java.util.List; import java.util.List;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed; import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless; import javax.ejb.Stateless;
import javax.inject.Inject; import javax.inject.Inject;
...@@ -17,113 +16,155 @@ import es.uvigo.esei.xcs.domain.entities.Pet; ...@@ -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.Vaccination;
import es.uvigo.esei.xcs.domain.entities.Vet; 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 @Stateless
@RolesAllowed("VET") @RolesAllowed("VET")
public class VetService { public class VetService {
@Inject
private Principal currentUser; @Inject
private Principal currentUser;
@PersistenceContext
EntityManager em; @PersistenceContext
private 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) * Counts the number of pets assigned to the current vet.
.setParameter("login", currentUser.getName()) *
.getSingleResult(); * @return the number of pets assigned to the current vet.
return count.intValue(); */
} public int countPets() {
Long count = em.createQuery(
"SELECT COUNT(p) FROM Vet v JOIN v.pets p WHERE v.login = :login", Long.class)
public Vet get(String login) { .setParameter("login", currentUser.getName())
return em.find(Vet.class, login); .getSingleResult();
} return count.intValue();
}
public List<Vet> list(){ /**
return em.createQuery("SELECT DISTINCT v FROM Vet v", Vet.class) * Returns a vet by login.
.getResultList(); *
} * @param login the login of the vet.
* @return the Vet entity, or {@code null} if not found.
*/
public List<Vet> findByPetName(String petName, int page, int pageSize){ public Vet get(String login) {
requireNonNull(petName, "Pet's name can't be null"); return em.find(Vet.class, login);
if (page < 0) { }
throw new IllegalArgumentException("The page can't be negative");
} /**
if (pageSize <= 0) { * Returns a list of all vets.
throw new IllegalArgumentException("The page size can't be negative or zero"); *
} * @return a list of Vet entities.
return this.em.createQuery("SELECT DISTINCT v FROM Vet v JOIN v.pets p " */
+ "WHERE p.name = :petName", Vet.class) public List<Vet> list() {
.setFirstResult(page * pageSize) return em.createQuery("SELECT DISTINCT v FROM Vet v", Vet.class)
.setMaxResults(pageSize) .getResultList();
.setParameter("petName", petName) }
.getResultList();
} /**
* Returns a paginated list of vets that have a pet with the given name.
*
public Vet create(Vet vet) { * @param petName the name of the pet.
requireNonNull(Vet.class, "Vet can't be null"); * @param page the 0-based page index.
em.persist(vet); * @param pageSize the maximum number of vets per page.
return vet; * @return a list of Vet entities.
} */
public List<Vet> findByPetName(String petName, int page, int pageSize) {
requireNonNull(petName, "Pet's name can't be null");
public Vet update(Vet vet) { if (page < 0) throw new IllegalArgumentException("The page can't be negative");
requireNonNull(Vet.class, "Vet can't be null"); if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero");
return em.merge(vet);
} return em.createQuery("SELECT DISTINCT v FROM Vet v JOIN v.pets p WHERE p.name = :petName", Vet.class)
.setFirstResult(page * pageSize)
.setMaxResults(pageSize)
public void remove(String login) { .setParameter("petName", petName)
em.remove(this.get(login)); .getResultList();
} }
/**
public List<Pet> getPets(int first , int pageSize) { * Creates a new vet.
if (first < 0) throw new IllegalArgumentException("First can't be negative"); *
if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); * @param vet the Vet entity to create.
* @return the persisted Vet entity.
return this.em.createQuery("SELECT DISTINCT p FROM Vet v JOIN v.pets p " */
+ "WHERE v.login = :login", Pet.class) public Vet create(Vet vet) {
.setFirstResult(first) requireNonNull(vet, "Vet can't be null");
.setMaxResults(pageSize) em.persist(vet);
.setParameter("login", currentUser.getName()) return vet;
.getResultList(); }
}
/**
public List<Vaccination> getVaccinationsFromOwnPet( * Updates an existing vet.
IdentifierType identifierType, *
String identifierValue, * @param vet the Vet entity to update.
int page, * @return the updated Vet entity.
int pageSize */
){ public Vet update(Vet vet) {
requireNonNull(identifierType, "pet's identifier type can't be null"); requireNonNull(vet, "Vet can't be null");
requireNonNull(identifierValue, "pet's identifier value can't be null"); return em.merge(vet);
if (page < 0) { }
throw new IllegalArgumentException("The page can't be negative");
} /**
if (pageSize <= 0) { * Removes a vet by login.
throw new IllegalArgumentException("The page size can't be negative or zero"); *
} * @param login the login of the vet to remove.
return em.createQuery( */
"SELECT v FROM Vet vet " public void remove(String login) {
+ "JOIN vet.pets p " em.remove(this.get(login));
+ "JOIN p.identifiers i " }
+ "JOIN p.vaccinations v "
+ "WHERE " /**
+ "vet.login = :login AND " * Returns a paginated list of pets assigned to the current vet.
+ "i.type = :identifierType AND " *
+ "i.value = :identifierValue", * @param first the index of the first pet (0-based).
Vaccination.class) * @param pageSize the maximum number of pets per page.
.setParameter("login", currentUser.getName()) * @return a list of Pet entities.
.setParameter("identifierType", identifierType) */
.setParameter("identifierValue", identifierValue) public List<Pet> getPets(int first, int pageSize) {
.setFirstResult(page * pageSize) if (first < 0) throw new IllegalArgumentException("First can't be negative");
.setMaxResults(pageSize) if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive");
.getResultList();
} 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<Vaccination> 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();
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment