diff --git a/src/main/angular/src/app/app-routing.module.ts b/src/main/angular/src/app/app-routing.module.ts
index 2a71deca534b4cf431058d778ba3f8f2a85ef33d..35154236bd97dd8f759c0b5f579758cdb971fd2c 100644
--- a/src/main/angular/src/app/app-routing.module.ts
+++ b/src/main/angular/src/app/app-routing.module.ts
@@ -23,6 +23,8 @@ import {UnauthenticatedGuard} from './guards/unauthenticated.guard';
import {AuthenticatedGuard} from './guards/authenticated.guard';
import {LoginPanelComponent} from './components/login-panel/login-panel.component';
import {MainPanelComponent} from './components/main-panel/main-panel.component';
+import {PetsFormComponent} from './modules/pets/components/pets-form/pets-form.component';
+
const routes: Routes = [
{
@@ -44,9 +46,29 @@ const routes: Routes = [
{
path: 'people',
loadChildren: () => import('./modules/people/people.module').then(m => m.PeopleModule)
+ },
+ {
+ path: 'listPets/:person',
+ redirectTo: ':person',
+ pathMatch: 'full'
+ },
+ {
+ path: ':person',
+ loadChildren: () => import('./modules/pets/pets.module').then(m => m.PetsModule)
}
]
- }
+ },
+
+
+
+
+
+ /*{
+ path: 'pets/:person',
+ pathMatch: 'full',
+ component: PetsFormComponent,
+ canActivate: [AuthenticatedGuard]
+ }*/
];
@NgModule({
diff --git a/src/main/angular/src/app/app.module.ts b/src/main/angular/src/app/app.module.ts
index aa0b268b3a818b21278022450d8eefe49f07343e..90dfecca79bbc09119943741cd1332661e916a15 100644
--- a/src/main/angular/src/app/app.module.ts
+++ b/src/main/angular/src/app/app.module.ts
@@ -33,7 +33,7 @@ import {AuthenticationInterceptor} from './interceptors/authentication.intercept
declarations: [
AppComponent,
LoginPanelComponent,
- MainPanelComponent
+ MainPanelComponent,
],
imports: [
AppRoutingModule,
diff --git a/src/main/angular/src/app/modules/people/components/people-list/people-list.component.html b/src/main/angular/src/app/modules/people/components/people-list/people-list.component.html
index 2f37f4e3dbefeac56e7eb7be9ed52954e91cfbe2..56e08d267c90d9940b9da7e37628abfad1b85dc2 100644
--- a/src/main/angular/src/app/modules/people/components/people-list/people-list.component.html
+++ b/src/main/angular/src/app/modules/people/components/people-list/people-list.component.html
@@ -32,6 +32,7 @@
+
|
diff --git a/src/main/angular/src/app/modules/people/components/people-list/people-list.component.ts b/src/main/angular/src/app/modules/people/components/people-list/people-list.component.ts
index d63efccab96aac5b3c1c36132ddc30813be4cdf0..1627e66046849b5830ddbd09f39630900734233f 100644
--- a/src/main/angular/src/app/modules/people/components/people-list/people-list.component.ts
+++ b/src/main/angular/src/app/modules/people/components/people-list/people-list.component.ts
@@ -20,6 +20,7 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {PersonModel} from '../../models/person.model';
import {PeopleService} from '../../services/people.service';
+import {Router} from '@angular/router';
@Component({
selector: 'app-people-list',
@@ -36,7 +37,7 @@ export class PeopleListComponent {
@Output()
public readonly delete: EventEmitter;
- public constructor() {
+ public constructor(private readonly router: Router) {
this.edit = new EventEmitter();
this.delete = new EventEmitter();
}
@@ -48,4 +49,8 @@ export class PeopleListComponent {
public onDelete(person: PersonModel) {
this.delete.emit(person);
}
+
+ public pets(person: PersonModel){
+ this.router.navigate(['//listPets',person.id]);
+ }
}
diff --git a/src/main/angular/src/app/modules/pets/components/pets-form/pets-form.component.html b/src/main/angular/src/app/modules/pets/components/pets-form/pets-form.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..c846cb2fb4bf4c67c3647d73d5ef269f6ae78eeb
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/components/pets-form/pets-form.component.html
@@ -0,0 +1,22 @@
+
+
+
diff --git a/src/main/angular/src/app/modules/pets/components/pets-form/pets-form.component.scss b/src/main/angular/src/app/modules/pets/components/pets-form/pets-form.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/main/angular/src/app/modules/pets/components/pets-form/pets-form.component.spec.ts b/src/main/angular/src/app/modules/pets/components/pets-form/pets-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..04c08170b67de8d62c035c6b1cf71647f2a08972
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/components/pets-form/pets-form.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PetsFormComponent } from './pets-form.component';
+
+describe('PetsFormComponent', () => {
+ let component: PetsFormComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ PetsFormComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PetsFormComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/main/angular/src/app/modules/pets/components/pets-form/pets-form.component.ts b/src/main/angular/src/app/modules/pets/components/pets-form/pets-form.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..31f74d1524f097e821a9e319ffd3e3ce785af738
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/components/pets-form/pets-form.component.ts
@@ -0,0 +1,55 @@
+import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import {ActivatedRoute} from '@angular/router';
+import { PetModel } from '../../models/pet.model';
+
+@Component({
+ selector: 'app-pets-form',
+ templateUrl: './pets-form.component.html',
+ styleUrls: ['./pets-form.component.scss']
+})
+export class PetsFormComponent {
+ public activePet: PetModel;
+ @Input()
+ public owner: number;
+
+ @Output()
+ public readonly clean: EventEmitter;
+
+ @Output()
+ public readonly modify: EventEmitter;
+
+ public name: string;
+ public kind: string;
+
+ constructor(
+ private route: ActivatedRoute
+ ) {
+ this.clean = new EventEmitter();
+ this.modify = new EventEmitter();
+ }
+
+ @Input()
+ public set pet(pet: PetModel) {
+ this.activePet = pet;
+ this.name = pet.name;
+ this.kind = pet.kind;
+ }
+
+ public get pet(): PetModel {
+ return this.activePet;
+ }
+
+ public onClean() {
+ this.clean.emit();
+ }
+
+ public onModify() {
+ this.modify.emit({
+ id: this.pet.id,
+ name: this.name,
+ kind: this.kind,
+ owner: this.owner
+ });
+ }
+
+}
diff --git a/src/main/angular/src/app/modules/pets/components/pets-list/pets-list.component.html b/src/main/angular/src/app/modules/pets/components/pets-list/pets-list.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..2159c31dadcceb772fc519296cbce2e2565fd940
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/components/pets-list/pets-list.component.html
@@ -0,0 +1,22 @@
+
+
+
+
+ Nombre |
+ Tipo |
+ |
+
+
+
+
+ {{pet.name}} |
+ {{pet.kind}} |
+
+
+
+ |
+
+
+
+
+
diff --git a/src/main/angular/src/app/modules/pets/components/pets-list/pets-list.component.scss b/src/main/angular/src/app/modules/pets/components/pets-list/pets-list.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/main/angular/src/app/modules/pets/components/pets-list/pets-list.component.spec.ts b/src/main/angular/src/app/modules/pets/components/pets-list/pets-list.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0afdebefd5d38c373e23bab2f691882b351a50c9
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/components/pets-list/pets-list.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PetsListComponent } from './pets-list.component';
+
+describe('PetsListComponent', () => {
+ let component: PetsListComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ PetsListComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PetsListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/main/angular/src/app/modules/pets/components/pets-list/pets-list.component.ts b/src/main/angular/src/app/modules/pets/components/pets-list/pets-list.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ef8d0642c2aca3645a15dec9b268c91f4fde91c4
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/components/pets-list/pets-list.component.ts
@@ -0,0 +1,34 @@
+import { Component, EventEmitter, OnInit, Input, Output } from '@angular/core';
+import { PetModel} from '../../models/pet.model';
+@Component({
+ selector: 'app-pets-list',
+ templateUrl: './pets-list.component.html',
+ styleUrls: ['./pets-list.component.scss']
+})
+export class PetsListComponent {
+
+ @Input()
+ public pets: PetModel[] = [];
+
+ @Output()
+ public readonly delete: EventEmitter;
+
+ @Output()
+ public readonly edit: EventEmitter;
+
+ constructor() {
+ this.delete = new EventEmitter();
+ this.edit = new EventEmitter();
+ }
+
+ public onDelete(pet: PetModel) {
+ this.delete.emit(pet);
+ }
+
+ public onEdit(pet: PetModel) {
+ this.edit.emit(pet);
+ }
+
+
+
+}
diff --git a/src/main/angular/src/app/modules/pets/components/pets-main/pets-main.component.html b/src/main/angular/src/app/modules/pets/components/pets-main/pets-main.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..1896fc4b6fde20a7b8a267172364206a8edab2a2
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/components/pets-main/pets-main.component.html
@@ -0,0 +1,11 @@
+
+Mascotas
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/angular/src/app/modules/pets/components/pets-main/pets-main.component.scss b/src/main/angular/src/app/modules/pets/components/pets-main/pets-main.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/main/angular/src/app/modules/pets/components/pets-main/pets-main.component.spec.ts b/src/main/angular/src/app/modules/pets/components/pets-main/pets-main.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e78e9a9c5741ed3a31c2cf06f1ac8580613b05a7
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/components/pets-main/pets-main.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PetsMainComponent } from './pets-main.component';
+
+describe('PetsMainComponent', () => {
+ let component: PetsMainComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ PetsMainComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PetsMainComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/main/angular/src/app/modules/pets/components/pets-main/pets-main.component.ts b/src/main/angular/src/app/modules/pets/components/pets-main/pets-main.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2fc1acadb24aa005231843da241911f36df0cb26
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/components/pets-main/pets-main.component.ts
@@ -0,0 +1,84 @@
+import { Component, OnInit } from '@angular/core';
+import {PetModel} from '../../models/pet.model';
+import {PetsService} from '../../services/pets.service';
+import {map, mergeMap} from 'rxjs/operators';
+import {ActivatedRoute, Router} from '@angular/router';
+
+
+@Component({
+ selector: 'app-pets-main',
+ templateUrl: './pets-main.component.html',
+ styleUrls: ['./pets-main.component.scss']
+})
+export class PetsMainComponent implements OnInit {
+ public id : number
+ public activePet: PetModel;
+ public pets: PetModel[];
+
+ constructor(
+ private readonly petsService: PetsService,
+ private route: ActivatedRoute,
+ private readonly router: Router
+ ) {
+ this.pets = [];
+ this.clearActivePet()
+ }
+
+ ngOnInit() {
+ this.id = this.route.snapshot.params.person;
+ this.petsService.list(this.id)
+ .subscribe(pets => this.pets = pets);
+
+ }
+
+ public onCleanForm(): void {
+ this.clearActivePet();
+ }
+
+ public clearActivePet():void{
+ this.activePet = { id: undefined, name: '', kind: '', owner: undefined };
+ }
+
+ public back(){
+ this.router.navigate(['/']);
+ }
+
+ public onDelete(pet: PetModel): void {
+ if (confirm(`¿Estás seguro de que deseas eliminar a ${pet.name}?`)) {
+ this.petsService.delete(pet)
+ .pipe(
+ mergeMap(() => this.petsService.list(pet.owner))
+ )
+ .subscribe(pets => this.pets = pets);
+ }
+ }
+
+ public onEdit(pet: PetModel): void {
+ this.activePet = pet;
+ console.log("Noe")
+ console.log(this.activePet)
+ }
+
+ public onModifyForm(pet: PetModel): void {
+ if (pet.id === undefined) {
+ this.petsService.create(pet)
+ .pipe(
+ mergeMap(() => this.petsService.list(pet.owner))
+ )
+ .subscribe(pets => {
+ this.pets = pets;
+ this.clearActivePet();
+ });
+ } else {
+ this.petsService.modify(pet)
+ .pipe(
+ mergeMap(() => this.petsService.list(pet.owner))
+ )
+ .subscribe(pets => {
+ this.pets = pets;
+ this.clearActivePet();
+ });
+ }
+ }
+
+}
diff --git a/src/main/angular/src/app/modules/pets/models/pet.model.ts b/src/main/angular/src/app/modules/pets/models/pet.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..58a954b4e45202521b706e1ee6cc1b2da36c3524
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/models/pet.model.ts
@@ -0,0 +1,7 @@
+export class PetModel {
+ id?: number;
+ name: string;
+ kind: string;
+ owner:number;
+ }
+
\ No newline at end of file
diff --git a/src/main/angular/src/app/modules/pets/pets-routing.module.ts b/src/main/angular/src/app/modules/pets/pets-routing.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..603d72ab783ad5b8116e610a9c3d1f5bfc9f81a1
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/pets-routing.module.ts
@@ -0,0 +1,16 @@
+import {NgModule} from '@angular/core';
+import {RouterModule, Routes} from '@angular/router';
+import {PetsMainComponent} from './components/pets-main/pets-main.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: PetsMainComponent
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class PetsRoutingModule { }
diff --git a/src/main/angular/src/app/modules/pets/pets.module.ts b/src/main/angular/src/app/modules/pets/pets.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e98bd8dbb84834dd2da40ed16efe54a273b776cc
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/pets.module.ts
@@ -0,0 +1,22 @@
+import {NgModule} from '@angular/core';
+import {CommonModule} from '@angular/common';
+
+import {PetsRoutingModule} from './pets-routing.module';
+import {PetsListComponent} from './components/pets-list/pets-list.component';
+import {PetsFormComponent} from './components/pets-form/pets-form.component';
+import {PetsMainComponent} from './components/pets-main/pets-main.component';
+import {FormsModule} from '@angular/forms';
+
+@NgModule({
+ declarations: [
+ PetsFormComponent,
+ PetsListComponent,
+ PetsMainComponent
+ ],
+ imports: [
+ CommonModule,
+ FormsModule,
+ PetsRoutingModule
+ ]
+})
+export class PetsModule { }
diff --git a/src/main/angular/src/app/modules/pets/services/pets.service.spec.ts b/src/main/angular/src/app/modules/pets/services/pets.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b0e426fcd3a47160f1ee796441f605f13c39c6c8
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/services/pets.service.spec.ts
@@ -0,0 +1,12 @@
+import { TestBed } from '@angular/core/testing';
+
+import { PetsService } from './pets.service';
+
+describe('PetsService', () => {
+ beforeEach(() => TestBed.configureTestingModule({}));
+
+ it('should be created', () => {
+ const service: PetsService = TestBed.get(PetsService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/src/main/angular/src/app/modules/pets/services/pets.service.ts b/src/main/angular/src/app/modules/pets/services/pets.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..abc4dd23686e269a169c86194c9fa1e8d200aed3
--- /dev/null
+++ b/src/main/angular/src/app/modules/pets/services/pets.service.ts
@@ -0,0 +1,41 @@
+import { Injectable } from '@angular/core';
+import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
+import {environment} from '../../../../environments/environment';
+import {Observable} from 'rxjs';
+import {PetModel} from '../models/pet.model';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class PetsService {
+
+ constructor(private readonly http: HttpClient) { }
+
+
+
+ public list(id: number): Observable{
+ return this.http.get(`${environment.restApi}/pets?owner=${id}`);
+ }
+
+ public delete(pet: PetModel): Observable {
+ return this.http.delete(`${environment.restApi}/pets/${pet.id}`);
+ }
+
+ public modify(pet: PetModel): Observable {
+ const data = new HttpParams()
+ .set('name', pet.name)
+ .set('kind', pet.kind)
+ .set('owner', pet.owner.toString());
+
+ return this.http.put(`${environment.restApi}/pets/${pet.id}`, data);
+ }
+
+ public create(pet: PetModel): Observable {
+ const data = new HttpParams()
+ .set('name', pet.name)
+ .set('kind', pet.kind)
+ .set('owner', pet.owner.toString());
+
+ return this.http.post(`${environment.restApi}/pets`, data);
+ }
+}
diff --git a/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java b/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java
index 2a67f22f93bf402148426fd8becb0ce7c8f37dfc..2f3a5c0439740d2d340628ab5063fc3b7224fce2 100644
--- a/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java
+++ b/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java
@@ -12,6 +12,7 @@ import javax.ws.rs.core.Application;
import es.uvigo.esei.daa.rest.PeopleResource;
import es.uvigo.esei.daa.rest.UsersResource;
+import es.uvigo.esei.daa.rest.PetsResource;
/**
* Configuration of the REST application. This class includes the resources and
@@ -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/PetsDAO.java b/src/main/java/es/uvigo/esei/daa/dao/PetsDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..95ac5233f69e4021043192d80c8e47920132b02d
--- /dev/null
+++ b/src/main/java/es/uvigo/esei/daa/dao/PetsDAO.java
@@ -0,0 +1,172 @@
+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 javax.sound.sampled.SourceDataLine;
+
+import es.uvigo.esei.daa.entities.Pet;
+
+/**
+ * DAO class for the {@link Pets} entities.
+ *
+ * @author Noelia García Hervella
+ *
+ */
+public class PetsDAO extends DAO {
+ private final static Logger LOG = Logger.getLogger(PetsDAO.class.getName());
+
+
+ /**
+ * 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(int id) throws DAOException {
+ try (final Connection conn = this.getConnection()) {
+ final String query = "SELECT * FROM pets where owner=?";
+
+ 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 listing pets", e);
+ throw new DAOException(e);
+ }
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * 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 kind surname of the new pet. Can't be {@code null}.
+ * @param owner id of the new owner. 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 or surname are {@code null}.
+ */
+ public Pet add(String name, String kind, String owner)
+ throws DAOException, IllegalArgumentException {
+ if (name == null || kind == null || owner == null ) {
+ throw new IllegalArgumentException("name, kind and owner can't be null");
+ }
+
+ 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, kind);
+ statement.setString(3, owner);
+
+ if (statement.executeUpdate() == 1) {
+ try (ResultSet resultKeys = statement.getGeneratedKeys()) {
+ if (resultKeys.next()) {
+ return new Pet(resultKeys.getInt(1), name, kind, Integer.parseInt(owner));
+ } 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 and surname 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=?, kind=? WHERE id=?";
+
+ try (PreparedStatement statement = conn.prepareStatement(query)) {
+ statement.setString(1, pet.getName());
+ statement.setString(2, pet.getKind());
+ statement.setInt(3, pet.getId());
+
+ if (statement.executeUpdate() != 1) {
+ throw new IllegalArgumentException("name and surname can't be null");
+ }
+ }
+ } catch (SQLException e) {
+ LOG.log(Level.SEVERE, "Error modifying a pet", e);
+ throw new DAOException();
+ }
+ }
+
+
+
+
+
+ private Pet rowToEntity(ResultSet row) throws SQLException {
+ return new Pet(
+ row.getInt("id"),
+ row.getString("name"),
+ row.getString("kind"),
+ row.getInt("owner")
+ );
+
+ }
+}
diff --git a/src/main/java/es/uvigo/esei/daa/entities/Pet.java b/src/main/java/es/uvigo/esei/daa/entities/Pet.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc282ba5f5dfe3b1198ebc28099c5e0497269ef4
--- /dev/null
+++ b/src/main/java/es/uvigo/esei/daa/entities/Pet.java
@@ -0,0 +1,121 @@
+package es.uvigo.esei.daa.entities;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * An entity that represents a pet.
+ *
+ * @author Noelia García Hervella
+ */
+public class Pet {
+ private int id;
+ private String name;
+ private String kind;
+ private int owner;
+
+ // Constructor needed for the JSON conversion
+ Pet() {}
+
+ /**
+ * Constructs a new instance of {@link Pet}.
+ *
+ * @param id identifier of the pet.
+ * @param name name of the pet.
+ * @param surname surname of the pet.
+ */
+ public Pet(int id, String name, String kind, int owner) {
+ this.id = id;
+ this.setName(name);
+ this.setKind(kind);
+ this.setOwner(owner);
+ }
+
+ /**
+ * Returns the identifier of the pet.
+ *
+ * @return the identifier of the pet.
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Returns the name of the pet.
+ *
+ * @return the name of the pet.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set the name of this pet.
+ *
+ * @param name the new name of the pet.
+ * @throws NullPointerException if the {@code name} is {@code null}.
+ */
+ public void setName(String name) {
+ this.name = requireNonNull(name, "Name can't be null");
+ }
+
+ /**
+ * Returns the surname of the pet.
+ *
+ * @return the surname of the pet.
+ */
+ public String getKind() {
+ return kind;
+ }
+
+ /**
+ * Set the surname of this pet.
+ *
+ * @param surname the new surname of the pet.
+ * @throws NullPointerException if the {@code surname} is {@code null}.
+ */
+ public void setKind(String surname) {
+ this.kind = requireNonNull(surname, "Kind can't be null");
+ }
+
+
+ /**
+ * Returns the id of the owner.
+ *
+ * @return the id of the owner.
+ */
+ public int getOwner() {
+ return owner;
+ }
+
+ /**
+ * Set the id of this owner.
+ *
+ * @param owner the new id of the owner.
+ * @throws NullPointerException if the {@code surname} is {@code null}.
+ */
+ public void setOwner(int owner) {
+ this.owner = requireNonNull(owner, "The owner' id can't be null");
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + id;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof Pet))
+ return false;
+ Pet other = (Pet) obj;
+ if (id != other.id)
+ return false;
+ return true;
+ }
+}
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..b05221f7bf4154165fa82b41977f8ece8f4bf8c6
--- /dev/null
+++ b/src/main/java/es/uvigo/esei/daa/rest/PetsResource.java
@@ -0,0 +1,189 @@
+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.PetsDAO;
+import es.uvigo.esei.daa.entities.Pet;
+
+/**
+ * REST resource for managing pets.
+ *
+ * @author Noelia García Hervella
+ */
+@Path("/pets")
+@Produces(MediaType.APPLICATION_JSON)
+public class PetsResource {
+ private final static Logger LOG = Logger.getLogger(PetsResource.class.getName());
+
+ private final PetsDAO dao;
+
+ /**
+ * Constructs a new instance of {@link PetsResource}.
+ */
+ public PetsResource() {
+ this(new PetsDAO());
+ }
+
+ // Needed for testing purposes
+ PetsResource(PetsDAO dao) {
+ this.dao = dao;
+ }
+
+ /**
+ * 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("owner") int id
+ ) {
+
+ try {
+ return Response.ok(this.dao.list(id)).build();
+ } catch (DAOException e) {
+ LOG.log(Level.SEVERE, "Error listing pets", 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 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.
+ */
+ @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();
+ }
+ }
+
+ /**
+ * Creates a new pet in the system.
+ *
+ * @param name the name of the new pet.
+ * @param surname the surname of the new pet.
+ * @return a 200 OK response with a pet that has been created. If the
+ * name or the 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.
+ */
+
+ @POST
+ public Response add(
+ @FormParam("name") String name,
+ @FormParam("kind") String kind,
+ @FormParam("owner") String owner
+ ) {
+ try {
+ final Pet newPet = this.dao.add(name, kind, 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();
+ }
+ }
+
+ /**
+ * Modifies the data of a pet.
+ *
+ * @param id identifier of the pet to modify.
+ * @param name the new name of the pet.
+ * @param surname the new surname of the pet.
+ * @param owner identifier of the owner.
+ * @return a 200 OK response with a pet 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("kind") String kind,
+ @FormParam("owner") String owner
+ ) {
+ try {
+ final Pet modifiedPet = new Pet(id, name, kind, Integer.parseInt(owner));
+ this.dao.modify(modifiedPet);
+
+ return Response.ok(modifiedPet).build();
+ } catch (NullPointerException npe) {
+ final String message = String.format("Invalid data for pet (name: %s, KIND: %s)", name, kind);
+
+ 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();
+ }
+ }
+
+
+
+}
diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
index b2b892cf60e8d4db82b89eb130fcf0b309df34eb..fd750c14c0ef57b1edb326429a7a850a27f71e76 100644
--- a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
+++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
@@ -1,5 +1,8 @@
es\uvigo\esei\daa\rest\PeopleResource.class
es\uvigo\esei\daa\dao\PeopleDAO.class
+es\uvigo\esei\daa\rest\PetsResource.class
+es\uvigo\esei\daa\dao\PetsDAO.class
+es\uvigo\esei\daa\entities\Pet.class
es\uvigo\esei\daa\entities\User.class
es\uvigo\esei\daa\dao\UsersDAO.class
es\uvigo\esei\daa\dao\DAOException.class