[Bug #932] Check there are not overlapped category assignments, and if there are mark failing criterio assignment in form

I refactored the code that does the checking in the business layer.
Instead of putting it directly in a method executed by
HibernateValidator I put it in a static method in the business layer.
This way it can be reused easily from the view layer.

The validation returns a ValidationException pointing to the object that
caused the error. Its corresponding component is localized in the view
and the error is shown as a WrongValidationException.

FEA: ItEr73S04BugFixing
This commit is contained in:
Diego Pino Garcia 2011-04-01 12:23:24 +02:00
parent 363a56126b
commit 24edef10ec
6 changed files with 115 additions and 30 deletions

View file

@ -25,6 +25,9 @@ import java.util.ArrayList;
import java.util.List;
import org.zkoss.zk.ui.Component;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Row;
import org.zkoss.zul.api.Rows;
/**
* Utility methods to find components
@ -56,4 +59,18 @@ public class ComponentsFinder {
return null;
}
public static Row findRowByValue(Grid grid, Object needle) {
Rows rows = grid.getRows();
for (Object each : rows.getChildren()) {
if (each instanceof Row) {
Row row = (Row) each;
Object value = row.getValue();
if (needle.equals(value)) {
return row;
}
}
}
return null;
}
}

View file

@ -69,6 +69,10 @@ public class ValidationException extends RuntimeException {
return invalidValues.clone();
}
public InvalidValue getInvalidValue() {
return (invalidValues.length > 0) ? invalidValues.clone()[0] : null;
}
public ValidationException(InvalidValue invalidValue) {
super(getValidationErrorSummary(invalidValue));
storeInvalidValues(toArray(invalidValue));

View file

@ -21,6 +21,8 @@
package org.navalplanner.business.costcategories.entities;
import static org.navalplanner.business.i18n.I18nHelper._;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@ -29,6 +31,7 @@ import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.AssertFalse;
import org.hibernate.validator.AssertTrue;
import org.hibernate.validator.InvalidValue;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.NotNull;
import org.hibernate.validator.Valid;
@ -37,6 +40,7 @@ import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.Registry;
import org.navalplanner.business.common.entities.EntitySequence;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.costcategories.daos.ICostCategoryDAO;
/**
@ -243,4 +247,50 @@ public class CostCategory extends IntegrationEntity {
public Integer getLastHourCostSequenceCode() {
return lastHourCostSequenceCode;
}
}
public static void checkOverlapping(
List<ResourcesCostCategoryAssignment> costCategoryAssignments) {
for (int i = 0; i < costCategoryAssignments.size(); i++) {
LocalDate initDate = costCategoryAssignments.get(i).getInitDate();
LocalDate endDate = costCategoryAssignments.get(i).getEndDate();
for (int j = i + 1; j < costCategoryAssignments.size(); j++) {
ResourcesCostCategoryAssignment costCategory = costCategoryAssignments
.get(j);
if (endDate == null && costCategory.getEndDate() == null) {
throw new ValidationException(invalidValue(_("Some cost category assignments overlap in time"), costCategory));
} else if ((endDate == null && costCategory.getEndDate()
.compareTo(initDate) >= 0)
|| (costCategory.getEndDate() == null && costCategory
.getInitDate().compareTo(endDate) <= 0)) {
throw new ValidationException(invalidValue(_("Some cost category assignments overlap in time"), costCategory));
} else if ((endDate != null && costCategory.getEndDate() != null)
&& ((costCategory.getEndDate().compareTo(initDate) >= 0 && // (1)
// listElement.getEndDate()
// inside
// [initDate,
// endDate]
costCategory.getEndDate().compareTo(endDate) <= 0)
|| (costCategory.getInitDate().compareTo(
initDate) >= 0 && // (2)
// listElement.getInitDate()
// inside [initDate,
// endDate]
costCategory.getInitDate().compareTo(endDate) <= 0) || (costCategory
.getInitDate().compareTo(initDate) <= 0 && // (3)
// [listElement.getInitDate(),
// listElement.getEndDate()]
costCategory.getEndDate().compareTo(endDate) >= 0))) { // contains
// [initDate,
// endDate]
throw new ValidationException(invalidValue(_("Some cost category assignments overlap in time"), costCategory));
}
}
}
}
private static InvalidValue invalidValue(String message, ResourcesCostCategoryAssignment each) {
return new InvalidValue(message, null, "", each, null);
}
}

View file

@ -52,6 +52,7 @@ import org.navalplanner.business.common.Registry;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.common.exceptions.MultipleInstancesException;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.costcategories.entities.CostCategory;
import org.navalplanner.business.costcategories.entities.ResourcesCostCategoryAssignment;
import org.navalplanner.business.planner.entities.AvailabilityCalculator;
import org.navalplanner.business.planner.entities.DayAssignment;
@ -1079,14 +1080,11 @@ public abstract class Resource extends IntegrationEntity {
* Check if time intervals in cost assignments are correct in isolation.
* If not, it does not make sense to check assignment overlapping.
*/
for (ResourcesCostCategoryAssignment i :
getResourcesCostCategoryAssignments()) {
if (!(i.isInitDateSpecified() &&
i.checkConstraintPositiveTimeInterval())) {
for (ResourcesCostCategoryAssignment each : getResourcesCostCategoryAssignments()) {
if (!(each.isInitDateSpecified() && each
.checkConstraintPositiveTimeInterval())) {
return false;
}
}
/*
@ -1095,28 +1093,11 @@ public abstract class Resource extends IntegrationEntity {
List<ResourcesCostCategoryAssignment> assignmentsList =
new ArrayList<ResourcesCostCategoryAssignment>();
assignmentsList.addAll(getResourcesCostCategoryAssignments());
for(int i=0; i<assignmentsList.size(); i++) {
LocalDate initDate = assignmentsList.get(i).getInitDate();
LocalDate endDate = assignmentsList.get(i).getEndDate();
for(int j=i+1; j<assignmentsList.size(); j++) {
ResourcesCostCategoryAssignment listElement = assignmentsList.get(j);
if (endDate == null && listElement.getEndDate() == null) {
return true;
}
else if((endDate == null && listElement.getEndDate().compareTo(initDate)>=0) ||
(listElement.getEndDate() == null && listElement.getInitDate().compareTo(endDate)<=0)) {
return true;
}
else if((endDate != null && listElement.getEndDate() != null) &&
((listElement.getEndDate().compareTo(initDate)>=0 && // (1) listElement.getEndDate() inside [initDate, endDate]
listElement.getEndDate().compareTo(endDate)<=0) ||
(listElement.getInitDate().compareTo(initDate)>=0 && // (2) listElement.getInitDate() inside [initDate, endDate]
listElement.getInitDate().compareTo(endDate)<=0) ||
(listElement.getInitDate().compareTo(initDate)<=0 && // (3) [listElement.getInitDate(), listElement.getEndDate()]
listElement.getEndDate().compareTo(endDate)>=0))) { // contains [initDate, endDate]
return true;
}
}
try {
CostCategory.checkOverlapping(assignmentsList);
} catch (ValidationException e) {
return true;
}
return false;

View file

@ -27,7 +27,9 @@ import java.util.Date;
import java.util.List;
import org.apache.commons.logging.LogFactory;
import org.hibernate.validator.InvalidValue;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.costcategories.entities.CostCategory;
import org.navalplanner.business.costcategories.entities.ResourcesCostCategoryAssignment;
import org.navalplanner.business.resources.entities.Resource;
@ -38,7 +40,9 @@ import org.navalplanner.web.common.MessagesForUser;
import org.navalplanner.web.common.Util;
import org.navalplanner.web.common.components.Autocomplete;
import org.navalplanner.web.workreports.WorkReportCRUDController;
import org.zkoss.ganttz.util.ComponentsFinder;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
@ -318,4 +322,25 @@ public class ResourcesCostCategoryAssignmentController extends GenericForwardCom
public void validateConstraints() {
ConstraintChecker.isValid(self);
}
/**
* Check there are not category assignment overlaps
*
* @return
*/
public boolean validate() {
List<ResourcesCostCategoryAssignment> costCategoryAssignments = resourcesCostCategoryAssignmentModel
.getCostCategoryAssignments();
try {
CostCategory.checkOverlapping(costCategoryAssignments);
} catch (ValidationException e) {
InvalidValue invalidValue = e.getInvalidValue();
Component comp = ComponentsFinder.findRowByValue(
listResourcesCostCategoryAssignments,
invalidValue.getValue());
throw new WrongValueException(comp, invalidValue.getMessage());
}
return true;
}
}

View file

@ -196,11 +196,19 @@ public class WorkerCRUDController extends GenericForwardComposer implements
public boolean save() {
validateConstraints();
// Validate 'Cost category assignment' tab is correct
if (resourcesCostCategoryAssignmentController != null) {
if (!resourcesCostCategoryAssignmentController.validate()) {
return false;
}
}
try {
if (baseCalendarEditionController != null) {
baseCalendarEditionController.save();
}
if(criterionsController != null){
if (criterionsController != null){
if(!criterionsController.validate()){
return false;
}