From 3ad1c801a63e65a4dfdcefdf7653d8afeb83fa51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Gonz=C3=A1lez=20Fern=C3=A1ndez?= Date: Thu, 21 Jul 2011 16:59:50 +0200 Subject: [PATCH] Don't use the returned by queries allocations belonging to the order Instead those allocations should be retrieved directly from the order so it works well when the scenario is not the owner one and with newly added allocations. FEA: ItEr75S11PreventLooseChanges --- .../planner/entities/DayAssignment.java | 12 +- .../planner/entities/ResourceAllocation.java | 2 +- .../planner/entities/TaskElement.java | 11 + .../business/resources/daos/IResourceDAO.java | 9 - .../business/resources/daos/ResourceDAO.java | 44 ---- .../planner/order/PlanningStateCreator.java | 236 ++++++++++++++++++ .../web/resourceload/ResourceLoadModel.java | 92 +++++-- 7 files changed, 324 insertions(+), 82 deletions(-) diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/DayAssignment.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/DayAssignment.java index 1ce654256..2ceda0148 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/DayAssignment.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/DayAssignment.java @@ -105,6 +105,15 @@ public abstract class DayAssignment extends BaseEntity { public static Map> byResourceAndOrdered( Collection assignments) { + Map> result = byResource(assignments); + for (Entry> entry : result.entrySet()) { + Collections.sort(entry.getValue(), byDayComparator()); + } + return result; + } + + public static Map> byResource( + Collection assignments) { Map> result = new HashMap>(); for (T assignment : assignments) { Resource resource = assignment.getResource(); @@ -113,9 +122,6 @@ public abstract class DayAssignment extends BaseEntity { } result.get(resource).add(assignment); } - for (Entry> entry : result.entrySet()) { - Collections.sort(entry.getValue(), byDayComparator()); - } return result; } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/ResourceAllocation.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/ResourceAllocation.java index 4942665cc..bb5413efe 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/ResourceAllocation.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/ResourceAllocation.java @@ -129,7 +129,7 @@ public abstract class ResourceAllocation extends } public static > List sortedByStartDate( - Collection allocations) { + Collection allocations) { List result = new ArrayList(allocations); Collections.sort(result, byStartDateComparator()); return result; diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskElement.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskElement.java index 95eb1e33e..f006bc384 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskElement.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskElement.java @@ -26,6 +26,7 @@ import static org.navalplanner.business.workingday.EffortDuration.zero; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.ConcurrentModificationException; @@ -63,6 +64,16 @@ public abstract class TaskElement extends BaseEntity { private static final Log LOG = LogFactory.getLog(TaskElement.class); + public static List justTasks(Collection tasks) { + List result = new ArrayList(); + for (TaskElement taskElement : tasks) { + if (taskElement instanceof Task) { + result.add((Task) taskElement); + } + } + return result; + } + public interface IDatesInterceptor { public void setStartDate(IntraDayDate previousStart, IntraDayDate previousEnd, IntraDayDate newStart); diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/IResourceDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/IResourceDAO.java index eb8fef58f..70fa36345 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/IResourceDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/IResourceDAO.java @@ -26,7 +26,6 @@ import java.util.List; import org.navalplanner.business.common.daos.IIntegrationEntityDAO; import org.navalplanner.business.labels.entities.Label; -import org.navalplanner.business.planner.entities.Task; import org.navalplanner.business.reports.dtos.HoursWorkedPerResourceDTO; import org.navalplanner.business.reports.dtos.HoursWorkedPerWorkerInAMonthDTO; import org.navalplanner.business.resources.entities.Criterion; @@ -42,14 +41,6 @@ import org.navalplanner.business.resources.entities.Worker; */ public interface IResourceDAO extends IIntegrationEntityDAO { - /** - * Returns all {@link Resource} which are related with tasks - * - * @param tasks - * @return - */ - List findResourcesRelatedTo(List tasks); - /** * Returns all {@link Machine} * diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourceDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourceDAO.java index 1e62c9ce1..24a81cc98 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourceDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourceDAO.java @@ -24,15 +24,12 @@ package org.navalplanner.business.resources.daos; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Set; import org.hibernate.Query; import org.hibernate.criterion.Restrictions; import org.navalplanner.business.common.daos.IntegrationEntityDAO; import org.navalplanner.business.labels.entities.Label; -import org.navalplanner.business.planner.entities.Task; import org.navalplanner.business.reports.dtos.HoursWorkedPerResourceDTO; import org.navalplanner.business.reports.dtos.HoursWorkedPerWorkerInAMonthDTO; import org.navalplanner.business.resources.entities.Criterion; @@ -41,7 +38,6 @@ import org.navalplanner.business.resources.entities.Machine; import org.navalplanner.business.resources.entities.Resource; import org.navalplanner.business.resources.entities.Worker; import org.navalplanner.business.scenarios.IScenarioManager; -import org.navalplanner.business.scenarios.entities.Scenario; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; @@ -91,46 +87,6 @@ public class ResourceDAO extends IntegrationEntityDAO implements return list; } - @Override - public List findResourcesRelatedTo(List taskElements) { - if (taskElements.isEmpty()) { - return new ArrayList(); - } - Set result = new LinkedHashSet(); - result.addAll(findRelatedToSpecific(taskElements)); - result.addAll(findRelatedToGeneric(taskElements)); - return new ArrayList(result); - } - - @SuppressWarnings("unchecked") - private List findRelatedToGeneric(List taskElements) { - String query = "SELECT DISTINCT resource FROM GenericResourceAllocation generic" - + " JOIN generic.genericDayAssignmentsContainers container " - + " JOIN container.dayAssignments dayAssignment" - + " JOIN dayAssignment.resource resource" - + " WHERE generic.task IN(:taskElements)"; - return getSession().createQuery(query) - .setParameterList("taskElements", - taskElements).list(); - } - - @SuppressWarnings("unchecked") - private List findRelatedToSpecific(List taskElements) { - Scenario scenario = scenarioManager.getCurrent(); - List list = getSession() - .createQuery( - "SELECT DISTINCT specificAllocation.resource " - + "FROM SpecificResourceAllocation specificAllocation " - + "JOIN specificAllocation.specificDayAssignmentsContainers container " - + "WHERE specificAllocation.task IN(:taskElements) " - + "and container.scenario = :scenario " - + "and container.dayAssignments IS NOT EMPTY") - .setParameterList("taskElements", taskElements) - .setParameter("scenario", scenario) - .list(); - return list; - } - public List getResources() { return list(Resource.class); } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/PlanningStateCreator.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/PlanningStateCreator.java index c7c3df5ce..8dc5d639a 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/PlanningStateCreator.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/PlanningStateCreator.java @@ -18,6 +18,8 @@ */ package org.navalplanner.web.planner.order; +import static org.navalplanner.business.planner.entities.TaskElement.justTasks; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -28,6 +30,7 @@ import java.util.Set; import org.apache.commons.lang.Validate; import org.hibernate.Hibernate; +import org.joda.time.LocalDate; import org.navalplanner.business.orders.daos.IOrderDAO; import org.navalplanner.business.orders.entities.Order; import org.navalplanner.business.orders.entities.OrderElement; @@ -38,6 +41,9 @@ import org.navalplanner.business.planner.entities.DayAssignment; import org.navalplanner.business.planner.entities.DerivedAllocation; import org.navalplanner.business.planner.entities.GenericResourceAllocation; import org.navalplanner.business.planner.entities.ResourceAllocation; +import org.navalplanner.business.planner.entities.ResourceAllocation.IVisitor; +import org.navalplanner.business.planner.entities.SpecificResourceAllocation; +import org.navalplanner.business.planner.entities.Task; import org.navalplanner.business.planner.entities.TaskElement; import org.navalplanner.business.planner.entities.TaskGroup; import org.navalplanner.business.planner.entities.TaskMilestone; @@ -509,6 +515,93 @@ public class PlanningStateCreator { } } + public List getResourcesRelatedWithAllocations() { + Set result = new HashSet(); + for (Task each : justTasks(order + .getAllChildrenAssociatedTaskElements())) { + result.addAll(resourcesRelatedWith(each)); + } + return new ArrayList(result); + } + + private Set resourcesRelatedWith(Task task) { + Set result = new HashSet(); + for (ResourceAllocation each : task + .getSatisfiedResourceAllocations()) { + result.addAll(resourcesRelatedWith(each)); + } + return result; + } + + private Collection resourcesRelatedWith( + ResourceAllocation allocation) { + return ResourceAllocation.visit(allocation, + new IVisitor>() { + + @Override + public Collection on( + SpecificResourceAllocation specificAllocation) { + return Collections.singletonList(specificAllocation + .getResource()); + } + + @Override + public Collection on( + GenericResourceAllocation genericAllocation) { + return DayAssignment.byResource( + genericAllocation.getAssignments()) + .keySet(); + } + }); + } + + public List> replaceByCurrentOnes( + Collection> allocationsReturnedByQuery, + IAllocationCriteria allocationCriteria) { + Set orderTasks = new HashSet( + order.getAllChildrenAssociatedTaskElements()); + List> result = allocationsNotInOrder( + allocationsReturnedByQuery, orderTasks); + result.addAll(allocationsInOrderSatisfyingCriteria(orderTasks, + allocationCriteria)); + return result; + } + + private List> allocationsNotInOrder( + Collection> allocationsReturnedByQuery, + Set orderTasks) { + List> result = new ArrayList>(); + for (ResourceAllocation each : allocationsReturnedByQuery) { + if (!orderTasks.contains(each.getTask())) { + result.add(each); + } + } + return result; + } + + private List> allocationsInOrderSatisfyingCriteria( + Collection tasks, + IAllocationCriteria allocationCriteria) { + List> result = new ArrayList>(); + for (Task each : justTasks(tasks)) { + result.addAll(satisfying(allocationCriteria, + each.getSatisfiedResourceAllocations())); + } + return result; + } + + private List> satisfying( + IAllocationCriteria criteria, + Collection> allocations) { + List> result = new ArrayList>(); + for (ResourceAllocation each : allocations) { + if (criteria.isSatisfiedBy(each)) { + result.add(each); + } + } + return result; + } + } private class EmptyPlannigState extends PlanningState { @@ -712,4 +805,147 @@ public class PlanningStateCreator { } + public interface IAllocationCriteria { + + boolean isSatisfiedBy(ResourceAllocation resourceAllocation); + + } + + public static IAllocationCriteria and(final IAllocationCriteria... criteria) { + return new IAllocationCriteria() { + + @Override + public boolean isSatisfiedBy( + ResourceAllocation resourceAllocation) { + for (IAllocationCriteria each : criteria) { + if (!each.isSatisfiedBy(resourceAllocation)) { + return false; + } + } + return true; + } + }; + } + + public static class TaskOnInterval implements IAllocationCriteria { + + private final LocalDate startInclusive; + + private final LocalDate endInclusive; + + public TaskOnInterval(LocalDate startInclusive, LocalDate endInclusive) { + this.startInclusive = startInclusive; + this.endInclusive = endInclusive; + } + + @Override + public boolean isSatisfiedBy(ResourceAllocation resourceAllocation) { + if (startInclusive != null + && resourceAllocation.getEndDate() + .compareTo(startInclusive) < 0) { + return false; + } + if (endInclusive != null + && resourceAllocation.getStartDate() + .compareTo(endInclusive) > 0) { + return false; + } + return true; + } + } + + public static class RelatedWithAnyOf implements + IAllocationCriteria { + + private final Collection anyOf; + + public RelatedWithAnyOf( + Collection anyOf) { + this.anyOf = anyOf; + } + + @Override + public boolean isSatisfiedBy(ResourceAllocation resourceAllocation) { + if (resourceAllocation instanceof GenericResourceAllocation) { + GenericResourceAllocation g = (GenericResourceAllocation) resourceAllocation; + Set allocationCriterions = g.getCriterions(); + return someCriterionIn(allocationCriterions); + } + return false; + } + + private boolean someCriterionIn( + Collection allocationCriterions) { + for (Criterion each : allocationCriterions) { + if (this.anyOf.contains(each)) { + return true; + } + } + return false; + } + + } + + public static class SpecificRelatedWithCriterionOnInterval implements + IAllocationCriteria { + + private final LocalDate startInclusive; + + private final LocalDate endExclusive; + + private final Criterion criterion; + + public SpecificRelatedWithCriterionOnInterval( + Criterion criterion, LocalDate startInclusive, + LocalDate endInclusive) { + Validate.notNull(criterion); + this.startInclusive = startInclusive; + this.endExclusive = endInclusive != null ? endInclusive.plusDays(1) + : null; + this.criterion = criterion; + } + + @Override + public boolean isSatisfiedBy(ResourceAllocation resourceAllocation) { + if (resourceAllocation instanceof SpecificResourceAllocation) { + SpecificResourceAllocation s = (SpecificResourceAllocation) resourceAllocation; + return s.interferesWith(criterion, startInclusive, endExclusive); + } + return false; + } + + } + + public static class RelatedWithResource implements IAllocationCriteria { + private final Resource resource; + + public RelatedWithResource(Resource resource) { + Validate.notNull(resource); + this.resource = resource; + } + + @Override + public boolean isSatisfiedBy(ResourceAllocation resourceAllocation) { + return ResourceAllocation.visit(resourceAllocation, + new IVisitor() { + + @Override + public Boolean on( + SpecificResourceAllocation specificAllocation) { + return specificAllocation.getResource().equals( + resource); + } + + @Override + public Boolean on( + GenericResourceAllocation genericAllocation) { + return DayAssignment.byResource( + genericAllocation.getAssignments()) + .containsKey(resource); + } + }); + } + + } + } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java index e037e5dad..992a06d11 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java @@ -21,7 +21,9 @@ package org.navalplanner.web.resourceload; +import static org.navalplanner.business.planner.entities.TaskElement.justTasks; import static org.navalplanner.web.I18nHelper._; +import static org.navalplanner.web.planner.order.PlanningStateCreator.and; import java.util.ArrayList; import java.util.Calendar; @@ -68,7 +70,12 @@ import org.navalplanner.business.users.entities.OrderAuthorizationType; import org.navalplanner.business.users.entities.User; import org.navalplanner.business.users.entities.UserRole; import org.navalplanner.web.calendars.BaseCalendarModel; +import org.navalplanner.web.planner.order.PlanningStateCreator.IAllocationCriteria; import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState; +import org.navalplanner.web.planner.order.PlanningStateCreator.RelatedWithAnyOf; +import org.navalplanner.web.planner.order.PlanningStateCreator.RelatedWithResource; +import org.navalplanner.web.planner.order.PlanningStateCreator.SpecificRelatedWithCriterionOnInterval; +import org.navalplanner.web.planner.order.PlanningStateCreator.TaskOnInterval; import org.navalplanner.web.security.SecurityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; @@ -262,17 +269,43 @@ public class ResourceLoadModel implements IResourceLoadModel { } } + private IAllocationCriteria onInterval() { + return new TaskOnInterval(initDateFilter, endDateFilter); + } + private Map> findAllocationsGroupedByCriteria( List relatedWith) { - return resourceAllocationDAO - .findGenericAllocationsBySomeCriterion( - relatedWith, asDate(initDateFilter), asDate(endDateFilter)); + Map> result = resourceAllocationDAO + .findGenericAllocationsBySomeCriterion(relatedWith, + asDate(initDateFilter), asDate(endDateFilter)); + return doReplacementsIfNeeded(result, + and(onInterval(), new RelatedWithAnyOf(relatedWith))); } private Map> findAllocationsGroupedByCriteria() { - return resourceAllocationDAO - .findGenericAllocationsByCriterion( - asDate(initDateFilter), asDate(endDateFilter)); + return doReplacementsIfNeeded( + resourceAllocationDAO.findGenericAllocationsByCriterion( + asDate(initDateFilter), asDate(endDateFilter)), + onInterval()); + } + + private Map> doReplacementsIfNeeded( + Map> map, + IAllocationCriteria criteria) { + if (filterBy == null) { + return map; + } + Map> result = new HashMap>(); + for (Entry> each : map + .entrySet()) { + List> replaced = filterBy + .replaceByCurrentOnes(each.getValue(), criteria); + if (!replaced.isEmpty()) { + result.put(each.getKey(), ResourceAllocation.getOfType( + GenericResourceAllocation.class, replaced)); + } + } + return result; } private Map>> withAssociatedSpecific( @@ -282,14 +315,29 @@ public class ResourceLoadModel implements IResourceLoadModel { .entrySet()) { List> both = new ArrayList>(); both.addAll(each.getValue()); - both.addAll(resourceAllocationDAO.findSpecificAllocationsRelatedTo( - each.getKey(), asDate(initDateFilter), - asDate(endDateFilter))); + both.addAll(doReplacementsIfNeeded(resourceAllocationDAO + .findSpecificAllocationsRelatedTo(each.getKey(), + asDate(initDateFilter), asDate(endDateFilter)), + and(onInterval(), specificRelatedTo(each.getKey())))); result.put(each.getKey(), both); } return result; } + private IAllocationCriteria specificRelatedTo(Criterion key) { + return new SpecificRelatedWithCriterionOnInterval(key, + initDateFilter, endDateFilter); + } + + private Collection> doReplacementsIfNeeded( + Collection> allocations, + IAllocationCriteria criteria) { + if (filterBy == null) { + return allocations; + } + return filterBy.replaceByCurrentOnes(allocations, criteria); + } + private > Map> onlyForThePagesShown( List criteriaReallyShown, Map> allocationsByCriteria) { @@ -405,19 +453,8 @@ public class ResourceLoadModel implements IResourceLoadModel { } private List resourcesForActiveTasks() { - return Resource.sortByName(resourcesDAO - .findResourcesRelatedTo(justTasks(filterBy.getOrder() - .getAllChildrenAssociatedTaskElements()))); - } - - private List justTasks(Collection tasks) { - List result = new ArrayList(); - for (TaskElement taskElement : tasks) { - if (taskElement instanceof Task) { - result.add((Task) taskElement); - } - } - return result; + return Resource.sortByName(filterBy + .getResourcesRelatedWithAllocations()); } private List allResources() { @@ -641,13 +678,18 @@ public class ResourceLoadModel implements IResourceLoadModel { Map>> map = new LinkedHashMap>>(); for (Resource resource : allResources) { map.put(resource, ResourceAllocation - .sortedByStartDate(resourceAllocationDAO - .findAllocationsRelatedTo(resource, initDateFilter, - endDateFilter))); + .sortedByStartDate(doReplacementsIfNeeded( + resourceAllocationDAO.findAllocationsRelatedTo( + resource, initDateFilter, endDateFilter), + and(onInterval(), relatedToResource(resource))))); } return map; } + private IAllocationCriteria relatedToResource(Resource resource) { + return new RelatedWithResource(resource); + } + private List buildGroupsFor( Map>> map) { List result = new ArrayList();