From 664d7a8f634267d183c73a8015a975e7280b72b1 Mon Sep 17 00:00:00 2001 From: Fernando Bellas Permuy Date: Thu, 11 Feb 2010 20:44:14 +0100 Subject: [PATCH] ItEr47S12CUImportacionRecursosProductivosItEr46S13: Added updating functionality to ResourceServiceREST Updating functionality has been added to ResourceServiceREST. All data associated to a resource can be updated with the exception of the calendar field, since the updating semantics are only clearly defined for such field at this moment (what happens with the previous derived calendar: modified?, removed?, disabled?). As part of this patch, some improvements to CriterionServiceREST implementation have also been made. In particular, updateUnvalidated methods has been added to related entities (as in ResourceServiceREST). Unlike createUnvalidated methods, such methods are used for updating, and like createUnvalidated methods, non-valid fields are allowed. Finally, performance of GenericRESTService has been improved. Previously, validations were executed twice for each entity being imported due to previous limitations of IGenericDAO interface. Now, a new method has been added to IGenericDAO to make possible to execute validations only one time for each entity being imported. --- .../common/daos/GenericDAOHibernate.java | 4 + .../business/common/daos/IGenericDAO.java | 5 + .../ResourcesCostCategoryAssignment.java | 21 ++ .../resources/entities/Criterion.java | 13 ++ .../entities/CriterionSatisfaction.java | 38 ++++ .../resources/entities/CriterionType.java | 31 +++ .../business/resources/entities/Machine.java | 13 ++ .../business/resources/entities/Resource.java | 51 ++++- .../business/resources/entities/Worker.java | 16 ++ .../ws/common/impl/GenericRESTService.java | 17 +- .../criterion/impl/CriterionConverter.java | 59 +---- .../ws/resources/impl/ResourceConverter.java | 202 ++++++++++++++++-- .../resources/impl/ResourceServiceREST.java | 12 +- .../ws/resources/api/ResourceServiceTest.java | 132 ++++++++++++ scripts/rest-clients/README | 3 + scripts/rest-clients/resources-sample.xml | 2 +- .../rest-clients/resources-update-sample.xml | 46 ++++ 17 files changed, 580 insertions(+), 85 deletions(-) create mode 100644 scripts/rest-clients/resources-update-sample.xml diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/GenericDAOHibernate.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/GenericDAOHibernate.java index f6261e2b7..8a2bbd0c6 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/GenericDAOHibernate.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/GenericDAOHibernate.java @@ -94,6 +94,10 @@ public class GenericDAOHibernate{ */ public void save(E entity) throws ValidationException; + /** + * Unlike save, it does not execute validations. + */ + public void saveWithoutValidating(E entity); + /** * It reattaches the entity to the current session. This method bypasses * hibernate validations and must only be used on read only transaction diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/costcategories/entities/ResourcesCostCategoryAssignment.java b/navalplanner-business/src/main/java/org/navalplanner/business/costcategories/entities/ResourcesCostCategoryAssignment.java index d4915c320..19fc377e9 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/costcategories/entities/ResourcesCostCategoryAssignment.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/costcategories/entities/ResourcesCostCategoryAssignment.java @@ -77,6 +77,27 @@ public class ResourcesCostCategoryAssignment extends IntegrationEntity { } + /** + * @throws InstanceNotFoundException if cost category does not exist + */ + public void updateUnvalidated(String costCategoryName, LocalDate initDate, + LocalDate endDate) throws InstanceNotFoundException { + + if (!StringUtils.isBlank(costCategoryName)) { + this.costCategory = Registry.getCostCategoryDAO(). + findUniqueByName(costCategoryName); + } + + if (initDate != null) { + this.initDate = initDate; + } + + if (endDate != null) { + this.endDate = endDate; + } + + } + @NotNull(message="cost assignment's start date not specified") public LocalDate getInitDate() { return initDate; diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Criterion.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Criterion.java index 7bf9f53a0..bdb16b9de 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Criterion.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Criterion.java @@ -26,6 +26,7 @@ import java.util.Date; import java.util.HashSet; import java.util.Set; +import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.apache.commons.lang.builder.EqualsBuilder; import org.hibernate.validator.AssertTrue; @@ -61,6 +62,18 @@ public class Criterion extends IntegrationEntity implements ICriterion { } + public void updateUnvalidated(String name, Boolean active) { + + if (!StringUtils.isBlank(name)) { + this.name = name; + } + + if (active != null) { + this.active = active; + } + + } + public static Criterion create(CriterionType type) { return create(new Criterion(type)); } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionSatisfaction.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionSatisfaction.java index eb61f0efb..bdd376839 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionSatisfaction.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionSatisfaction.java @@ -23,6 +23,7 @@ package org.navalplanner.business.resources.entities; import java.util.Comparator; import java.util.Date; +import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.apache.commons.lang.builder.ToStringBuilder; import org.hibernate.validator.AssertTrue; @@ -104,6 +105,43 @@ public class CriterionSatisfaction extends IntegrationEntity { } + /** + * @throws InstanceNotFoundException if criterion type or criterion does + * not exist + */ + public void updateUnvalidated(String criterionTypeName, + String criterionName, Date startDate, Date finishDate) + throws InstanceNotFoundException { + + CriterionType criterionType = null; + + if (StringUtils.isBlank(criterionTypeName)) { + criterionType = criterion.getType(); + } else { + criterionType = Registry.getCriterionTypeDAO().findUniqueByName( + criterionTypeName); + } + + String newCriterionName = null; + + if (StringUtils.isBlank(criterionName)) { + newCriterionName = StringUtils.trim(criterion.getName()); + } else { + newCriterionName = criterionName; + } + + this.criterion = criterionType.getCriterion(newCriterionName); + + if (startDate != null) { + this.startDate = startDate; + } + + if (finishDate != null) { + this.finishDate = finishDate; + } + + } + /** * Constructor for hibernate. Do not use! */ diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java index 5cd7e2346..2c68da68f 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java @@ -80,6 +80,37 @@ public class CriterionType extends IntegrationEntity implements } + public void updateUnvalidated(String name, String description, + Boolean allowHierarchy, Boolean allowSimultaneousCriterionsPerResource, + Boolean enabled, ResourceEnum resource) { + + if (!StringUtils.isBlank(name)) { + this.name = name; + } + + if (!StringUtils.isBlank(description)) { + this.description = description; + } + + if (allowHierarchy != null) { + this.allowHierarchy = allowHierarchy; + } + + if (allowSimultaneousCriterionsPerResource != null) { + this.allowSimultaneousCriterionsPerResource = + allowSimultaneousCriterionsPerResource; + } + + if (enabled != null) { + this.enabled = enabled; + } + + if (resource != null) { + this.resource = resource; + } + + } + public static CriterionType create(String name,String description) { return create(new CriterionType(name,description)); } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Machine.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Machine.java index 7509154c0..68e7720b6 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Machine.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Machine.java @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; +import org.apache.commons.lang.StringUtils; import org.hibernate.validator.NotEmpty; import org.hibernate.validator.Valid; @@ -69,6 +70,18 @@ public class Machine extends Resource { } + public void updateUnvalidated(String name, String description) { + + if (!StringUtils.isBlank(name)) { + this.name = name; + } + + if (!StringUtils.isBlank(description)) { + this.description = description; + } + + } + /** * Used by Hibernate. Do not use! */ diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java index 1b55943d1..e30b2b68c 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java @@ -118,6 +118,25 @@ public abstract class Resource extends IntegrationEntity { return satisfactionActives; } + public CriterionSatisfaction getCriterionSatisfactionByCode(String code) + throws InstanceNotFoundException { + + if (StringUtils.isBlank(code)) { + throw new InstanceNotFoundException(code, + CriterionSatisfaction.class.getName()); + } + + for (CriterionSatisfaction i : criterionSatisfactions) { + if (i.getCode().equalsIgnoreCase(StringUtils.trim(code))) { + return i; + } + } + + throw new InstanceNotFoundException(code, + CriterionSatisfaction.class.getName()); + + } + public abstract String getShortDescription(); public abstract String getName(); @@ -699,7 +718,7 @@ public abstract class Resource extends IntegrationEntity { } else { List baseCalendars = Registry.getBaseCalendarDAO(). - findByName(StringUtils.trim(calendarName)); + findByName(calendarName); if (baseCalendars.isEmpty()) { throw new InstanceNotFoundException(calendarName, @@ -832,12 +851,42 @@ public abstract class Resource extends IntegrationEntity { return resourcesCostCategoryAssignments; } + public ResourcesCostCategoryAssignment + getResourcesCostCategoryAssignmentByCode(String code) + throws InstanceNotFoundException { + + if (StringUtils.isBlank(code)) { + throw new InstanceNotFoundException(code, + ResourcesCostCategoryAssignment.class.getName()); + } + + for (ResourcesCostCategoryAssignment i : + resourcesCostCategoryAssignments) { + + if (i.getCode().equalsIgnoreCase(StringUtils.trim(code))) { + return i; + } + + } + + throw new InstanceNotFoundException(code, + ResourcesCostCategoryAssignment.class.getName()); + + } + public void addResourcesCostCategoryAssignment(ResourcesCostCategoryAssignment assignment) { resourcesCostCategoryAssignments.add(assignment); if(assignment.getResource()!=this) assignment.setResource(this); } + public void addUnvalidatedResourcesCostCategoryAssignment( + ResourcesCostCategoryAssignment assignment) { + + resourcesCostCategoryAssignments.add(assignment); + + } + public void removeResourcesCostCategoryAssignment(ResourcesCostCategoryAssignment assignment) { resourcesCostCategoryAssignments.remove(assignment); if(assignment.getResource()==this) diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Worker.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Worker.java index b5103ef92..bab974938 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Worker.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Worker.java @@ -59,6 +59,22 @@ public class Worker extends Resource { } + public void updateUnvalidated(String firstName, String surname, String nif) { + + if (!StringUtils.isBlank(firstName)) { + this.firstName = firstName; + } + + if (!StringUtils.isBlank(surname)) { + this.surname = surname; + } + + if (!StringUtils.isBlank(nif)) { + this.nif = nif; + } + + } + private String firstName; private String surname; diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/GenericRESTService.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/GenericRESTService.java index 1837c772b..9247d079d 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/GenericRESTService.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/GenericRESTService.java @@ -134,23 +134,10 @@ public abstract class GenericRESTService criterionWrappers = @@ -132,7 +132,9 @@ public final class CriterionConverter { try { Criterion criterion = criterionType.getCriterionByCode( criterionWrapper.dto.code); - updateCriterionBasicProperties(criterion, criterionWrapper.dto); + criterion.updateUnvalidated( + StringUtils.trim(criterionWrapper.dto.name), + criterionWrapper.dto.active); } catch (InstanceNotFoundException e) { criterionType.getCriterions().add(toEntityWithoutChildren( criterionWrapper.dto, criterionType, null)); @@ -158,7 +160,13 @@ public final class CriterionConverter { /* 4: Update criterion type basic properties. */ - updateCriterionTypeBasicProperties(criterionType, criterionTypeDTO); + criterionType.updateUnvalidated( + StringUtils.trim(criterionTypeDTO.name), + StringUtils.trim(criterionTypeDTO.description), + criterionTypeDTO.allowHierarchy, + criterionTypeDTO.allowSimultaneousCriterionsPerResource, + criterionTypeDTO.enabled, + ResourceEnumConverter.fromDTO(criterionTypeDTO.resource)); } @@ -208,49 +216,4 @@ public final class CriterionConverter { } - private static void updateCriterionTypeBasicProperties( - CriterionType criterionType, CriterionTypeDTO criterionTypeDTO) { - - if (!StringUtils.isBlank(criterionTypeDTO.name)) { - criterionType.setName(StringUtils.trim(criterionTypeDTO.name)); - } - - if (!StringUtils.isBlank(criterionTypeDTO.description)) { - criterionType.setDescription( - StringUtils.trim(criterionTypeDTO.description)); - } - - if (criterionTypeDTO.allowHierarchy != null) { - criterionType.setAllowHierarchy(criterionTypeDTO.allowHierarchy); - } - - if (criterionTypeDTO.allowSimultaneousCriterionsPerResource != null) { - criterionType.setAllowSimultaneousCriterionsPerResource( - criterionTypeDTO.allowSimultaneousCriterionsPerResource); - } - - if (criterionTypeDTO.enabled != null) { - criterionType.setEnabled(criterionTypeDTO.enabled); - } - - if (criterionTypeDTO.resource != null) { - criterionType.setResource( - ResourceEnumConverter.fromDTO(criterionTypeDTO.resource)); - } - - } - - private static void updateCriterionBasicProperties(Criterion criterion, - CriterionDTO criterionDTO) { - - if (!StringUtils.isBlank(criterionDTO.name)) { - criterion.setName(StringUtils.trim(criterionDTO.name)); - } - - if (criterionDTO.active != null) { - criterion.setActive(criterionDTO.active); - } - - } - } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/impl/ResourceConverter.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/impl/ResourceConverter.java index 12ce3a7bb..a3c8a9ed9 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/impl/ResourceConverter.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/impl/ResourceConverter.java @@ -36,6 +36,7 @@ import org.navalplanner.business.resources.entities.Resource; import org.navalplanner.business.resources.entities.Worker; import org.navalplanner.ws.common.impl.DateConverter; import org.navalplanner.ws.common.impl.InstanceNotFoundRecoverableErrorException; +import org.navalplanner.ws.common.impl.RecoverableErrorException; import org.navalplanner.ws.resources.api.CriterionSatisfactionDTO; import org.navalplanner.ws.resources.api.MachineDTO; import org.navalplanner.ws.resources.api.ResourceDTO; @@ -51,20 +52,27 @@ import org.navalplanner.ws.resources.criterion.api.CriterionTypeDTO; */ public class ResourceConverter { + /* + * These constants should probably be moved to XxxDTO.ENTITY_TYPE + * if the corresponding DTOs are created in the future. + */ + private final static String RESOURCE_CALENDAR_ENTITY_TYPE = + "resource-calendar"; + private final static String COST_CATEGORY_ENTITY_TYPE = "cost-category"; + private ResourceConverter() {} - public final static Resource toEntity(ResourceDTO resourceDTO) { + public final static Resource toEntity(ResourceDTO resourceDTO) + throws ValidationException, RecoverableErrorException { + + checkResourceDTOType(resourceDTO); Resource resource; if (resourceDTO instanceof MachineDTO) { resource = createResourceWithBasicData((MachineDTO) resourceDTO); - } else if (resourceDTO instanceof WorkerDTO) { - resource = createResourceWithBasicData((WorkerDTO) resourceDTO); } else { - throw new RuntimeException( - _("Service does not manage resource of type: {0}", - resourceDTO.getClass().getName())); + resource = createResourceWithBasicData((WorkerDTO) resourceDTO); } addCriterionSatisfactions(resource, @@ -77,6 +85,24 @@ public class ResourceConverter { } + public final static void updateResource(Resource resource, + ResourceDTO resourceDTO) + throws ValidationException, RecoverableErrorException { + + checkResourceDTOType(resourceDTO); + + updateBasicData(resource, resourceDTO); + + updateResourceCalendar(resource, resourceDTO.calendarName); + + updateCriterionSatisfactions(resource, + resourceDTO.criterionSatisfactions); + + updateResourcesCostCategoryAssignments(resource, + resourceDTO.resourcesCostCategoryAssignments); + + } + private final static Machine createResourceWithBasicData( MachineDTO machineDTO) { @@ -154,13 +180,10 @@ public class ResourceConverter { String calendarName) { try { - resource.setResourceCalendar(calendarName); + resource.setResourceCalendar(StringUtils.trim(calendarName)); } catch (InstanceNotFoundException e) { throw new InstanceNotFoundRecoverableErrorException( - "resource-calendar", e.getKey().toString()); - // TODO: literal "resource-calendar" should possibly be - // replaced by ResourceCalendarDTO.ENTITY_TYPE if - // ResourceCalendarDTO is created in the future. + RESOURCE_CALENDAR_ENTITY_TYPE, e.getKey().toString()); } catch (MultipleInstancesException e) { throw new ValidationException( _("there exist multiple resource calendars with name {0}", @@ -178,7 +201,7 @@ public class ResourceConverter { ResourcesCostCategoryAssignment assignment = toEntity(assignmentDTO, resource); - resource.addResourcesCostCategoryAssignment(assignment); + resource.addUnvalidatedResourcesCostCategoryAssignment(assignment); } @@ -194,15 +217,160 @@ public class ResourceConverter { try { return ResourcesCostCategoryAssignment.createUnvalidated( - assignmentDTO.code, assignmentDTO.costCategoryName, resource, + assignmentDTO.code, + StringUtils.trim(assignmentDTO.costCategoryName), resource, DateConverter.toLocalDate(assignmentDTO.startDate), DateConverter.toLocalDate(assignmentDTO.endDate)); } catch (InstanceNotFoundException e) { throw new InstanceNotFoundRecoverableErrorException( - "cost-category", e.getKey().toString()); - // TODO: literal "cost-category" should possibly be replaced by - // CostCategoryDTO.ENTITY_TYPE if CostCategoryDTO is created in the - // future. + COST_CATEGORY_ENTITY_TYPE, e.getKey().toString()); + } + + } + + private static void updateBasicData(Resource resource, + ResourceDTO resourceDTO) { + + if (resource instanceof Machine && resourceDTO instanceof MachineDTO) { + + Machine machine = (Machine) resource; + MachineDTO machineDTO = (MachineDTO) resourceDTO; + + machine.updateUnvalidated( + StringUtils.trim(machineDTO.name), + StringUtils.trim(machineDTO.description)); + + } else if (resource instanceof Worker && + resourceDTO instanceof WorkerDTO) { + + Worker worker = (Worker) resource; + WorkerDTO workerDTO = (WorkerDTO) resourceDTO; + + worker.updateUnvalidated( + StringUtils.trim(workerDTO.firstName), + StringUtils.trim(workerDTO.surname), + StringUtils.trim(workerDTO.nif)); + + } else { + + throw new ValidationException( + _("Incompatible update: stored resource is not of type: {0}", + resourceDTO.getEntityType())); + } + + } + + + private static void updateResourceCalendar(Resource resource, + String calendarName) { + + // TODO. Decide policy to update calendar (e.g. previous calendar must + // be removed?, if new calendar is the same as previous, must be + // reinitialized again?, etc.) + + } + + private static void updateCriterionSatisfactions(Resource resource, + List criterionSatisfactions) { + + for (CriterionSatisfactionDTO i : criterionSatisfactions) { + + try { + + CriterionSatisfaction criterionSatisfaction = + resource.getCriterionSatisfactionByCode(i.code); + updateCriterionSatisfaction(criterionSatisfaction, i); + + } catch (InstanceNotFoundException e) { + + CriterionSatisfaction criterionSatisfaction = + toEntity(i, resource); + + resource.addUnvalidatedSatisfaction(criterionSatisfaction); + } + + } + + } + + private static void updateCriterionSatisfaction( + CriterionSatisfaction criterionSatisfaction, + CriterionSatisfactionDTO criterionSatisfactionDTO) { + + try { + + criterionSatisfaction.updateUnvalidated( + StringUtils.trim(criterionSatisfactionDTO.criterionTypeName), + StringUtils.trim(criterionSatisfactionDTO.criterionName), + DateConverter.toDate(criterionSatisfactionDTO.startDate), + DateConverter.toDate(criterionSatisfactionDTO.endDate)); + + } catch (InstanceNotFoundException e) { + + if (e.getClassName().equals(CriterionType.class.getName())) { + throw new InstanceNotFoundRecoverableErrorException( + CriterionTypeDTO.ENTITY_TYPE, e.getKey().toString()); + } else { + throw new InstanceNotFoundRecoverableErrorException( + CriterionDTO.ENTITY_TYPE, e.getKey().toString()); + } + + } + + } + + private static void updateResourcesCostCategoryAssignments( + Resource resource, + List resourcesCostCategoryAssignments) { + + for (ResourcesCostCategoryAssignmentDTO i : + resourcesCostCategoryAssignments) { + + try { + + ResourcesCostCategoryAssignment assignment = + resource.getResourcesCostCategoryAssignmentByCode(i.code); + updateResourcesCostCategoryAssignment(assignment, i); + + } catch (InstanceNotFoundException e) { + + ResourcesCostCategoryAssignment assignment = + toEntity(i, resource); + + resource.addUnvalidatedResourcesCostCategoryAssignment( + assignment); + + } + + } + + } + + private static void updateResourcesCostCategoryAssignment( + ResourcesCostCategoryAssignment assignment, + ResourcesCostCategoryAssignmentDTO i) { + + try { + assignment.updateUnvalidated( + StringUtils.trim(i.costCategoryName), + DateConverter.toLocalDate(i.startDate), + DateConverter.toLocalDate(i.endDate)); + } catch (InstanceNotFoundException e) { + throw new InstanceNotFoundRecoverableErrorException( + COST_CATEGORY_ENTITY_TYPE, e.getKey().toString()); + } + + } + + private static void checkResourceDTOType(ResourceDTO resourceDTO) { + + if (!(resourceDTO instanceof MachineDTO) && + !(resourceDTO instanceof WorkerDTO)) { + + throw new ValidationException( + _("Service does not manage resource of type: {0}", + resourceDTO.getEntityType())); + } } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/impl/ResourceServiceREST.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/impl/ResourceServiceREST.java index 2382ae3be..c5caccdbc 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/impl/ResourceServiceREST.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/impl/ResourceServiceREST.java @@ -31,6 +31,7 @@ import org.navalplanner.business.resources.daos.IResourceDAO; import org.navalplanner.business.resources.entities.Resource; import org.navalplanner.ws.common.api.InstanceConstraintViolationsListDTO; import org.navalplanner.ws.common.impl.GenericRESTService; +import org.navalplanner.ws.common.impl.RecoverableErrorException; import org.navalplanner.ws.resources.api.IResourceService; import org.navalplanner.ws.resources.api.ResourceDTO; import org.navalplanner.ws.resources.api.ResourceListDTO; @@ -63,8 +64,11 @@ public class ResourceServiceREST } @Override - protected Resource toEntity(ResourceDTO entityDTO) { + protected Resource toEntity(ResourceDTO entityDTO) + throws ValidationException, RecoverableErrorException { + return ResourceConverter.toEntity(entityDTO); + } @Override @@ -79,8 +83,10 @@ public class ResourceServiceREST @Override protected void updateEntity(Resource entity, ResourceDTO entityDTO) - throws ValidationException { - // FIXME: updated functionality not implemented yet. + throws ValidationException, RecoverableErrorException { + + ResourceConverter.updateResource(entity, entityDTO); + } } diff --git a/navalplanner-webapp/src/test/java/org/navalplanner/web/test/ws/resources/api/ResourceServiceTest.java b/navalplanner-webapp/src/test/java/org/navalplanner/web/test/ws/resources/api/ResourceServiceTest.java index 59bad2ac4..cc8c2cd8f 100644 --- a/navalplanner-webapp/src/test/java/org/navalplanner/web/test/ws/resources/api/ResourceServiceTest.java +++ b/navalplanner-webapp/src/test/java/org/navalplanner/web/test/ws/resources/api/ResourceServiceTest.java @@ -34,6 +34,9 @@ import static org.navalplanner.web.test.ws.common.Util.assertOneRecoverableError import static org.navalplanner.web.test.ws.common.Util.getUniqueName; import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; import java.util.List; import javax.xml.datatype.DatatypeConfigurationException; @@ -41,6 +44,7 @@ import javax.xml.datatype.DatatypeConstants; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; +import org.joda.time.LocalDate; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,11 +54,13 @@ import org.navalplanner.business.common.IAdHocTransactionService; import org.navalplanner.business.common.IOnTransaction; import org.navalplanner.business.common.daos.IConfigurationDAO; import org.navalplanner.business.common.entities.IConfigurationBootstrap; +import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.costcategories.daos.ICostCategoryDAO; import org.navalplanner.business.costcategories.entities.CostCategory; import org.navalplanner.business.resources.daos.ICriterionTypeDAO; import org.navalplanner.business.resources.daos.IMachineDAO; import org.navalplanner.business.resources.daos.IResourceDAO; +import org.navalplanner.business.resources.daos.IWorkerDAO; import org.navalplanner.business.resources.entities.Criterion; import org.navalplanner.business.resources.entities.CriterionSatisfaction; import org.navalplanner.business.resources.entities.CriterionType; @@ -95,6 +101,9 @@ public class ResourceServiceTest { @Autowired private IMachineDAO machineDAO; + @Autowired + private IWorkerDAO workerDAO; + @Autowired private ICriterionTypeDAO criterionTypeDAO; @@ -720,6 +729,100 @@ public class ResourceServiceTest { } + @Test + public void testUpdateResources() throws InstanceNotFoundException { + + /* Create a criterion type and a cost category. */ + CriterionType ct = createCriterionType(); + CostCategory costCategory = createCostCategory(); + + /* Create a machine DTO. */ + MachineDTO m1 = new MachineDTO("name", "desc"); + CriterionSatisfactionDTO m1s1 = new CriterionSatisfactionDTO( + ct.getName(), "c1", getDate(2000, 1, 1), getDate(2000, 2, 1)); + m1.criterionSatisfactions.add(m1s1); + ResourcesCostCategoryAssignmentDTO m1a1 = + new ResourcesCostCategoryAssignmentDTO(costCategory.getName(), + getDate(2000, 1, 1), getDate(2000, 2, 1)); + m1.resourcesCostCategoryAssignments.add(m1a1); + + /* Create a worker DTO. */ + WorkerDTO w1 = new WorkerDTO(getUniqueName(), "surname", "nif"); + CriterionSatisfactionDTO w1s1 = new CriterionSatisfactionDTO( + ct.getName(), "c1", getDate(2000, 1, 1), getDate(2000, 2, 1)); + w1.criterionSatisfactions.add(w1s1); + ResourcesCostCategoryAssignmentDTO w1a1 = + new ResourcesCostCategoryAssignmentDTO(costCategory.getName(), + getDate(2000, 1, 1), getDate(2000, 2, 1)); + w1.resourcesCostCategoryAssignments.add(w1a1); + + /* Add resources. */ + assertNoConstraintViolations( + resourceService.addResources(createResourceListDTO(m1, w1))); + + /* + * Build DTOs for making the following update: + * + * + m1: update name, m1s1's start date, and add a new cost category + * assignment. + * + w1: update surname, w1a1's start date, and add a new criterion + * satisfaction. + */ + MachineDTO m1Updated = new MachineDTO(m1.code, "name" + "UPDATED", + null); + CriterionSatisfactionDTO m1s1Updated = new CriterionSatisfactionDTO( + m1s1.code, null, null, getDate(2000, 1, 2), null); + m1Updated.criterionSatisfactions.add(m1s1Updated); + ResourcesCostCategoryAssignmentDTO m1a2 = + new ResourcesCostCategoryAssignmentDTO(costCategory.getName(), + getDate(2000, 3, 1), getDate(2000, 4, 1)); + m1Updated.resourcesCostCategoryAssignments.add(m1a2); + + WorkerDTO w1Updated = new WorkerDTO(w1.code, null, + "surname" + "UPDATED", null); + CriterionSatisfactionDTO w1s2 = new CriterionSatisfactionDTO( + ct.getName(), "c1", getDate(2000, 3, 1), getDate(2000, 4, 1)); + w1Updated.criterionSatisfactions.add(w1s2); + ResourcesCostCategoryAssignmentDTO w1a1Updated = + new ResourcesCostCategoryAssignmentDTO(w1a1.code, null, + getDate(2000, 2, 1), null); + w1Updated.resourcesCostCategoryAssignments.add(w1a1Updated); + + /* Update resources and test. */ + assertNoConstraintViolations( + resourceService.addResources(createResourceListDTO(m1Updated, + w1Updated))); + + /* Test machine update. */ + Machine m1Entity = machineDAO.findByCode(m1.code); + + assertEquals(m1Updated.name, m1Entity.getName()); // Modified. + assertEquals(m1.description, m1Entity.getDescription()); //Not modified. + assertTrue(datesEquals( // Modified. + m1s1Updated.startDate, + m1Entity.getCriterionSatisfactionByCode(m1s1.code).getStartDate())); + assertTrue(datesEquals( // Not modified. + m1s1.endDate, + m1Entity.getCriterionSatisfactionByCode(m1s1.code).getEndDate())); + m1Entity.getResourcesCostCategoryAssignmentByCode(m1a2.code); // New. + + /* Test worker update. */ + Worker w1Entity = workerDAO.findByCode(w1.code); + + assertEquals(w1Updated.surname, w1Entity.getSurname()); // Modified. + assertEquals(w1.firstName, w1Entity.getFirstName()); // Not modified. + w1Entity.getCriterionSatisfactionByCode(w1s2.code); // New. + assertTrue(datesEquals( // Modified. + w1a1Updated.startDate, + w1Entity.getResourcesCostCategoryAssignmentByCode(w1a1.code). + getInitDate())); + assertTrue(datesEquals( // Not modified. + w1a1.endDate, + w1Entity.getResourcesCostCategoryAssignmentByCode(w1a1.code). + getEndDate())); + + } + private CriterionType createCriterionType() { return createCriterionType(ResourceEnum.RESOURCE, true); } @@ -885,4 +988,33 @@ public class ResourceServiceTest { } + private boolean datesEquals(XMLGregorianCalendar date1, Date date2) { + + GregorianCalendar date2AsGC = new GregorianCalendar(); + date2AsGC.setTime(date2); + + return datesEquals(date1.toGregorianCalendar(), date2AsGC); + + } + + private boolean datesEquals(XMLGregorianCalendar date1, LocalDate date2) { + + GregorianCalendar date2AsGC = new GregorianCalendar( + date2.getYear(), date2.getMonthOfYear()-1, date2.getDayOfMonth()); + + return datesEquals(date1.toGregorianCalendar(), date2AsGC); + + + } + + public boolean datesEquals(GregorianCalendar date1, + GregorianCalendar date2) { + + return date1.get(Calendar.YEAR) == date2.get(Calendar.YEAR) && + date1.get(Calendar.MONTH) == date2.get(Calendar.MONTH) && + date1.get(Calendar.DAY_OF_MONTH) == + date2.get(Calendar.DAY_OF_MONTH); + + } + } diff --git a/scripts/rest-clients/README b/scripts/rest-clients/README index 048693da3..8eb0f4d0e 100644 --- a/scripts/rest-clients/README +++ b/scripts/rest-clients/README @@ -38,6 +38,9 @@ - Check the returned errors are consistent with the comments in resources-sample.xml. + - Repeat with resources-update-sample.xml (resources-sample-mini.xml + must be previously imported). + * Export order elements: - export-order-element.sh ORDER-ELEMENT-CODE (authenticate with diff --git a/scripts/rest-clients/resources-sample.xml b/scripts/rest-clients/resources-sample.xml index fc7a00274..df40f83fb 100644 --- a/scripts/rest-clients/resources-sample.xml +++ b/scripts/rest-clients/resources-sample.xml @@ -16,7 +16,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +