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,14 +14,18 @@ import es.uvigo.esei.xcs.service.OwnerService; ...@@ -27,14 +14,18 @@ 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.
*
* Accessible under the path "/owner".
* *
* @author Miguel Reboiro Jato * @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;
...@@ -42,13 +33,11 @@ public class OwnerResource { ...@@ -42,13 +33,11 @@ public class OwnerResource {
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}")
...@@ -57,18 +46,18 @@ public class OwnerResource { ...@@ -57,18 +46,18 @@ public class OwnerResource {
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) {
...@@ -76,27 +65,22 @@ public class OwnerResource { ...@@ -76,27 +65,22 @@ public class OwnerResource {
} }
/** /**
* 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");
...@@ -104,18 +88,19 @@ public class OwnerResource { ...@@ -104,18 +88,19 @@ public class OwnerResource {
} }
/** /**
* 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); final Owner owner = this.service.get(login);
ownerData.assignData(owner); ownerData.assignData(owner);
this.service.update(owner); this.service.update(owner);
...@@ -123,15 +108,14 @@ public class OwnerResource { ...@@ -123,15 +108,14 @@ public class OwnerResource {
} }
/** /**
* 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");
...@@ -139,23 +123,28 @@ public class OwnerResource { ...@@ -139,23 +123,28 @@ public class OwnerResource {
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;
...@@ -40,22 +33,20 @@ public class PetResource { ...@@ -40,22 +33,20 @@ public class PetResource {
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);
...@@ -63,38 +54,39 @@ public class PetResource { ...@@ -63,38 +54,39 @@ public class PetResource {
} }
/** /**
* 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 {
...@@ -103,11 +95,9 @@ public class PetResource { ...@@ -103,11 +95,9 @@ public class PetResource {
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");
...@@ -117,15 +107,13 @@ public class PetResource { ...@@ -117,15 +107,13 @@ public class PetResource {
} }
/** /**
* 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
...@@ -136,9 +124,7 @@ public class PetResource { ...@@ -136,9 +124,7 @@ public class PetResource {
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);
...@@ -146,20 +132,18 @@ public class PetResource { ...@@ -146,20 +132,18 @@ public class PetResource {
} }
/** /**
* 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");
...@@ -43,6 +60,14 @@ public class VaccineResource { ...@@ -43,6 +60,14 @@ public class VaccineResource {
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;
...@@ -54,73 +40,113 @@ public class VetResource { ...@@ -54,73 +40,113 @@ public class VetResource {
@Context @Context
private UriInfo uriInfo; private UriInfo uriInfo;
/**
* Returns a vet by login.
*
* @param login vet login.
* @return HTTP 200 with the vet.
*/
@GET @GET
@Path("{login}") @Path("{login}")
public Response get(@PathParam("login") String login) { public Response get(@PathParam("login") String login) {
return Response.ok(vetService.get(login)).build(); return Response.ok(vetService.get(login)).build();
} }
/**
* Returns the list of all vets.
*
* @return HTTP 200 with the list of vets.
*/
@GET @GET
public Response list() { public Response list() {
return Response.ok(vetService.list()).build(); return Response.ok(vetService.list()).build();
} }
/**
* Creates a new vet.
*
* @param vetData data of the vet to create.
* @return HTTP 201 with the URI of the created vet.
* @throws SecurityException if creation fails.
*/
@POST @POST
public Response create(VetData vetData) { public Response create(VetData vetData) {
requireNonNull(vetData); requireNonNull(vetData, "vetData can't be null");
try { try {
final Vet vet = this.vetService.create(vetData.toVet()); final Vet vet = this.vetService.create(vetData.toVet());
final URI vetUri = uriInfo.getAbsolutePathBuilder() final URI vetUri = uriInfo.getAbsolutePathBuilder()
.path(vet.getLogin()).build(); .path(vet.getLogin()).build();
return Response.created(vetUri).build(); return Response.created(vetUri).build();
} catch (Exception e) { } catch (Exception e) {
throw new SecurityException(e); throw new SecurityException(e);
} }
} }
/**
* Deletes a vet by login.
*
* @param login vet login.
* @return HTTP 200 when deleted successfully.
* @throws SecurityException if deletion fails due to access control.
*/
@Path("{login}") @Path("{login}")
@DELETE @DELETE
public Response delete(@PathParam("login") String login) { public Response delete(@PathParam("login") String login) {
try { try {
this.vetService.remove(login); this.vetService.remove(login);
return Response.ok().build(); return Response.ok().build();
} catch (EJBAccessException e) { } catch (EJBAccessException e) {
throw new SecurityException(e); throw new SecurityException(e);
} }
} }
/**
* Returns a paginated list of pets for the current vet.
*
* @param page 0-based page index.
* @param pageSize number of pets per page.
* @return HTTP 200 with the list of pets.
*/
@GET @GET
@Path("pets") @Path("pets")
public Response listPets( public Response listPets(@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.vetService.getPets(page, pageSize)).build(); return Response.ok(this.vetService.getPets(page, pageSize)).build();
} }
/**
* Returns a specific pet by ID.
*
* @param petId pet ID.
* @return HTTP 200 with the pet.
*/
@GET @GET
@Path("pets/{petId}") @Path("pets/{petId}")
public Response getPet(@PathParam("petId") Long petId) { public Response getPet(@PathParam("petId") Long petId) {
return Response.ok(this.petService.get(petId)).build(); return Response.ok(this.petService.get(petId)).build();
} }
/**
* Returns a paginated list of vaccines.
*
* @param page 0-based page index.
* @param pageSize number of vaccines per page.
* @return HTTP 200 with the list of vaccines.
*/
@GET @GET
@Path("vaccine") @Path("vaccine")
public Response listVaccines(@QueryParam("page") int page, @QueryParam("pageSize") int pageSize) { public Response listVaccines(@QueryParam("page") int page,
@QueryParam("pageSize") int pageSize) {
return Response.ok(this.vaccineService.list(page, pageSize)).build(); return Response.ok(this.vaccineService.list(page, pageSize)).build();
} }
/**
* Creates a new vaccine.
*
* @param vaccineData data to create the vaccine.
* @return HTTP 200 with the created vaccine.
*/
@POST @POST
@Path("vaccine") @Path("vaccine")
public Response createVaccine(VaccineCreationData vaccineData) { public Response createVaccine(VaccineCreationData vaccineData) {
...@@ -132,21 +158,33 @@ public class VetResource { ...@@ -132,21 +158,33 @@ public class VetResource {
vaccineData.getPeriode() vaccineData.getPeriode()
); );
return Response.ok(vaccine).build(); return Response.ok(vaccine).build();
} }
/**
* Updates a vaccine.
*
* @param id vaccine ID.
* @param vaccineData data to update the vaccine.
* @return HTTP 200 when updated successfully.
* @throws IllegalArgumentException if vaccineData is null.
*/
@Path("vaccine/{id}") @Path("vaccine/{id}")
@PUT @PUT
public Response updateVaccine(@PathParam("id") Long id, VaccineEditionData vaccineData) { public Response updateVaccine(@PathParam("id") Long id, VaccineEditionData vaccineData) {
if (vaccineData == null) { requireNonNull(vaccineData, "vaccineData can't be null");
throw new IllegalArgumentException("vaccineData can't be null");
}
final Vaccine vaccine = this.vaccineService.get(id); final Vaccine vaccine = this.vaccineService.get(id);
vaccineData.assignData(vaccine); vaccineData.assignData(vaccine);
this.vaccineService.update(vaccine); this.vaccineService.update(vaccine);
return Response.ok().build(); return Response.ok().build();
} }
/**
* Deletes a vaccine by ID.
*
* @param id vaccine ID.
* @return HTTP 200 when deleted successfully.
* @throws SecurityException if deletion fails due to access control.
*/
@Path("vaccine/{id}") @Path("vaccine/{id}")
@DELETE @DELETE
public Response deleteVaccine(@PathParam("id") Long id) { public Response deleteVaccine(@PathParam("id") Long id) {
...@@ -158,17 +196,22 @@ public class VetResource { ...@@ -158,17 +196,22 @@ public class VetResource {
} }
} }
/**
* Returns paginated list of vaccinations of a pet owned by the current vet.
*
* @param petIdentifierType type of the pet's identifier.
* @param petIdentifierValue value of the pet's identifier.
* @param page 0-based page index.
* @param pageSize number of vaccinations per page.
* @return HTTP 200 with the list of vaccinations.
*/
@Path("pet/{petIdentifierType}/{petIdentifierValue}/vaccination") @Path("pet/{petIdentifierType}/{petIdentifierValue}/vaccination")
@GET @GET
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.vetService.getVaccinationsFromOwnPet( return Response.ok(this.vetService.getVaccinationsFromOwnPet(
//login,
petIdentifierType, petIdentifierType,
petIdentifierValue, petIdentifierValue,
page, page,
...@@ -176,12 +219,17 @@ public class VetResource { ...@@ -176,12 +219,17 @@ public class VetResource {
)).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") @Path("vaccination")
@POST @POST
public Response registerVaccination( public Response registerVaccination(@QueryParam("date") Date date,
@QueryParam("date") Date date, VaccinationCreationData vaccinationData) {
VaccinationCreationData vaccinationData
) {
if (date == null) { if (date == null) {
date = new Date(); date = new Date();
} }
...@@ -190,25 +238,26 @@ public class VetResource { ...@@ -190,25 +238,26 @@ public class VetResource {
vaccinationData.getVaccineId(), vaccinationData.getVaccineId(),
date date
); );
final URI vaccinationUri = uriInfo.getAbsolutePathBuilder() final URI vaccinationUri = uriInfo.getAbsolutePathBuilder()
.path(String.valueOf(vaccination.getId())).build(); .path(String.valueOf(vaccination.getId())).build();
return Response.created(vaccinationUri).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 @POST
@Path("/assign/pets/{petId}") @Path("/assign/pets/{petId}")
public Response assignVetToPet( public Response assignVetToPet(@PathParam("petId") Long petId) {
@PathParam("petId") Long petId
) {
requireNonNull(petId, "petId can't be null"); requireNonNull(petId, "petId can't be null");
try { try {
petService.assignVetToPet(petId); petService.assignVetToPet(petId);
return Response.ok() return Response.ok().build();
.build();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return Response.status(Response.Status.NOT_FOUND) return Response.status(Response.Status.NOT_FOUND)
.entity(e.getMessage()) .entity(e.getMessage())
...@@ -216,24 +265,25 @@ public class VetResource { ...@@ -216,24 +265,25 @@ public class VetResource {
} }
} }
/**
* 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 @DELETE
@Path("{login}/unassign/pets/{petId}") @Path("{login}/unassign/pets/{petId}")
public Response unassignVetFromPet( public Response unassignVetFromPet(@PathParam("petId") Long petId) {
@PathParam("petId") Long petId
) {
requireNonNull(petId, "petId can't be null"); requireNonNull(petId, "petId can't be null");
try { try {
petService.unassignVetFromPet(petId); petService.unassignVetFromPet(petId);
return Response.ok() return Response.ok().build();
.build();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return Response.status(Response.Status.NOT_FOUND) return Response.status(Response.Status.NOT_FOUND)
.entity(e.getMessage()) .entity(e.getMessage())
.build(); .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;
/**
* Returns an administrator by its ID.
*/
public Administrator get(int id) { public Administrator get(int id) {
return em.find(Administrator.class, id); return em.find(Administrator.class, id);
} }
/**
* Returns a paginated list of all users.
*/
public List<User> list(int page, int pageSize) {
if (page < 0) throw new IllegalArgumentException("The page can't be negative");
if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero");
public List<User> list(int page, int pageSize){
if (page < 0) {
throw new IllegalArgumentException("The page can't be negative");
}
if (pageSize <= 0) {
throw new IllegalArgumentException("The page size can't be negative or zero");
}
return em.createQuery("SELECT DISTINCT u FROM User u", User.class) return em.createQuery("SELECT DISTINCT u FROM User u", User.class)
.setFirstResult(page * pageSize) .setFirstResult(page * pageSize)
.setMaxResults(pageSize) .setMaxResults(pageSize)
.getResultList(); .getResultList();
} }
/**
* Persists a new administrator entity.
*/
public Administrator create(Administrator administrator) { public Administrator create(Administrator administrator) {
requireNonNull(Administrator.class, "Administrator can't be null"); requireNonNull(administrator, "Administrator can't be null");
em.persist(administrator); em.persist(administrator);
return administrator; return administrator;
} }
/**
* Updates an existing administrator.
*/
public Administrator update(Administrator administrator) { public Administrator update(Administrator administrator) {
requireNonNull(Administrator.class, "Administrator can't be null"); requireNonNull(administrator, "Administrator can't be null");
return em.merge(administrator); return em.merge(administrator);
} }
/**
* Removes an administrator by ID.
*/
public void remove(int id) { public void remove(int id) {
em.remove(this.get(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 this.vaccineCounter = em.createQuery("SELECT COUNT(v) FROM Vaccine v", Long.class)
.createQuery("SELECT COUNT(v) FROM Vaccine v", Long.class)
.getSingleResult(); .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;
/**
* Persists a new identifier.
*
* @param identifier the Identifier entity to persist.
* @return the persisted Identifier entity.
* @throws NullPointerException if {@code identifier} is null.
*/
public Identifier create(Identifier identifier) { public Identifier create(Identifier identifier) {
requireNonNull(identifier, "Identifier can't be null"); requireNonNull(identifier, "Identifier can't be null");
em.persist(identifier); em.persist(identifier);
return identifier; return identifier;
} }
/**
* Removes an identifier by its value.
*
* @param value the identifier value.
*/
public void remove(String value) { public void remove(String value) {
Identifier identifier = em.find(Identifier.class, value); Identifier identifier = em.find(Identifier.class, value);
if (identifier != null) {
em.remove(identifier); 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,52 +12,55 @@ import javax.persistence.EntityExistsException; ...@@ -13,52 +12,55 @@ 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 @PersistenceContext
private EntityManager em; private EntityManager em;
@Inject @Inject
private Principal currentUser; private Principal currentUser;
/**
* Counts all owners in the system.
*
* @return the total number of owners.
*/
public int countAll() { public int countAll() {
Long count = em.createQuery("SELECT COUNT(o) FROM Owner o", Long.class) Long count = em.createQuery("SELECT COUNT(o) FROM Owner o", Long.class)
.getSingleResult(); .getSingleResult();
return count.intValue(); return count.intValue();
} }
/** /**
* Returns the owner identified by {@code login}. If there is no owner with * Returns the owner identified by {@code login}.
* the specified login, {@code null} will be returned.
* *
* @param login the login of an owner. * @param login the login of an owner.
* @return the owner with the provided login or {@code null} if there is no * @return the owner with the provided login or {@code null} if not found.
* owner with the specified login. * @throws IllegalArgumentException if {@code login} is {@code null}.
* @throws IllegalArgumentException if {@code login} is {@code null} or it
* does not identifies a valid owner.
*/ */
public Owner get(String login) { public Owner get(String login) {
return em.find(Owner.class, 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.
* @param pageSize the maximum number of owners to return.
* @return the list of owners in the specified page.
* @throws IllegalArgumentException if {@code first} is negative or {@code pageSize} is not positive.
*/ */
public List<Owner> list(int first, int pageSize) { public List<Owner> list(int first, int pageSize) {
if (first < 0) throw new IllegalArgumentException("First can't be negative"); if (first < 0) throw new IllegalArgumentException("First can't be negative");
...@@ -73,46 +75,40 @@ public class OwnerService { ...@@ -73,46 +75,40 @@ public class OwnerService {
/** /**
* Returns the list of owners that have a pet with the specified name. * Returns the list of owners that have a pet with the specified name.
* *
* @param petName a pet's name. * @param petName the name of the pet.
* @return the list of owners that have a pet with the specified name. The * @return the list of owners with a pet matching the name.
* list may be empty if any owner has a pet with the specified name.
* @throws IllegalArgumentException if {@code petName} is {@code null}. * @throws IllegalArgumentException if {@code petName} is {@code null}.
*/ */
public List<Owner> findByPetName(String petName) { public List<Owner> findByPetName(String petName) {
if (petName == null) if (petName == null)
throw new IllegalArgumentException("petName can't be null"); throw new IllegalArgumentException("petName can't be null");
final String query = "SELECT o FROM Owner o JOIN o.pets p " + final String query = "SELECT o FROM Owner o JOIN o.pets p WHERE p.name = :petName";
"WHERE p.name = :petName";
return em.createQuery(query, Owner.class) return em.createQuery(query, Owner.class)
.setParameter("petName", petName) .setParameter("petName", petName)
.getResultList(); .getResultList();
} }
/** /**
* Creates a new owner. If the owner already has pets, they will be created * Creates a new owner along with any pets associated.
* too.
* *
* @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 a new owner. If the owner is not stored, it will be persisted. * Updates an existing owner. If the owner does not exist, it will be persisted.
* *
* @param owner an owner to be updated. * @param owner the owner to update.
* @return the updated owner. * @return the updated owner.
* @throws IllegalArgumentException if {@code owner} is {@code null}. * @throws IllegalArgumentException if {@code owner} is {@code null}.
*/ */
...@@ -124,11 +120,10 @@ public class OwnerService { ...@@ -124,11 +120,10 @@ public class OwnerService {
} }
/** /**
* Deletes an owner. * Deletes an owner by login.
* *
* @param login the login of the owner to be deleted. * @param login the login of the owner to delete.
* @throws IllegalArgumentException if {@code login} is {@code null} or if * @throws IllegalArgumentException if {@code login} is {@code null}.
* it does not identifies a valid owner.
*/ */
public void remove(String login) { public void remove(String login) {
Owner owner = this.get(login); Owner owner = this.get(login);
...@@ -136,53 +131,54 @@ public class OwnerService { ...@@ -136,53 +131,54 @@ public class OwnerService {
} }
/** /**
* Returns the list of pets of an owner. * Returns a paginated list of pets of the specified owner.
* *
* @param login the login of the owner that owns the pets. * @param login the login of the owner.
* @return the list of pets of an owner. * @param first the starting index (0-based).
* @throws IllegalArgumentException if {@code login} is {@code null} or it * @param pageSize the maximum number of pets to return.
* does not identifies a valid owner. * @return the list of pets for the owner.
* @throws IllegalArgumentException if {@code login} is {@code null}, {@code first} is negative, or {@code pageSize} is not positive.
*/ */
public List<Pet> getPets(String login, int first, int pageSize) { public List<Pet> getPets(String login, int first, int pageSize) {
if (first < 0) throw new IllegalArgumentException("First can't be negative"); if (first < 0) throw new IllegalArgumentException("First can't be negative");
if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive");
return em.createQuery("SELECT p FROM Owner o " return em.createQuery("SELECT p FROM Owner o JOIN o.pets p WHERE o.login = :login", Pet.class)
+ "JOIN o.pets p "
+ "WHERE "
+ "o.login = :login",
Pet.class)
.setFirstResult(first) .setFirstResult(first)
.setMaxResults(pageSize) .setMaxResults(pageSize)
.setParameter("login", login) .setParameter("login", login)
.getResultList(); .getResultList();
} }
/**
* Returns a paginated list of vaccinations for a pet of the current user, identified by an identifier type and value.
*
* @param identifierType the type of the pet's identifier.
* @param identifierValue the value of the pet's identifier.
* @param page the 0-based page index.
* @param pageSize the maximum number of vaccinations per page.
* @return the list of vaccinations.
* @throws NullPointerException if {@code identifierType} or {@code identifierValue} is {@code null}.
* @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive.
*/
public List<Vaccination> getVaccinationsFromOwnPet( public List<Vaccination> getVaccinationsFromOwnPet(
IdentifierType identifierType, IdentifierType identifierType,
String identifierValue, String identifierValue,
int page, int page,
int pageSize int pageSize
){ ) {
requireNonNull(identifierType, "pet's identifier type can't be null"); requireNonNull(identifierType, "pet's identifier type can't be null");
requireNonNull(identifierValue, "pet's identifier value can't be null"); requireNonNull(identifierValue, "pet's identifier value can't be null");
if (page < 0) { if (page < 0) throw new IllegalArgumentException("The page can't be negative");
throw new IllegalArgumentException("The page can't be negative"); if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero");
}
if (pageSize <= 0) {
throw new IllegalArgumentException("The page size can't be negative or zero");
}
return em.createQuery( return em.createQuery(
"SELECT v FROM Owner o " "SELECT v FROM Owner o " +
+ "JOIN o.pets p " "JOIN o.pets p " +
+ "JOIN p.identifiers i " "JOIN p.identifiers i " +
+ "JOIN p.vaccinations v " "JOIN p.vaccinations v " +
+ "WHERE " "WHERE o.login = :login AND i.type = :identifierType AND i.value = :identifierValue",
+ "o.login = :login AND "
+ "i.type = :identifierType AND "
+ "i.value = :identifierValue",
Vaccination.class) Vaccination.class)
.setParameter("login", currentUser.getName()) .setParameter("login", currentUser.getName())
.setParameter("identifierType", identifierType) .setParameter("identifierType", identifierType)
...@@ -191,5 +187,4 @@ public class OwnerService { ...@@ -191,5 +187,4 @@ public class OwnerService {
.setMaxResults(pageSize) .setMaxResults(pageSize)
.getResultList(); .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,19 +17,19 @@ import javax.persistence.PersistenceContext; ...@@ -19,19 +17,19 @@ 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 @Inject
private Principal currentUser; private Principal currentUser;
...@@ -42,73 +40,56 @@ public class PetService { ...@@ -42,73 +40,56 @@ public class PetService {
private EntityManager em; private EntityManager em;
/** /**
* Returns a pet identified by the provided id. If an owner tries to access * Counts all pets in the system.
* a pet that does now own, an {@link EJBAccessException} will be thrown.
* *
* @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.
* @throws EJBAccessException if the current owner does not owns the pet.
*/ */
/*public Pet get(Long id) {
final Pet pet = em.find(Pet.class, id);
if (pet == null) {
return null;
} else if (pet.getOwner().getLogin().equals(this.currentOwner.getName())) {
return pet;
} else {
throw new EJBAccessException("Pet's owner is not the current principal");
}
}*/
public int countAll() { public int countAll() {
Long count = em.createQuery("SELECT COUNT(p) FROM Pet p", Long.class) Long count = em.createQuery("SELECT COUNT(p) FROM Pet p", Long.class)
.getSingleResult(); .getSingleResult();
return count.intValue(); return count.intValue();
} }
/**
* Returns a pet identified by the provided id.
*
* @param id the identifier of the pet.
* @return the pet or {@code null} if not found.
*/
public Pet get(Long id) { public Pet get(Long id) {
return em.find(Pet.class, id); return em.find(Pet.class, id);
} }
/*public List<Pet> getAll(int page, int pageSize) { /**
if (page < 0) { * Returns a paginated list of all pets (0-based first index).
throw new IllegalArgumentException("The page can't be negative"); *
} * @param first the starting index of the first pet.
if (pageSize <= 0) { * @param pageSize the maximum number of pets to return.
throw new IllegalArgumentException("The page size can't be negative or zero"); * @return a list of pets.
} * @throws IllegalArgumentException if {@code first} is negative or {@code pageSize} is not positive.
return em.createQuery("SELECT p FROM Pet p", Pet.class) */
.setFirstResult(page * pageSize)
.setMaxResults(pageSize)
.getResultList();
}*/
public List<Pet> getAll(int first, int pageSize) { public List<Pet> getAll(int first, int pageSize) {
if (first < 0) throw new IllegalArgumentException("First can't be negative"); if (first < 0) throw new IllegalArgumentException("First can't be negative");
if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive");
return em.createQuery("SELECT p FROM Pet p", Pet.class) return em.createQuery("SELECT p FROM Pet p", Pet.class)
.setFirstResult(first) // no multiplicar por pageSize .setFirstResult(first)
.setMaxResults(pageSize) .setMaxResults(pageSize)
.getResultList(); .getResultList();
} }
/** /**
* Returns the complete list of pets of the current owner. * Returns a paginated list of pets belonging to the current owner (0-based page index).
* *
* @return the complete list of pets of the current owner. * @param page the 0-based page index.
* @param pageSize the maximum number of pets per page.
* @return the list of pets of the current owner.
* @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive.
*/ */
public List<Pet> list(int page, int pageSize) { public List<Pet> list(int page, int pageSize) {
if (page < 0) { if (page < 0) throw new IllegalArgumentException("The page can't be negative");
throw new IllegalArgumentException("The page can't be negative"); if (pageSize <= 0) throw new IllegalArgumentException("The page size must be negative or zero");
}
if (pageSize <= 0) {
throw new IllegalArgumentException("The page size can't be negative or zero");
}
return em.createQuery("SELECT p FROM Pet p WHERE p.owner.login = :login", Pet.class) return em.createQuery("SELECT p FROM Pet p WHERE p.owner.login = :login", Pet.class)
.setFirstResult(page * pageSize) .setFirstResult(page * pageSize)
.setMaxResults(pageSize) .setMaxResults(pageSize)
...@@ -117,15 +98,12 @@ public class PetService { ...@@ -117,15 +98,12 @@ public class PetService {
} }
/** /**
* Creates a new pet owned by the current user. * Creates a new pet for the current owner.
* *
* @param pet a new pet to be stored. * @param pet the pet to create.
* @return the persistent version of the pet created. * @return the persistent version of the pet.
* @throws EJBAccessException if the pet already has an owner and it is not * @throws IllegalArgumentException if {@code pet} is null.
* the current user. If the pet has no owner, this exception will be never * @throws EJBAccessException if the pet already has an owner different from the current user.
* thrown.
* @throws IllegalArgumentException if a pet with the same identifier
* already exists.
*/ */
public Pet create(Pet pet) { public Pet create(Pet pet) {
requireNonNull(pet, "Pet can't be null"); requireNonNull(pet, "Pet can't be null");
...@@ -136,26 +114,25 @@ public class PetService { ...@@ -136,26 +114,25 @@ public class PetService {
throw new EJBAccessException("Pet's owner is not the current principal"); throw new EJBAccessException("Pet's owner is not the current principal");
} else { } else {
pet.setOwner(owner); pet.setOwner(owner);
em.persist(pet);
this.em.persist(pet);
return pet; return pet;
} }
} }
/**
* Convenience method to create a new pet with basic attributes.
*/
public Pet createPet(String name, AnimalType animal, Date birth) { public Pet createPet(String name, AnimalType animal, Date birth) {
Owner owner = em.find(Owner.class, currentUser.getName()); Owner owner = em.find(Owner.class, currentUser.getName());
Pet pet = new Pet(name, animal, birth, owner); Pet pet = new Pet(name, animal, birth, owner);
this.em.persist(pet); em.persist(pet);
return pet; return pet;
} }
/** /**
* Updates the information of a pet. If the pet is not stored, it will be * Updates an existing pet. If the pet does not exist, it will be persisted.
* created.
* *
* @param pet a pet to be updated. * @param pet the pet to update.
* @return the updated pet. * @return the updated pet.
* @throws IllegalArgumentException if the pet has no owner. * @throws IllegalArgumentException if the pet has no owner.
* @throws EJBAccessException if the pet's owner is not the current user. * @throws EJBAccessException if the pet's owner is not the current user.
...@@ -164,7 +141,7 @@ public class PetService { ...@@ -164,7 +141,7 @@ public class PetService {
if (pet.getOwner() == null) if (pet.getOwner() == null)
throw new IllegalArgumentException("Pet must have an owner"); throw new IllegalArgumentException("Pet must have an owner");
if (pet.getOwner().getLogin().equals(this.currentUser.getName())) { if (pet.getOwner().getLogin().equals(currentUser.getName())) {
return em.merge(pet); return em.merge(pet);
} else { } else {
throw new EJBAccessException("Pet's owner is not the current principal"); throw new EJBAccessException("Pet's owner is not the current principal");
...@@ -174,44 +151,52 @@ public class PetService { ...@@ -174,44 +151,52 @@ public class PetService {
/** /**
* Deletes a pet. * Deletes a pet.
* *
* @param id the identifier of the pet to be deleted. * @param id the identifier of the pet.
* @throws IllegalArgumentException if there is no pet with the provided * @throws IllegalArgumentException if no pet exists with the provided id.
* identifier.
* @throws EJBAccessException if the pet's owner is not the current user. * @throws EJBAccessException if the pet's owner is not the current user.
*/ */
public void remove(Long id) { public void remove(Long id) {
final Pet pet = this.get(id); final Pet pet = this.get(id);
pet.setOwner(null); pet.setOwner(null);
em.remove(pet); em.remove(pet);
} }
public List<Vaccine> getVaccinesByPetId(Long id, int page, int pageSize){ /**
if (page < 0) { * Returns a paginated list of vaccines for a given pet.
throw new IllegalArgumentException("The page can't be negative"); *
} * @param id the identifier of the pet.
if (pageSize <= 0) { * @param page the 0-based page index.
throw new IllegalArgumentException("The page size can't be negative or zero"); * @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) return em.createQuery("SELECT v.pet FROM Vaccination v WHERE v.pet.id = :id", Vaccine.class)
.setFirstResult(page * pageSize) .setFirstResult(page * pageSize)
.setMaxResults(pageSize) .setMaxResults(pageSize)
.setParameter("id", id)
.getResultList(); .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") @RolesAllowed("VET")
public void assignVetToPet(Long petId) { public void assignVetToPet(Long petId) {
requireNonNull(petId, "Pet ID can't be null"); requireNonNull(petId, "Pet ID can't be null");
//requireNonNull(vetLogin, "Vet login can't be null");
Pet pet = em.find(Pet.class, petId); Pet pet = em.find(Pet.class, petId);
if (pet == null) if (pet == null) throw new IllegalArgumentException("Pet not found");
throw new IllegalArgumentException("Pet not found");
Vet vet = em.find(Vet.class, currentUser.getName()); Vet vet = em.find(Vet.class, currentUser.getName());
if (vet == null) if (vet == null) throw new IllegalArgumentException("Vet not found");
throw new IllegalArgumentException("Vet not found");
pet.addVet(vet); pet.addVet(vet);
pet.internalAddVet(vet); pet.internalAddVet(vet);
...@@ -219,33 +204,50 @@ public class PetService { ...@@ -219,33 +204,50 @@ public class PetService {
} }
/**
* Unassigns the current vet from 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") @RolesAllowed("VET")
public void unassignVetFromPet(Long petId) { public void unassignVetFromPet(Long petId) {
requireNonNull(petId, "Pet ID can't be null"); requireNonNull(petId, "Pet ID can't be null");
//requireNonNull(vetLogin, "Vet login can't be null");
Pet pet = em.find(Pet.class, petId); Pet pet = em.find(Pet.class, petId);
if (pet == null) if (pet == null) throw new IllegalArgumentException("Pet not found");
throw new IllegalArgumentException("Pet not found");
Vet vet = em.find(Vet.class, currentUser.getName()); Vet vet = em.find(Vet.class, currentUser.getName());
if (vet == null) if (vet == null) throw new IllegalArgumentException("Vet not found");
throw new IllegalArgumentException("Vet not found");
pet.removeVet(vet); pet.removeVet(vet);
pet.internalRemoveVet(vet); pet.internalRemoveVet(vet);
em.merge(pet); em.merge(pet);
} }
/**
* Returns the current authenticated user (Principal).
*
* @return the current Principal.
*/
public Principal getCurrentUser() { public Principal getCurrentUser() {
return this.currentUser; return this.currentUser;
} }
/**
* Checks if the current vet is assigned to a given pet.
*
* @param petId the identifier of the pet.
* @return {@code true} if the current vet is assigned to the pet, {@code false} otherwise.
* @throws NullPointerException if {@code petId} is null.
*/
@RolesAllowed("VET") @RolesAllowed("VET")
public boolean isAssignedToCurrentVet(Long petId) { public boolean isAssignedToCurrentVet(Long petId) {
requireNonNull(petId, "Pet ID can't be null"); requireNonNull(petId, "Pet ID can't be null");
Long count = em.createQuery( Long count = em.createQuery(
"SELECT COUNT(p) FROM Pet p JOIN p.vets v WHERE p.id = :petId AND v.login = :login", "SELECT COUNT(p) FROM Pet p JOIN p.vets v WHERE p.id = :petId AND v.login = :login",
Long.class Long.class
...@@ -256,5 +258,4 @@ public class PetService { ...@@ -256,5 +258,4 @@ public class PetService {
return count > 0; return count > 0;
} }
} }
...@@ -13,9 +13,16 @@ import javax.persistence.PersistenceContext; ...@@ -13,9 +13,16 @@ 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 @PersistenceContext
private EntityManager em; private EntityManager em;
...@@ -23,42 +30,63 @@ public class UserService { ...@@ -23,42 +30,63 @@ public class UserService {
private Principal principal; private Principal principal;
/** /**
* Returns the current user entity. * Returns the entity of the currently authenticated user.
* *
* @return the entity with the information of the current user. * @return the current User entity.
*/ */
public User getCurrentUser() { public User getCurrentUser() {
return this.em.find(User.class, this.principal.getName()); return this.em.find(User.class, this.principal.getName());
} }
/**
* Returns a user by login.
*
* @param login the login of the user.
* @return the User entity, or {@code null} if not found.
*/
public User get(String login) { public User get(String login) {
return this.em.find(User.class, login); return this.em.find(User.class, login);
} }
public List<User> list(int page, int pageSize){ /**
if (page < 0) { * Returns a paginated list of users (0-based page index).
throw new IllegalArgumentException("The page can't be negative"); *
} * @param page the 0-based page index.
if (pageSize <= 0) { * @param pageSize the maximum number of users per page.
throw new IllegalArgumentException("The page size can't be negative or zero"); * @return a list of users.
} * @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive.
*/
public List<User> list(int page, int pageSize) {
if (page < 0) throw new IllegalArgumentException("The page can't be negative");
if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero");
return this.em.createQuery("SELECT DISTINCT u FROM User u", User.class) return this.em.createQuery("SELECT DISTINCT u FROM User u", User.class)
.setFirstResult(page * pageSize) .setFirstResult(page * pageSize)
.setMaxResults(pageSize) .setMaxResults(pageSize)
.getResultList(); .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) { public User create(User user) {
requireNonNull(user, "User can't be null"); requireNonNull(user, "User can't be null");
this.em.persist(user); this.em.persist(user);
return 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) { public void remove(String login) {
User user = this.get(login); User user = this.get(login);
this.em.remove(user); 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,38 +19,64 @@ import es.uvigo.esei.xcs.domain.entities.Pet; ...@@ -22,38 +19,64 @@ 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 @Inject
private Principal currentUser; private Principal currentUser;
@PersistenceContext @PersistenceContext
EntityManager em; private EntityManager em;
@EJB @EJB
private EmailService emailService; private EmailService emailService;
/**
* Returns a vaccination by its ID.
*
* @param vaccinationId the identifier of the vaccination.
* @return the Vaccination entity, or {@code null} if not found.
*/
public Vaccination get(int vaccinationId) { public Vaccination get(int vaccinationId) {
return em.find(Vaccination.class, vaccinationId); return em.find(Vaccination.class, vaccinationId);
} }
/**
* Returns a paginated list of vaccinations (0-based page index).
*
* @param page the 0-based page index.
* @param pageSize the maximum number of vaccinations per page.
* @return a list of Vaccination entities.
* @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive.
*/
public List<Vaccination> list(int page, int pageSize) {
if (page < 0) throw new IllegalArgumentException("The page can't be negative");
if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero");
public List<Vaccination> list(int page, int pageSize){
if (page < 0) {
throw new IllegalArgumentException("The page can't be negative");
}
if (pageSize <= 0) {
throw new IllegalArgumentException("The page size can't be negative or zero");
}
return em.createQuery("SELECT DISTINCT v FROM Vaccination v", Vaccination.class) return em.createQuery("SELECT DISTINCT v FROM Vaccination v", Vaccination.class)
.setFirstResult(page * pageSize) .setFirstResult(page * pageSize)
.setMaxResults(pageSize) .setMaxResults(pageSize)
.getResultList(); .getResultList();
} }
/**
* Creates a new vaccination for a pet with a given vaccine and date.
* Sends an email notification to the pet's owner.
*
* @param petId the identifier of the pet.
* @param vaccineId the identifier of the vaccine.
* @param date the date of the vaccination.
* @return the persisted Vaccination entity.
* @throws NullPointerException if {@code pet} or {@code vaccine} is null.
* @throws IllegalArgumentException if the vaccination cannot be created due to vaccine rules.
*/
public Vaccination create(Long petId, Long vaccineId, Date date) { public Vaccination create(Long petId, Long vaccineId, Date date) {
Pet pet = requireNonNull(em.find(Pet.class, petId), "Pet can't be null"); Pet pet = requireNonNull(em.find(Pet.class, petId), "Pet can't be null");
Vaccine vaccine = requireNonNull(em.find(Vaccine.class, vaccineId), "Vaccine can't be null"); Vaccine vaccine = requireNonNull(em.find(Vaccine.class, vaccineId), "Vaccine can't be null");
...@@ -72,8 +95,14 @@ public class VaccinationService { ...@@ -72,8 +95,14 @@ public class VaccinationService {
return vaccination; return vaccination;
} }
/**
* Updates the date of an existing vaccination.
*
* @param vaccinationId the identifier of the vaccination.
* @param date the new date.
* @return the updated Vaccination entity.
* @throws NullPointerException if the vaccination does not exist.
*/
public Vaccination updateDate(int vaccinationId, Date date) { public Vaccination updateDate(int vaccinationId, Date date) {
Vaccination vaccination = em.find(Vaccination.class, vaccinationId); Vaccination vaccination = em.find(Vaccination.class, vaccinationId);
requireNonNull(vaccination, "Vaccination can't be null"); requireNonNull(vaccination, "Vaccination can't be null");
...@@ -81,14 +110,26 @@ public class VaccinationService { ...@@ -81,14 +110,26 @@ public class VaccinationService {
return em.merge(vaccination); return em.merge(vaccination);
} }
/**
* Removes a vaccination by its ID.
*
* @param vaccinationId the identifier of the vaccination.
* @throws NullPointerException if the vaccination does not exist.
*/
public void remove(int vaccinationId) { public void remove(int vaccinationId) {
Vaccination vaccination = this.get(vaccinationId); Vaccination vaccination = this.get(vaccinationId);
requireNonNull(vaccination, "Vaccination can't be null"); requireNonNull(vaccination, "Vaccination can't be null");
em.remove(vaccination); em.remove(vaccination);
} }
/**
* Checks whether a pet can be vaccinated with a given vaccine on a given date.
*
* @param petId the identifier of the pet.
* @param vaccineId the identifier of the vaccine.
* @param date the intended vaccination date.
* @return {@code true} if vaccination is allowed, {@code false} otherwise.
*/
public Boolean canVaccinate(Long petId, Long vaccineId, Date date) { public Boolean canVaccinate(Long petId, Long vaccineId, Date date) {
Pet pet = em.find(Pet.class, petId); Pet pet = em.find(Pet.class, petId);
Vaccine vaccine = em.find(Vaccine.class, vaccineId); Vaccine vaccine = em.find(Vaccine.class, vaccineId);
...@@ -115,27 +156,17 @@ public class VaccinationService { ...@@ -115,27 +156,17 @@ public class VaccinationService {
long diffDays; long diffDays;
switch (periodic.getPeriodicType()) { switch (periodic.getPeriodicType()) {
case YEARS: case YEARS: diffDays = periodic.getPeriode() * 365L; break;
diffDays = periodic.getPeriode() * 365L; case MONTHS: diffDays = periodic.getPeriode() * 30L; break;
break; case DAYS: diffDays = periodic.getPeriode(); break;
case MONTHS: default: return false;
diffDays = periodic.getPeriode() * 30L;
break;
case DAYS:
diffDays = periodic.getPeriode();
break;
default:
return false;
} }
long diffMillis = date.getTime() - last.getDate().getTime(); long diffMillis = date.getTime() - last.getDate().getTime();
return diffMillis >= diffDays * 24L * 60L * 60L * 1000L; return diffMillis >= diffDays * 24L * 60L * 60L * 1000L;
} else { // MONODOSE } else { // Monodose
return prevVaccinations.isEmpty(); 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,33 +14,59 @@ import es.uvigo.esei.xcs.domain.entities.PeriodicVaccine; ...@@ -17,33 +14,59 @@ 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 @PersistenceContext
private EntityManager em; private EntityManager em;
/**
* Returns a vaccine by its ID.
*
* @param id the identifier of the vaccine.
* @return the Vaccine entity, or {@code null} if not found.
*/
public Vaccine get(Long id) { public Vaccine get(Long id) {
final Vaccine vaccine = em.find(Vaccine.class, id); return em.find(Vaccine.class, id);
return vaccine;
} }
/**
* Returns a paginated list of vaccines (0-based page index).
*
* @param page the 0-based page index.
* @param pageSize the maximum number of vaccines per page.
* @return a list of Vaccine entities.
* @throws IllegalArgumentException if {@code page} is negative or {@code pageSize} is not positive.
*/
public List<Vaccine> list(int page, int pageSize) {
if (page < 0) throw new IllegalArgumentException("The page can't be negative");
if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero");
public List<Vaccine> list(int page, int pageSize){
if (page < 0) {
throw new IllegalArgumentException("The page can't be negative");
}
if (pageSize <= 0) {
throw new IllegalArgumentException("The page size can't be negative or zero");
}
return em.createQuery("SELECT v FROM Vaccine v", Vaccine.class) return em.createQuery("SELECT v FROM Vaccine v", Vaccine.class)
.setFirstResult(page * pageSize) .setFirstResult(page * pageSize)
.setMaxResults(pageSize) .setMaxResults(pageSize)
.getResultList(); .getResultList();
} }
/**
* Creates a vaccine of a specific type.
*
* @param name the name of the vaccine.
* @param type the type of vaccine ("MONODOSE", "MULTIDOSE", "PERIODIC").
* @param doses the number of doses (for MULTIDOSE).
* @param periodicTypeString the periodic type string (for PERIODIC).
* @param periode the period length (for PERIODIC).
* @return the created Vaccine entity.
* @throws IllegalArgumentException if the type is unknown.
*/
public Vaccine create(String name, String type, Integer doses, String periodicTypeString, Integer periode) { public Vaccine create(String name, String type, Integer doses, String periodicTypeString, Integer periode) {
switch(type) { switch(type) {
case "MONODOSE": case "MONODOSE":
...@@ -62,69 +85,86 @@ public class VaccineService { ...@@ -62,69 +85,86 @@ public class VaccineService {
PeriodicVaccine periodicVaccine = new PeriodicVaccine(name, periodicType, periode); PeriodicVaccine periodicVaccine = new PeriodicVaccine(name, periodicType, periode);
em.persist(periodicVaccine); em.persist(periodicVaccine);
return periodicVaccine; return periodicVaccine;
default: throw new IllegalArgumentException("Tipo de vacuna desconocido"); default: throw new IllegalArgumentException("Unknown vaccine type");
} }
} }
/**
* Updates an existing vaccine.
*
* @param vaccine the Vaccine entity to update.
* @return the updated Vaccine entity.
* @throws IllegalArgumentException if {@code vaccine} is null.
*/
public Vaccine update(Vaccine vaccine) { public Vaccine update(Vaccine vaccine) {
if (vaccine == null) if (vaccine == null) throw new IllegalArgumentException("vaccine can't be null");
throw new IllegalArgumentException("vaccine can't be null");
return em.merge(vaccine); return em.merge(vaccine);
} }
/**
* Updates the name of a vaccine.
*
* @param id the identifier of the vaccine.
* @param newName the new name.
* @return the updated Vaccine entity.
* @throws IllegalArgumentException if the id or name is invalid or the vaccine is not found.
*/
public Vaccine updateName(Long id, String newName) { public Vaccine updateName(Long id, String newName) {
if (id == null || newName == null || newName.trim().isEmpty()) if (id == null || newName == null || newName.trim().isEmpty())
throw new IllegalArgumentException("Id o nombre inválido"); throw new IllegalArgumentException("Id or name invalid");
Vaccine vaccine = em.find(Vaccine.class, id); Vaccine vaccine = em.find(Vaccine.class, id);
if (vaccine == null) if (vaccine == null) throw new IllegalArgumentException("Vaccine not found");
throw new IllegalArgumentException("Vacuna no encontrada");
vaccine.setName(newName); vaccine.setName(newName);
return em.merge(vaccine); return em.merge(vaccine);
} }
/**
* Removes a vaccine by its ID.
*
* @param id the identifier of the vaccine.
*/
public void remove(Long id) { public void remove(Long id) {
final Vaccine vaccine = this.get(id); final Vaccine vaccine = this.get(id);
em.remove(vaccine); 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");
public List<Pet> getVaccinatedPetsByVaccine(int vaccineId, int page, int pageSize){ return em.createQuery("SELECT v.pet FROM Vaccination v WHERE v.vaccine.id = :vaccineId", Pet.class)
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) .setFirstResult(page * pageSize)
.setMaxResults(pageSize) .setMaxResults(pageSize)
.setParameter("vaccineId", vaccineId) .setParameter("vaccineId", vaccineId)
.getResultList(); .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");
public List<Pet> getVaccinatedPetsByVaccineName(String vaccineName, int page, int pageSize){ return em.createQuery("SELECT v.pet FROM Vaccination v WHERE v.vaccine.name = :vaccineName", Pet.class)
if (page < 0) {
throw new IllegalArgumentException("The page can't be negative");
}
if (pageSize <= 0) {
throw new IllegalArgumentException("The page size can't be negative or zero");
}
return em.createQuery("SELECT v.pet FROM Vaccination v\r\n"
+ "WHERE v.vaccine.name = :vaccineName", Pet.class)
.setFirstResult(page * pageSize) .setFirstResult(page * pageSize)
.setMaxResults(pageSize) .setMaxResults(pageSize)
.setParameter("vaccineName", vaccineName) .setParameter("vaccineName", vaccineName)
.getResultList(); .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,15 +16,28 @@ import es.uvigo.esei.xcs.domain.entities.Pet; ...@@ -17,15 +16,28 @@ 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 @Inject
private Principal currentUser; private Principal currentUser;
@PersistenceContext @PersistenceContext
EntityManager em; private EntityManager em;
/**
* Counts the number of pets assigned to the current vet.
*
* @return the number of pets assigned to the current vet.
*/
public int countPets() { public int countPets() {
Long count = em.createQuery( Long count = em.createQuery(
"SELECT COUNT(p) FROM Vet v JOIN v.pets p WHERE v.login = :login", Long.class) "SELECT COUNT(p) FROM Vet v JOIN v.pets p WHERE v.login = :login", Long.class)
...@@ -34,88 +46,119 @@ public class VetService { ...@@ -34,88 +46,119 @@ public class VetService {
return count.intValue(); return count.intValue();
} }
/**
* Returns a vet by login.
*
* @param login the login of the vet.
* @return the Vet entity, or {@code null} if not found.
*/
public Vet get(String login) { public Vet get(String login) {
return em.find(Vet.class, login); return em.find(Vet.class, login);
} }
/**
public List<Vet> list(){ * Returns a list of all vets.
*
* @return a list of Vet entities.
*/
public List<Vet> list() {
return em.createQuery("SELECT DISTINCT v FROM Vet v", Vet.class) return em.createQuery("SELECT DISTINCT v FROM Vet v", Vet.class)
.getResultList(); .getResultList();
} }
/**
public List<Vet> findByPetName(String petName, int page, int pageSize){ * Returns a paginated list of vets that have a pet with the given name.
*
* @param petName the name of the pet.
* @param page the 0-based page index.
* @param pageSize the maximum number of vets per page.
* @return a list of Vet entities.
*/
public List<Vet> findByPetName(String petName, int page, int pageSize) {
requireNonNull(petName, "Pet's name can't be null"); requireNonNull(petName, "Pet's name can't be null");
if (page < 0) { if (page < 0) throw new IllegalArgumentException("The page can't be negative");
throw new IllegalArgumentException("The page can't be negative"); if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero");
}
if (pageSize <= 0) { return em.createQuery("SELECT DISTINCT v FROM Vet v JOIN v.pets p WHERE p.name = :petName", Vet.class)
throw new IllegalArgumentException("The page size can't be negative or zero");
}
return this.em.createQuery("SELECT DISTINCT v FROM Vet v JOIN v.pets p "
+ "WHERE p.name = :petName", Vet.class)
.setFirstResult(page * pageSize) .setFirstResult(page * pageSize)
.setMaxResults(pageSize) .setMaxResults(pageSize)
.setParameter("petName", petName) .setParameter("petName", petName)
.getResultList(); .getResultList();
} }
/**
* Creates a new vet.
*
* @param vet the Vet entity to create.
* @return the persisted Vet entity.
*/
public Vet create(Vet vet) { public Vet create(Vet vet) {
requireNonNull(Vet.class, "Vet can't be null"); requireNonNull(vet, "Vet can't be null");
em.persist(vet); em.persist(vet);
return vet; return vet;
} }
/**
* Updates an existing vet.
*
* @param vet the Vet entity to update.
* @return the updated Vet entity.
*/
public Vet update(Vet vet) { public Vet update(Vet vet) {
requireNonNull(Vet.class, "Vet can't be null"); requireNonNull(vet, "Vet can't be null");
return em.merge(vet); return em.merge(vet);
} }
/**
* Removes a vet by login.
*
* @param login the login of the vet to remove.
*/
public void remove(String login) { public void remove(String login) {
em.remove(this.get(login)); em.remove(this.get(login));
} }
/**
public List<Pet> getPets(int first , int pageSize) { * Returns a paginated list of pets assigned to the current vet.
*
* @param first the index of the first pet (0-based).
* @param pageSize the maximum number of pets per page.
* @return a list of Pet entities.
*/
public List<Pet> getPets(int first, int pageSize) {
if (first < 0) throw new IllegalArgumentException("First can't be negative"); if (first < 0) throw new IllegalArgumentException("First can't be negative");
if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive"); if (pageSize <= 0) throw new IllegalArgumentException("Page size must be positive");
return this.em.createQuery("SELECT DISTINCT p FROM Vet v JOIN v.pets p " return em.createQuery("SELECT DISTINCT p FROM Vet v JOIN v.pets p WHERE v.login = :login", Pet.class)
+ "WHERE v.login = :login", Pet.class)
.setFirstResult(first) .setFirstResult(first)
.setMaxResults(pageSize) .setMaxResults(pageSize)
.setParameter("login", currentUser.getName()) .setParameter("login", currentUser.getName())
.getResultList(); .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( public List<Vaccination> getVaccinationsFromOwnPet(
IdentifierType identifierType, IdentifierType identifierType,
String identifierValue, String identifierValue,
int page, int page,
int pageSize int pageSize) {
){
requireNonNull(identifierType, "pet's identifier type can't be null"); requireNonNull(identifierType, "Pet's identifier type can't be null");
requireNonNull(identifierValue, "pet's identifier value can't be null"); requireNonNull(identifierValue, "Pet's identifier value can't be null");
if (page < 0) { if (page < 0) throw new IllegalArgumentException("The page can't be negative");
throw new IllegalArgumentException("The page can't be negative"); if (pageSize <= 0) throw new IllegalArgumentException("The page size can't be negative or zero");
}
if (pageSize <= 0) {
throw new IllegalArgumentException("The page size can't be negative or zero");
}
return em.createQuery( return em.createQuery(
"SELECT v FROM Vet vet " "SELECT v FROM Vet vet JOIN vet.pets p JOIN p.identifiers i JOIN p.vaccinations v " +
+ "JOIN vet.pets p " "WHERE vet.login = :login AND i.type = :identifierType AND i.value = :identifierValue",
+ "JOIN p.identifiers i "
+ "JOIN p.vaccinations v "
+ "WHERE "
+ "vet.login = :login AND "
+ "i.type = :identifierType AND "
+ "i.value = :identifierValue",
Vaccination.class) Vaccination.class)
.setParameter("login", currentUser.getName()) .setParameter("login", currentUser.getName())
.setParameter("identifierType", identifierType) .setParameter("identifierType", identifierType)
...@@ -124,6 +167,4 @@ public class VetService { ...@@ -124,6 +167,4 @@ public class VetService {
.setMaxResults(pageSize) .setMaxResults(pageSize)
.getResultList(); .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