...
 
Commits (13)
...@@ -15,3 +15,8 @@ WebContent ...@@ -15,3 +15,8 @@ WebContent
# Testing # Testing
/servers /servers
C:\\nppdf32Log\\debuglog.txt C:\\nppdf32Log\\debuglog.txt
#Santi
.idea/*
example.iml
...@@ -14,6 +14,18 @@ CREATE TABLE `daaexample`.`users` ( ...@@ -14,6 +14,18 @@ CREATE TABLE `daaexample`.`users` (
PRIMARY KEY (`login`) PRIMARY KEY (`login`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `daaexample`.`pet` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner` VARCHAR(50) NOT NULL,
`name` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_pet_person` (`owner`),
CONSTRAINT `FK_pet_person` FOREIGN KEY (`owner`) REFERENCES `people` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
GRANT ALL ON `daaexample`.* TO 'daa'@'localhost' IDENTIFIED BY 'daa'; GRANT ALL ON `daaexample`.* TO 'daa'@'localhost' IDENTIFIED BY 'daa';
INSERT INTO `daaexample`.`people` (`id`,`name`,`surname`) VALUES (0,'Antón','Pérez'); INSERT INTO `daaexample`.`people` (`id`,`name`,`surname`) VALUES (0,'Antón','Pérez');
...@@ -30,3 +42,5 @@ INSERT INTO `daaexample`.`users` (`login`,`password`,`role`) ...@@ -30,3 +42,5 @@ INSERT INTO `daaexample`.`users` (`login`,`password`,`role`)
VALUES ('admin', '713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca','ADMIN'); VALUES ('admin', '713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca','ADMIN');
INSERT INTO `daaexample`.`users` (`login`,`password`,`role`) INSERT INTO `daaexample`.`users` (`login`,`password`,`role`)
VALUES ('normal', '7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83','USER'); VALUES ('normal', '7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83','USER');
INSERT INTO `daaexample`.`pet` (`id`, `owner`, `name`)
VALUES ('1', '1', 'Tom'), ('2', '1', 'Jerry');
...@@ -14,4 +14,14 @@ CREATE TABLE `daaexample`.`users` ( ...@@ -14,4 +14,14 @@ CREATE TABLE `daaexample`.`users` (
PRIMARY KEY (`login`) PRIMARY KEY (`login`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `daaexample`.`pet` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner` int(11) NOT NULL,
`name` VARCHAR (50) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_pet_person` (`owner`),
CONSTRAINT `FK_pet_person` FOREIGN KEY (`owner`) REFERENCES `people` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
GRANT ALL ON `daaexample`.* TO 'daa'@'localhost' IDENTIFIED BY 'daa'; GRANT ALL ON `daaexample`.* TO 'daa'@'localhost' IDENTIFIED BY 'daa';
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<groupId>es.uvigo.esei.daa</groupId> <groupId>es.uvigo.esei.daa</groupId>
<artifactId>example</artifactId> <artifactId>example</artifactId>
<packaging>war</packaging> <packaging>war</packaging>
<version>0.1.11</version> <version>0.1.12</version>
<name>DAA Example</name> <name>DAA Example</name>
<licenses> <licenses>
......
package es.uvigo.esei.daa; package es.uvigo.esei.daa;
import static java.util.stream.Collectors.toSet; import es.uvigo.esei.daa.rest.PeopleResource;
import es.uvigo.esei.daa.rest.PetsResource;
import es.uvigo.esei.daa.rest.UsersResource;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.ws.rs.ApplicationPath; import static java.util.stream.Collectors.toSet;
import javax.ws.rs.core.Application;
import es.uvigo.esei.daa.rest.PeopleResource;
import es.uvigo.esei.daa.rest.UsersResource;
/** /**
* Configuration of the REST application. This class includes the resources and * Configuration of the REST application. This class includes the resources and
...@@ -26,7 +26,8 @@ public class DAAExampleApplication extends Application { ...@@ -26,7 +26,8 @@ public class DAAExampleApplication extends Application {
public Set<Class<?>> getClasses() { public Set<Class<?>> getClasses() {
return Stream.of( return Stream.of(
PeopleResource.class, PeopleResource.class,
UsersResource.class UsersResource.class,
PetsResource.class
).collect(toSet()); ).collect(toSet());
} }
......
package es.uvigo.esei.daa.dao;
import es.uvigo.esei.daa.entities.Pet;
import java.sql.*;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class PetsDAO extends DAO {
private final static Logger LOG = Logger.getLogger(PetsDAO.class.getName());
public Pet get(int id) throws DAOException, IllegalArgumentException {
try (final Connection conn = this.getConnection()) {
final String query = "SELECT * FROM pet 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 person", e);
throw new DAOException(e);
}
}
private Pet rowToEntity(ResultSet row) throws SQLException {
return new Pet(
row.getInt("id"),
row.getInt("owner"),
row.getString("name")
);
}
public void delete(int id)
throws DAOException, IllegalArgumentException {
try (final Connection conn = this.getConnection()) {
final String query = "DELETE FROM pet 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);
}
}
public List<Pet> list(int owner) throws DAOException {
try (final Connection conn = this.getConnection()) {
final String query = "SELECT * FROM pet WHERE owner = ?";
try (final PreparedStatement statement = conn.prepareStatement(query)) {
statement.setInt(1, owner);
try (final ResultSet result = statement.executeQuery()) {
final List<Pet> 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);
}
}
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 pet SET name=?, owner=? WHERE id=?";
try (PreparedStatement statement = conn.prepareStatement(query)) {
statement.setString(1, pet.getName());
statement.setInt(2, pet.getOwner());
statement.setInt(3, pet.getId());
if (statement.executeUpdate() != 1) {
throw new IllegalArgumentException("name and owner can't be null");
}
}
} catch (SQLException e) {
LOG.log(Level.SEVERE, "Error modifying a pet", e);
throw new DAOException();
}
}
public Pet add(String name, int owner)
throws DAOException, IllegalArgumentException {
if (name == null) {
throw new IllegalArgumentException("name and owner can't be null");
}
try (Connection conn = this.getConnection()) {
final String query = "INSERT INTO pet VALUES(null, ?, ?)";
try (PreparedStatement statement = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS)) {
statement.setString(1, name);
statement.setInt(2, owner);
if (statement.executeUpdate() == 1) {
try (ResultSet resultKeys = statement.getGeneratedKeys()) {
if (resultKeys.next()) {
return new Pet(resultKeys.getInt(1), owner, name);
} 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);
}
}
}
package es.uvigo.esei.daa.entities;
public class Pet {
private int id;
private String name;
private int owner;
// Constructor needed for the JSON conversion
Pet() {}
/**
* Constructs a new instance of {@link Pet}
*
* @param id idintefier of the pet
* @param name name of the pet
* @param owner identifier of the pet ownet
*/
public Pet(int id, int owner, String name) {
this.id = id;
this.name = name;
this.owner = owner;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOwner() {
return owner;
}
public void setOwner(int owner) {
this.owner = owner;
}
public boolean equals(Object object) {
if (this == object) return true;
if (!(object instanceof Pet)) return false;
if (!super.equals(object)) return false;
Pet pet = (Pet) object;
return getId() == pet.getId() &&
getOwner() == pet.getOwner() &&
java.util.Objects.equals(getName(), pet.getName());
}
public int hashCode() {
return java.util.Objects.hash(super.hashCode(), getId(), getName(), getOwner());
}
}
package es.uvigo.esei.daa.rest;
import es.uvigo.esei.daa.dao.DAOException;
import es.uvigo.esei.daa.dao.PetsDAO;
import es.uvigo.esei.daa.entities.Pet;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* REST resource for managing pets.
*
* @author sgvilar.
*/
@Path("/pets")
@Produces(MediaType.APPLICATION_JSON)
public class PetsResource {
private final static Logger LOG = Logger.getLogger(PetsResource.class.getName());
private final PetsDAO dao;
public PetsResource() {
this(new PetsDAO());
}
PetsResource(PetsDAO dao) {
this.dao = dao;
}
@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 pet 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();
}
}
@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();
}
}
@GET
@Path("/owner/{owner}")
public Response list(@PathParam("owner") int owner) {
try {
return Response.ok(this.dao.list(owner)).build();
} catch (DAOException e) {
LOG.log(Level.SEVERE, "Error listing pets", e);
return Response.serverError().entity(e.getMessage()).build();
}
}
@PUT
@Path("/{id}")
public Response modify(
@PathParam("id") int id,
@FormParam("name") String name,
@FormParam("owner") int owner
) {
try {
final Pet modifiedPet = new Pet(id, owner, name);
this.dao.modify(modifiedPet);
return Response.ok(modifiedPet).build();
} catch (NullPointerException npe) {
final String message = String.format("Invalid data for pet (name: %s, owner: %s)", name, owner);
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();
}
}
@POST
public Response add(
@FormParam("name") String name,
@FormParam("owner") int owner
) {
try {
final Pet newPet = this.dao.add(name, owner);
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();
}
}
}
...@@ -5,7 +5,7 @@ var PeopleDAO = (function() { ...@@ -5,7 +5,7 @@ var PeopleDAO = (function() {
fail = typeof fail !== 'undefined' ? fail : function() {}; fail = typeof fail !== 'undefined' ? fail : function() {};
always = typeof always !== 'undefined' ? always : function() {}; always = typeof always !== 'undefined' ? always : function() {};
let authToken = localStorage.getItem('authorization-token'); var authToken = localStorage.getItem('authorization-token');
if (authToken !== null) { if (authToken !== null) {
data.beforeSend = function(xhr) { data.beforeSend = function(xhr) {
xhr.setRequestHeader('Authorization', 'Basic ' + authToken); xhr.setRequestHeader('Authorization', 'Basic ' + authToken);
...@@ -23,7 +23,7 @@ var PeopleDAO = (function() { ...@@ -23,7 +23,7 @@ var PeopleDAO = (function() {
}, done, fail, always); }, done, fail, always);
}; };
this.addPerson = function(person, done, fail, always) { this.addPet = function (person, done, fail, always) {
requestByAjax({ requestByAjax({
url : resourcePath, url : resourcePath,
type : 'POST', type : 'POST',
...@@ -31,7 +31,7 @@ var PeopleDAO = (function() { ...@@ -31,7 +31,7 @@ var PeopleDAO = (function() {
}, done, fail, always); }, done, fail, always);
}; };
this.modifyPerson = function(person, done, fail, always) { this.modifyPet = function (person, done, fail, always) {
requestByAjax({ requestByAjax({
url : resourcePath + person.id, url : resourcePath + person.id,
type : 'PUT', type : 'PUT',
......
var PetsDAO = (function () {
var resourcePath = "rest/pets/";
var requestByAjax = function (data, done, fail, always) {
done = typeof done !== 'undefined' ? done : function () {
};
fail = typeof fail !== 'undefined' ? fail : function () {
};
always = typeof always !== 'undefined' ? always : function () {
};
var authToken = localStorage.getItem('authorization-token');
if (authToken !== null) {
data.beforeSend = function (xhr) {
xhr.setRequestHeader('Authorization', 'Basic ' + authToken);
};
}
$.ajax(data).done(done).fail(fail).always(always);
};
function PetsDAO() {
this.listPets = function (owner, done, fail, always) {
requestByAjax({
url: resourcePath + "owner/" + owner,
type: 'GET'
}, done, fail, always);
};
this.addPet = function (pet, done, fail, always) {
requestByAjax({
url: resourcePath,
type: 'POST',
data: pet
}, done, fail, always);
};
this.modifyPet = function (pet, done, fail, always) {
requestByAjax({
url: resourcePath + pet.id,
type: 'PUT',
data: pet
}, done, fail, always);
};
this.deletePet = function (id, done, fail, always) {
requestByAjax({
url: resourcePath + id,
type: 'DELETE',
}, done, fail, always);
};
}
return PetsDAO;
})();
\ No newline at end of file
This diff is collapsed.
var PetsView = (function () {
var dao;
// Referencia a this que permite acceder a las funciones públicas desde las funciones de jQuery.
var self;
var formId = 'pets-form';
var listId = 'pets-list';
var formQuery = '#' + formId;
var listQuery = '#' + listId;
function PetsView(owner, petsDao, formContainerId, listContainerId) {
dao = petsDao;
self = this;
insertPetsForm($('#' + formContainerId));
insertPetsList($('#' + listContainerId));
this.init = function () {
dao.listPets(owner, function (pets) {
$.each(pets, function (key, pet) {
appendToTable(pet);
});
},
function () {
alert('No has sido posible acceder al listado de mascotas.');
});
// La acción por defecto de enviar formulario (submit) se sobreescribe
// para que el envío sea a través de AJAX
$(formQuery).submit(function (event) {
var pet = self.getPetInForm();
if (self.isEditing()) {
dao.modifyPet(pet,
function (pet) {
$('#pet-' + pet.id + ' td.name').text(pet.name);
$('#pet-' + pet.id + ' td.owner').text(pet.owner);
self.resetForm();
},
showErrorMessage,
self.enableForm
);
} else {
dao.addPet(pet,
function (pet) {
appendToTable(pet);
self.resetForm();
},
showErrorMessage,
self.enableForm
);
}
return false;
});
$('#btnClear').click(this.resetForm);
};
this.getPetInForm = function () {
var form = $(formQuery);
return {
'id': form.find('input[name="id"]').val(),
'name': form.find('input[name="name"]').val(),
'owner': form.find('input[name="owner"]').val()
};
};
this.getPetInRow = function (id) {
var row = $('#pet-' + id);
if (row !== undefined) {
return {
'id': id,
'name': row.find('td.name').text(),
'owner': row.find('td.owner').text()
};
} else {
return undefined;
}
};
this.editPet = function (id) {
var row = $('#pet-' + id);
if (row !== undefined) {
var form = $(formQuery);
form.find('input[name="id"]').val(id);
form.find('input[name="name"]').val(row.find('td.name').text());
form.find('input[name="owner"]').val(row.find('td.owner').text());
$('input#btnSubmit').val('Modificar');
}
};
this.deletePet = function (id) {
if (confirm('Está a punto de eliminar a una mascota. ¿Está seguro de que desea continuar?')) {
dao.deletePet(id,
function () {
$('tr#pet-' + id).remove();
},
showErrorMessage
);
}
};
this.showPets = function (id) {
}
this.isEditing = function () {
return $(formQuery + ' input[name="id"]').val() != "";
};
this.disableForm = function () {
$(formQuery + ' input').prop('disabled', true);
};
this.enableForm = function () {
$(formQuery + ' input').prop('disabled', false);
};
this.resetForm = function () {
$(formQuery)[0].reset();
$(formQuery + ' input[name="id"]').val('');
$('#btnSubmit').val('Crear');
};
};
var insertPetsList = function (parent) {
parent.append(
'<table id="' + listId + '" class="table">\
<thead>\
<tr class="row">\
<th class="col-sm-4">Nombre</th>\
<th class="col-sm-5">Propietario</th>\
<th class="col-sm-3">&nbsp;</th>\
</tr>\
</thead>\
<tbody>\
</tbody>\
</table>'
);
};
var insertPetsForm = function (parent) {
parent.append(
'<form id="' + formId + '" class="mb-5 mb-10">\
<input name="id" type="hidden" value=""/>\
<div class="row">\
<div class="col-sm-4">\
<input name="name" type="text" value="" placeholder="Nombre" class="form-control" required/>\
</div>\
<div class="col-sm-5">\
<input name="owner" type="text" value="" placeholder="Dueño" class="form-control" required/>\
</div>\
<div class="col-sm-3">\
<input id="btnSubmit" type="submit" value="Crear" class="btn btn-primary" />\
<input id="btnClear" type="reset" value="Limpiar" class="btn" />\
</div>\
</div>\
</form>'
);
};
var createPetRow = function (pet) {
return '<tr id="pet-' + pet.id + '" class="row">\
<td class="name col-sm-6 col-md-3">' + pet.name + '</td>\
<td class="owner col-sm-6 col-md-4">' + pet.owner + '</td>\
<td class="col-sm-12 col-md-5">\
<a class="edit btn btn-warning" href="#">Editar</a>\
<a class="delete btn btn-danger" href="#">Eliminar</a>\
</td>\
</tr>';
};
var showErrorMessage = function (jqxhr, textStatus, error) {
alert(textStatus + ": " + error);
};
var addRowListeners = function (pet) {
$('#pet-' + pet.id + ' a.edit').click(function () {
self.editPet(pet.id);
});
$('#pet-' + pet.id + ' a.delete').click(function () {
self.deletePet(pet.id);
});
};
var appendToTable = function (pet) {
$(listQuery + ' > tbody:last')
.append(createPetRow(pet));
addRowListeners(pet);
};
return PetsView;
})();
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>DAA Example</title> <title>DAA Example</title>
<link rel="stylesheet" <link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"> href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head> </head>
<body> <body>
<header> <header>
<div class="navbar navbar-dark bg-dark box-shadow"> <div class="navbar navbar-dark bg-dark box-shadow">
<div class="container d-flex justify-content-between"> <div class="container d-flex justify-content-between">
<a href="#" class="navbar-brand d-flex align-items-center"> <a href="#" class="navbar-brand d-flex align-items-center">
<strong>DAA Example</strong> <strong>DAA Example</strong>
</a> </a>
<button id="logout" class="btn btn-dark">Cerrar sesión</button> <button id="logout" class="btn btn-dark">Cerrar sesión</button>
</div> </div>
</div> </div>
</header> </header>
<div class="container"> <div class="container">
<div id="people-container"> <div id="people-container">
<h1 class="display-5 mt-3 mb-3">Personas</h1> <h1 class="display-5 mt-3 mb-3">Personas</h1>
</div> </div>
</div> <div id="pet-container">
<h1 class="display-5 mt-3 mb-3">Mascotas</h1>
<script type="text/javascript" </div>
src="http://code.jquery.com/jquery-2.2.4.min.js"></script> </div>
<script type="text/javascript" src="js/dao/people.js"></script>
<script type="text/javascript" src="js/view/people.js"></script>
<script type="text/javascript" src="js/login.js"></script>
<script type="text/javascript">
$(document).ready(
function() {
$('#logout').click(function(event) {
event.preventDefault();
doLogout();
});
var view = new PeopleView(new PeopleDAO(), <script type="text/javascript"
'people-container', 'people-container' src="http://code.jquery.com/jquery-2.2.4.min.js"></script>
); <script type="text/javascript" src="js/dao/people.js"></script>
<script type="text/javascript" src="js/view/people.js"></script>
<script type="text/javascript" src="js/dao/pets.js"></script>
<script type="text/javascript" src="js/view/pets.js"></script>
<script type="text/javascript" src="js/login.js"></script>
<script type="text/javascript">
$(document).ready(
function () {
$('#logout').click(function (event) {
event.preventDefault();
doLogout();
});
document.getElementById("pet-container").style.display = "none";
document.getElementById('people-container').style.display = 'block';
view.init(); var view = new PeopleView(new PeopleDAO(),
}); 'people-container', 'people-container'
</script> );
view.init();
});
</script>
</body> </body>
</html> </html>
\ No newline at end of file
package es.uvigo.esei.daa.dataset; package es.uvigo.esei.daa.dataset;
import static java.util.Arrays.binarySearch; import es.uvigo.esei.daa.entities.Person;
import static java.util.Arrays.stream;
import java.util.Arrays; import java.util.Arrays;
import java.util.function.Predicate; import java.util.function.Predicate;
import es.uvigo.esei.daa.entities.Person; import static java.util.Arrays.binarySearch;
import static java.util.Arrays.stream;
public final class PeopleDataset { public final class PeopleDataset {
private PeopleDataset() {} private PeopleDataset() {}
...@@ -45,7 +45,7 @@ public final class PeopleDataset { ...@@ -45,7 +45,7 @@ public final class PeopleDataset {
} }
public static int existentId() { public static int existentId() {
return 5; return 1;
} }
public static int nonExistentId() { public static int nonExistentId() {
......
package es.uvigo.esei.daa.dataset;
import es.uvigo.esei.daa.entities.Pet;
import static java.util.Arrays.stream;
public final class PetsDataset {
private PetsDataset() {
}
public static Pet[] pets() {
return new Pet[]{
new Pet(1, 1, "Tom"),
new Pet(2, 1, "Jerry")
};
}
public static Pet pet(int id) {
return stream(pets())
.filter(p -> p.getId() == id)
.findAny()
.orElseThrow(IllegalArgumentException::new);
}
public static int existentId() {
return 1;
}
public static Pet existentPet() {
return pet(existentId());
}
public static String newName() { return "Nibbles";}
public static int newOwner() {
return 2;
}
public static Pet newPet() {
return new Pet(pets().length + 1, newOwner(), newName());
}
}
package es.uvigo.esei.daa.matchers;
import es.uvigo.esei.daa.entities.Person;
import es.uvigo.esei.daa.entities.Pet;
import org.hamcrest.Factory;
import org.hamcrest.Matcher;
public class IsEqualToPet extends IsEqualToEntity<Pet> {
public IsEqualToPet(Pet entity) {
super(entity);
}
@Override
protected boolean matchesSafely(Pet actual) {
this.clearDescribeTo();
if (actual == null) {
this.addTemplatedDescription("actual", expected.toString());
return false;
} else {
return checkAttribute("id", Pet::getId, actual)
&& checkAttribute("name", Pet::getName, actual)
&& checkAttribute("owner", Pet::getOwner, actual);
}
}
/**
* Factory method that creates a new {@link IsEqualToEntity} matcher with
* the provided {@link Person} as the expected value.
*
* @param pet the expected pet.
* @return a new {@link IsEqualToEntity} matcher with the provided
* {@link Person} as the expected value.
*/
@Factory
public static IsEqualToPet equalsToPet(Pet pet) {
return new IsEqualToPet(pet);
}
/**
* Factory method that returns a new {@link Matcher} that includes several
* {@link IsEqualToPet} matchers, each one using an {@link Person} of the
* provided ones as the expected value.
*
* @param pets the pets to be used as the expected values.
* @return a new {@link Matcher} that includes several
* {@link IsEqualToPet} matchers, each one using an {@link Person} of the
* provided ones as the expected value.
* @see IsEqualToEntity#containsEntityInAnyOrder(java.util.function.Function, Object...)
*/
@Factory
public static Matcher<Iterable<? extends Pet>> containsPetsInAnyOrder(Pet ... pets) {
return containsEntityInAnyOrder(IsEqualToPet::equalsToPet, pets);
}
}
package es.uvigo.esei.daa.rest;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import es.uvigo.esei.daa.DAAExampleApplication;
import es.uvigo.esei.daa.entities.Pet;
import es.uvigo.esei.daa.listeners.ApplicationContextBinding;
import es.uvigo.esei.daa.listeners.ApplicationContextJndiBindingTestExecutionListener;
import es.uvigo.esei.daa.listeners.DbManagement;
import es.uvigo.esei.daa.listeners.DbManagementTestExecutionListener;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.sql.DataSource;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.List;
import static es.uvigo.esei.daa.dataset.PetsDataset.*;
import static es.uvigo.esei.daa.dataset.UsersDataset.adminLogin;
import static es.uvigo.esei.daa.dataset.UsersDataset.userToken;
import static es.uvigo.esei.daa.matchers.HasHttpStatus.hasOkStatus;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.containsPetsInAnyOrder;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.equalsToPet;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:contexts/mem-context.xml")
@TestExecutionListeners({
DbUnitTestExecutionListener.class,
DbManagementTestExecutionListener.class,
ApplicationContextJndiBindingTestExecutionListener.class
})
@ApplicationContextBinding(
jndiUrl = "java:/comp/env/jdbc/daaexample",
type = DataSource.class
)
@DbManagement(
create = "classpath:db/hsqldb.sql",
drop = "classpath:db/hsqldb-drop.sql"
)
@DatabaseSetup("/datasets/dataset.xml") // Puede variar
@ExpectedDatabase("/datasets/dataset.xml") // Puede variar
public class PetsResourceTest extends JerseyTest {
@Override
protected Application configure() {
return new DAAExampleApplication();
}
@Override
protected void configureClient(ClientConfig config) {
super.configureClient(config);
// Enables JSON transformation in client
config.register(JacksonJsonProvider.class);
config.property("com.sun.jersey.api.json.POJOMappingFeature", Boolean.TRUE);
}
@Test
public void testList() throws IOException {
final Response response = target("pets").request()
.header("Authorization", "Basic " + userToken(adminLogin()))
.get();
assertThat(response, hasOkStatus());
final List<Pet> pets = response.readEntity(new GenericType<List<Pet>>() {
});
assertThat(pets, containsPetsInAnyOrder(pets()));
}
@Test
public void testGet() throws IOException {
final Response response = target("pets/" + existentId()).request()
.header("Authorization", "Basic " + userToken(adminLogin()))
.get();
assertThat(response, hasOkStatus());
final Pet pet = response.readEntity(Pet.class);
assertThat(pet, is(equalsToPet(existentPet())));
}
}
package es.uvigo.esei.daa.rest;
import es.uvigo.esei.daa.dao.DAOException;
import es.uvigo.esei.daa.dao.PetsDAO;
import es.uvigo.esei.daa.entities.Pet;
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.ws.rs.core.Response;
import java.util.List;
import static es.uvigo.esei.daa.dataset.PeopleDataset.existentPerson;
import static es.uvigo.esei.daa.dataset.PeopleDataset.newName;
import static es.uvigo.esei.daa.dataset.PetsDataset.*;
import static es.uvigo.esei.daa.matchers.HasHttpStatus.*;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.containsPetsInAnyOrder;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.equalsToPet;
import static java.util.Arrays.asList;
import static org.easymock.EasyMock.*;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
public class PetsResourceUnitTest {
private PetsDAO daoMock;
private PetsResource resource;
@Before
public void setUp() throws Exception {
daoMock = createMock(PetsDAO.class);
resource = new PetsResource(daoMock);
}
@After
public void tearDown() throws Exception {
try {
verify(daoMock);
} finally {
daoMock = null;
resource = null;
}
}
@Test
public void testGet() throws Exception {
final Pet pet = existentPet();
expect(daoMock.get(pet.getId())).andReturn(pet);
replay(daoMock);
final Response response = resource.get(pet.getId());
assertThat(response, hasOkStatus());
assertThat((Pet) response.getEntity(), is(equalsToPet(pet)));
}
@Test
@SuppressWarnings("unchecked")
public void testList() throws Exception {
final List<Pet> pets = asList(pets());
expect(daoMock.list(existentPerson().getId())).andReturn(pets);
replay(daoMock);
final Response response = resource.list(existentPet().getId());
assertThat(response, hasOkStatus());
assertThat((List<Pet>) response.getEntity(), containsPetsInAnyOrder(pets()));
}
@Test
public void testListDAOException() throws Exception {
expect(daoMock.list(existentPerson().getId())).andThrow(new DAOException());
replay(daoMock);
final Response response = resource.list(existentPerson().getId());
assertThat(response, hasInternalServerErrorStatus());
}
@Test
public void testGetDAOException() throws Exception {
expect(daoMock.get(anyInt())).andThrow(new DAOException());
replay(daoMock);
final Response response = resource.get(existentId());
assertThat(response, hasInternalServerErrorStatus());
}
@Test
public void testGetIllegalArgumentException() throws Exception {
expect(daoMock.get(anyInt())).andThrow(new IllegalArgumentException());
replay(daoMock);
final Response response = resource.get(existentId());
assertThat(response, hasBadRequestStatus());
}
@Test
public void testDelete() throws Exception {
daoMock.delete(anyInt());
replay(daoMock);
final Response response = resource.delete(1);
assertThat(response, hasOkStatus());
}
@Test
public void testDeleteDAOException() throws Exception {
daoMock.delete(anyInt());
expectLastCall().andThrow(new DAOException());
replay(daoMock);
final Response response = resource.delete(1);
assertThat(response, hasInternalServerErrorStatus());
}
@Test
public void testDeleteIllegalArgumentException() throws Exception {
daoMock.delete(anyInt());
expectLastCall().andThrow(new IllegalArgumentException());
replay(daoMock);
final Response response = resource.delete(1);
assertThat(response, hasBadRequestStatus());
}
// @Test
public void testModify() throws Exception {
final Pet pet = existentPet();
pet.setName(newName());
pet.setOwner(newOwner());
daoMock.modify(pet);
replay(daoMock);
final Response response = resource.modify(
pet.getId(), pet.getName(), pet.getOwner());
assertThat(response, hasOkStatus());
assertEquals(pet, response.getEntity());
}
@Test
public void testAdd() throws Exception {
expect(daoMock.add(newName(), newOwner()))
.andReturn(newPet());
replay(daoMock);
final Response response = resource.add(newName(), newOwner());
assertThat(response, hasOkStatus());
assertThat((Pet) response.getEntity(), CoreMatchers.is(equalsToPet(newPet())));
}
@Test
public void testAddDAOException() throws Exception {
expect(daoMock.add(anyString(), anyInt()))
.andThrow(new DAOException());
replay(daoMock);
final Response response = resource.add(newName(), newOwner());
assertThat(response, hasInternalServerErrorStatus());
}
@Test
public void testAddIllegalArgumentException() throws Exception {
expect(daoMock.add(anyString(), anyInt()))
.andThrow(new IllegalArgumentException());
replay(daoMock);
final Response response = resource.add(newName(), newOwner());
assertThat(response, hasBadRequestStatus());
}
}
package es.uvigo.esei.daa.suites; package es.uvigo.esei.daa.suites;
import es.uvigo.esei.daa.rest.PetsResourceUnitTest;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses; import org.junit.runners.Suite.SuiteClasses;
...@@ -11,7 +12,8 @@ import es.uvigo.esei.daa.rest.UsersResourceTest; ...@@ -11,7 +12,8 @@ import es.uvigo.esei.daa.rest.UsersResourceTest;
@SuiteClasses({ @SuiteClasses({
PeopleDAOTest.class, PeopleDAOTest.class,
PeopleResourceTest.class, PeopleResourceTest.class,
UsersResourceTest.class UsersResourceTest.class,
PetsResourceUnitTest.class
}) })
@RunWith(Suite.class) @RunWith(Suite.class)
public class IntegrationTestSuite { public class IntegrationTestSuite {
......
...@@ -14,6 +14,11 @@ ...@@ -14,6 +14,11 @@
<people id="10" name="Juan" surname="Jiménez" /> <people id="10" name="Juan" surname="Jiménez" />
<people id="11" name="John" surname="Doe" /> <people id="11" name="John" surname="Doe" />
<pets id="1" owner="1" name="Tom"/>
<pets id="2" owner="1" name="Jerry"/>
<pets id="3" owner="2" name="Nibbles"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/> <users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" /> <users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset> </dataset>
\ No newline at end of file
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
<people id="9" name="Julia" surname="Justa" /> <people id="9" name="Julia" surname="Justa" />
<people id="10" name="Juan" surname="Jiménez" /> <people id="10" name="Juan" surname="Jiménez" />
<pets id="2" owner="1" name="Jerry"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/> <users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" /> <users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset> </dataset>
\ No newline at end of file
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
<people id="9" name="Julia" surname="Justa" /> <people id="9" name="Julia" surname="Justa" />
<people id="10" name="Juan" surname="Jiménez" /> <people id="10" name="Juan" surname="Jiménez" />
<pets id="1" owner="2" name="Nibbles"/>
<pets id="2" owner="1" name="Jerry"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/> <users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" /> <users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset> </dataset>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT dataset (people*, users*)> <!ELEMENT dataset (people*, users*, pets*)>
<!ELEMENT people EMPTY> <!ELEMENT people EMPTY>
<!ELEMENT users EMPTY> <!ELEMENT users EMPTY>
<!ATTLIST people <!ELEMENT pets EMPTY>
id CDATA #IMPLIED <!ATTLIST people
name CDATA #IMPLIED id CDATA #IMPLIED
surname CDATA #IMPLIED name CDATA #IMPLIED
> surname CDATA #IMPLIED
<!ATTLIST users >
login CDATA #IMPLIED <!ATTLIST pets
password CDATA #IMPLIED id CDATA #IMPLIED
role CDATA #IMPLIED name CDATA #IMPLIED
> owner CDATA #IMPLIED
>
<!ATTLIST users
login CDATA #IMPLIED
password CDATA #IMPLIED
role CDATA #IMPLIED
>
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dataset SYSTEM "dataset.dtd"> <!DOCTYPE dataset SYSTEM "dataset.dtd">
<dataset> <dataset>
<people id="1" name="Antón" surname="Álvarez" /> <people id="1" name="Antón" surname="Álvarez" />
<people id="2" name="Ana" surname="Amargo" /> <people id="2" name="Ana" surname="Amargo" />
...@@ -13,6 +12,10 @@ ...@@ -13,6 +12,10 @@
<people id="9" name="Julia" surname="Justa" /> <people id="9" name="Julia" surname="Justa" />
<people id="10" name="Juan" surname="Jiménez" /> <people id="10" name="Juan" surname="Jiménez" />
<pets id="1" owner="1" name="Tom"/>
<pets id="2" owner="1" name="Jerry"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/> <users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" /> <users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset> </dataset>
\ No newline at end of file
CREATE DATABASE `daaexample`;
CREATE TABLE `daaexample`.`people` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`surname` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `daaexample`.`users` (
`login` varchar(100) NOT NULL,
`password` varchar(64) NOT NULL,
`role` varchar(10) NOT NULL,
PRIMARY KEY (`login`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `daaexample`.`pet` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner` VARCHAR(50) NOT NULL,
`name` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_pet_person` (`owner`),
CONSTRAINT `FK_pet_person` FOREIGN KEY (`owner`) REFERENCES `people` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
GRANT ALL ON `daaexample`.* TO 'daa'@'localhost' IDENTIFIED BY 'daa';
INSERT INTO `daaexample`.`people` (`id`,`name`,`surname`) VALUES (0,'Antón','Pérez');
INSERT INTO `daaexample`.`people` (`id`,`name`,`surname`) VALUES (0,'Manuel','Martínez');
INSERT INTO `daaexample`.`people` (`id`,`name`,`surname`) VALUES (0,'Laura','Reboredo');
INSERT INTO `daaexample`.`people` (`id`,`name`,`surname`) VALUES (0,'Perico','Palotes');
INSERT INTO `daaexample`.`people` (`id`,`name`,`surname`) VALUES (0,'Ana','María');
INSERT INTO `daaexample`.`people` (`id`,`name`,`surname`) VALUES (0,'María','Nuevo');
INSERT INTO `daaexample`.`people` (`id`,`name`,`surname`) VALUES (0,'Alba','Fernández');
INSERT INTO `daaexample`.`people` (`id`,`name`,`surname`) VALUES (0,'Asunción','Jiménez');
-- The password for each user is its login suffixed with "pass". For example, user "admin" has the password "adminpass".
INSERT INTO `daaexample`.`users` (`login`,`password`,`role`)
VALUES ('admin', '713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca','ADMIN');
INSERT INTO `daaexample`.`users` (`login`,`password`,`role`)
VALUES ('normal', '7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83','USER');
INSERT INTO `daaexample`.`pet` (`id`, `owner`, `name`)
VALUES ('1', '1', 'Tom'), ('2', '1', 'Jerry');
CREATE DATABASE `daaexample`;
CREATE TABLE `daaexample`.`people` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`surname` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `daaexample`.`users` (
`login` varchar(100) NOT NULL,
`password` varchar(64) NOT NULL,
`role` varchar(10) NOT NULL,
PRIMARY KEY (`login`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `daaexample`.`pet` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner` int(11) NOT NULL,
`name` VARCHAR (50) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_pet_person` (`owner`),
CONSTRAINT `FK_pet_person` FOREIGN KEY (`owner`) REFERENCES `people` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
GRANT ALL ON `daaexample`.* TO 'daa'@'localhost' IDENTIFIED BY 'daa';