diff --git a/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java b/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java index 2a67f22f93bf402148426fd8becb0ce7c8f37dfc..18f4b96d75183222a7fba00d61ecb7b0a8a8239b 100644 --- a/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java +++ b/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java @@ -11,6 +11,7 @@ import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; import es.uvigo.esei.daa.rest.PeopleResource; +import es.uvigo.esei.daa.rest.PetsResource; import es.uvigo.esei.daa.rest.UsersResource; /** @@ -26,7 +27,8 @@ public class DAAExampleApplication extends Application { public Set> getClasses() { return Stream.of( PeopleResource.class, - UsersResource.class + UsersResource.class, + PetsResource.class ).collect(toSet()); } diff --git a/src/main/java/es/uvigo/esei/daa/dao/PetDAO.java b/src/main/java/es/uvigo/esei/daa/dao/PetDAO.java new file mode 100644 index 0000000000000000000000000000000000000000..f75371bc7ab489b8e71708d79fad3e005cca1a08 --- /dev/null +++ b/src/main/java/es/uvigo/esei/daa/dao/PetDAO.java @@ -0,0 +1,238 @@ +package es.uvigo.esei.daa.dao; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import es.uvigo.esei.daa.entities.Person; +import es.uvigo.esei.daa.entities.Pet; + +/** + * DAO class for managing the pets of the system. + * + * @author Miguel Ferreiro Diaz + */ +public class PetDAO extends DAO { + private final static Logger LOG = Logger.getLogger(PetDAO.class.getName()); + + /** + * Returns a person stored persisted in the system. + * + * @param id identifier of the pet. + * @return a pet with the provided identifier. + * @throws DAOException if an error happens while retrieving the pet. + * @throws IllegalArgumentException if the provided id does not corresponds + * with any persisted pet. + */ + public Pet get(int id) + throws DAOException, IllegalArgumentException { + try (final Connection conn = this.getConnection()) { + final String query = "SELECT * FROM pets WHERE id=?"; + + try (final PreparedStatement statement = conn.prepareStatement(query)) { + statement.setInt(1, id); + + try (final ResultSet result = statement.executeQuery()) { + if (result.next()) { + return rowToEntity(result); + } else { + throw new IllegalArgumentException("Invalid id"); + } + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error getting a pet", e); + throw new DAOException(e); + } + } + + /** + * Returns a list with all the pets persisted in the system. + * + * @return a list with all the pets persisted in the system. + * @throws DAOException if an error happens while retrieving the pets. + */ + public List list() throws DAOException { + try (final Connection conn = this.getConnection()) { + final String query = "SELECT * FROM pets"; + + try (final PreparedStatement statement = conn.prepareStatement(query)) { + try (final ResultSet result = statement.executeQuery()) { + final List pets = new LinkedList<>(); + + while (result.next()) { + pets.add(rowToEntity(result)); + } + + return pets; + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error listing pets", e); + throw new DAOException(e); + } + } + + /** + * Persists a new pet in the system. An identifier will be assigned + * automatically to the new pet. + * + * @param name name of the new pet. Can't be {@code null}. + * @param specie specie of the new pet. Can't be {@code null}. + * @param idOwner idOwner of the new pet. Can't be {@code null}. + * @return a {@link Pet} entity representing the persisted pet. + * @throws DAOException if an error happens while persisting the new pet. + * @throws IllegalArgumentException if the name, specie and idOwner are {@code null}. + */ + public Pet add(String name, String specie, int idOwner) + throws DAOException, IllegalArgumentException { + if (name == null || specie == null) { + throw new IllegalArgumentException("name and specie can't be null " + specie); + } + + if ( idOwner <= 0) { + throw new IllegalArgumentException("idOwner can't be negative"); + } + + try (Connection conn = this.getConnection()) { + final String query = "INSERT INTO pets VALUES(null, ?, ?,?)"; + + try (PreparedStatement statement = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS)) { + statement.setString(1, name); + statement.setString(2, specie); + statement.setInt(3, idOwner); + + if (statement.executeUpdate() == 1) { + try (ResultSet resultKeys = statement.getGeneratedKeys()) { + if (resultKeys.next()) { + return new Pet(resultKeys.getInt(1), name, specie, idOwner); + } else { + LOG.log(Level.SEVERE, "Error retrieving inserted id"); + throw new SQLException("Error retrieving inserted id"); + } + } + } else { + LOG.log(Level.SEVERE, "Error inserting value"); + throw new SQLException("Error inserting value"); + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error adding a pet", e); + throw new DAOException(e); + } + } + + + /** + * Modifies a pet previously persisted in the system. The pet will be + * retrieved by the provided id and its current name, specie and idOwner will be + * replaced with the provided. + * + * @param pet a {@link Pet} entity with the new data. + * @throws DAOException if an error happens while modifying the new pet. + * @throws IllegalArgumentException if the pet is {@code null}. + */ + public void modify(Pet pet) + throws DAOException, IllegalArgumentException { + if (pet == null) { + throw new IllegalArgumentException("pet can't be null"); + } + + try (Connection conn = this.getConnection()) { + final String query = "UPDATE pets SET name=?, specie=?, idOwner=? WHERE id=?"; + + try (PreparedStatement statement = conn.prepareStatement(query)) { + statement.setString(1, pet.getName()); + statement.setString(2, pet.getSpecie()); + statement.setInt(3, pet.getIdOwner()); + statement.setInt(4, pet.getId()); + + if (statement.executeUpdate() != 1) { + throw new IllegalArgumentException("name, specie and idOwner can't be null"); + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error modifying a pet", e); + throw new DAOException(); + } + } + + /** + * Removes a persisted pet from the system. + * + * @param id identifier of the pet to be deleted. + * @throws DAOException if an error happens while deleting the pet. + * @throws IllegalArgumentException if the provided id does not corresponds + * with any persisted pet. + */ + public void delete(int id) + throws DAOException, IllegalArgumentException { + try (final Connection conn = this.getConnection()) { + final String query = "DELETE FROM pets WHERE id=?"; + + try (final PreparedStatement statement = conn.prepareStatement(query)) { + statement.setInt(1, id); + + if (statement.executeUpdate() != 1) { + throw new IllegalArgumentException("Invalid id"); + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error deleting a pet", e); + throw new DAOException(e); + } + } + + /** + * Returns the pets of a person stored persisted in the system. + * + * @param id identifier of the person. + * @return pets of the person with the provided identifier. + * @throws DAOException if an error happens while retrieving the person. + * @throws IllegalArgumentException if the provided id does not corresponds + * with any persisted person. + */ + public List getPets(int id) + throws DAOException, IllegalArgumentException { + try (final Connection conn = this.getConnection()) { + final String query = "SELECT T.id, T.name, T.specie, T.idOwner " + + "FROM people P, pets T " + + "WHERE P.id = T.idOwner AND P.id = ?"; + + try (final PreparedStatement statement = conn.prepareStatement(query)) { + + statement.setInt(1, id); + + try (final ResultSet result = statement.executeQuery()) { + + final List pets = new LinkedList<>(); + + while (result.next()) { + pets.add(rowToEntity(result)); + } + + return pets; + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error getting pets of a person ", e); + throw new DAOException(e); + } + } + + + private Pet rowToEntity(ResultSet row) throws SQLException { + return new Pet( + row.getInt("id"), + row.getString("name"), + row.getString("specie"), + row.getInt("idOwner") + ); + } +} diff --git a/src/main/java/es/uvigo/esei/daa/rest/PetsResource.java b/src/main/java/es/uvigo/esei/daa/rest/PetsResource.java new file mode 100644 index 0000000000000000000000000000000000000000..0edc9bf859f47a07157048bcd2d5d97b3de3e7e3 --- /dev/null +++ b/src/main/java/es/uvigo/esei/daa/rest/PetsResource.java @@ -0,0 +1,229 @@ +package es.uvigo.esei.daa.rest; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +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.MediaType; +import javax.ws.rs.core.Response; + +import es.uvigo.esei.daa.dao.DAOException; +import es.uvigo.esei.daa.dao.PetDAO; +import es.uvigo.esei.daa.entities.Person; +import es.uvigo.esei.daa.entities.Pet; + +/** + * REST resource for managing pet. + * + * @author Miguel Ferreiro Diaz. + */ +@Path("/pets") +@Produces(MediaType.APPLICATION_JSON) +public class PetsResource { + private final static Logger LOG = Logger.getLogger(PetsResource.class.getName()); + + private final PetDAO dao; + + /** + * Constructs a new instance of {@link PetResource}. + */ + public PetsResource() { + this(new PetDAO()); + } + + // Needed for testing purposes + PetsResource(PetDAO dao) { + this.dao = dao; + } + + /** + * Returns a person with the provided identifier. + * + * @param id the identifier of the person to retrieve. + * @return a 200 OK response with a person that has the provided identifier. + * If the identifier does not corresponds with any user, a 400 Bad Request + * response with an error message will be returned. If an error happens + * while retrieving the list, a 500 Internal Server Error response with an + * error message will be returned. + */ + @GET + @Path("/{id}") + public Response get( + @PathParam("id") int id + ) { + try { + final Pet pet = this.dao.get(id); + + return Response.ok(pet).build(); + } catch (IllegalArgumentException iae) { + LOG.log(Level.FINE, "Invalid person id in get method", iae); + + return Response.status(Response.Status.BAD_REQUEST) + .entity(iae.getMessage()) + .build(); + } catch (DAOException e) { + LOG.log(Level.SEVERE, "Error getting a pet", e); + + return Response.serverError() + .entity(e.getMessage()) + .build(); + } + } + + /** + * Returns the complete list of pets stored in the system. + * + * @return a 200 OK response with the complete list of pets stored in the + * system. If an error happens while retrieving the list, a 500 Internal + * Server Error response with an error message will be returned. + */ + @GET + public Response list( + @QueryParam("idOwner") Integer idOwner + ) { + try { + + if (idOwner == null) { + return Response.ok(this.dao.list()).build(); + } else { + return Response.ok(this.dao.getPets(idOwner)).build(); + } + + } catch (DAOException e) { + LOG.log(Level.SEVERE, "Error listing pets", e); + return Response.serverError().entity(e.getMessage()).build(); + } + } + + + /** + * Creates a new pet in the system. + * + * @param name the name of the new pet. + * @param specie the specie of the new pet. + * @param idOwner the idOwner of the new pet + * @return a 200 OK response with a pet that has been created. If the + * name, specie or idOwner are not provided, a 400 Bad Request response with an + * error message will be returned. If an error happens while retrieving the + * list, a 500 Internal Server Error response with an error message will be + * returned. + */ + @POST + public Response add( + @FormParam("name") String name, + @FormParam("specie") String specie, + @FormParam("idOwner") int idOwner + ) { + try { + final Pet newPet = this.dao.add(name, specie, idOwner); + + return Response.ok(newPet).build(); + } catch (IllegalArgumentException iae) { + LOG.log(Level.FINE, "Invalid pet id in add method", iae); + + return Response.status(Response.Status.BAD_REQUEST) + .entity(iae.getMessage()) + .build(); + } catch (DAOException e) { + LOG.log(Level.SEVERE, "Error adding a pet", e); + + return Response.serverError() + .entity(e.getMessage()) + .build(); + } + } + + /** + * Modifies the data of a pet. + * + * @param id identifier of the person to modify. + * @param name the new name of the person. + * @param surname the new surname of the person. + * @return a 200 OK response with a person that has been modified. If the + * identifier does not corresponds with any user or the name or surname are + * not provided, a 400 Bad Request response with an error message will be + * returned. If an error happens while retrieving the list, a 500 Internal + * Server Error response with an error message will be returned. + */ + @PUT + @Path("/{id}") + public Response modify( + @PathParam("id") int id, + @FormParam("name") String name, + @FormParam("specie") String specie, + @FormParam("idOwner") int idOwner + ) { + try { + final Pet modifiedPet = new Pet(id, name, specie, idOwner); + this.dao.modify(modifiedPet); + + return Response.ok(modifiedPet).build(); + } catch (NullPointerException npe) { + final String message = String.format("Invalid data for pet (name: %s, specie: %s, idOwner:%d )", name, specie, idOwner); + + LOG.log(Level.FINE, message); + + return Response.status(Response.Status.BAD_REQUEST) + .entity(message) + .build(); + } catch (IllegalArgumentException iae) { + LOG.log(Level.FINE, "Invalid pet id in modify method", iae); + + return Response.status(Response.Status.BAD_REQUEST) + .entity(iae.getMessage()) + .build(); + } catch (DAOException e) { + LOG.log(Level.SEVERE, "Error modifying a pet", e); + + return Response.serverError() + .entity(e.getMessage()) + .build(); + } + } + + + + + /** + * Deletes a pet from the system. + * + * @param id the identifier of the pet to be deleted. + * @return a 200 OK response with the identifier of the pet that has + * been deleted. If the identifier does not corresponds with any pet, a 400 + * Bad Request response with an error message will be returned. If an error + * happens while retrieving the list, a 500 Internal Server Error response + * with an error message will be returned. + */ + @DELETE + @Path("/{id}") + public Response delete( + @PathParam("id") int id + ) { + try { + this.dao.delete(id); + + return Response.ok(id).build(); + } catch (IllegalArgumentException iae) { + LOG.log(Level.FINE, "Invalid pet id in delete method", iae); + + return Response.status(Response.Status.BAD_REQUEST) + .entity(iae.getMessage()) + .build(); + } catch (DAOException e) { + LOG.log(Level.SEVERE, "Error deleting a pet", e); + + return Response.serverError() + .entity(e.getMessage()) + .build(); + } + } + +}