From a2f359013eeda10d10063f01a3e699e5ff7507f3 Mon Sep 17 00:00:00 2001 From: Diego Pino Garcia Date: Thu, 16 Dec 2010 12:02:13 +0100 Subject: [PATCH] Respect dependency constraints for manual allocation Manual allocation, either appropriative and non-appropriative, didn't respect dependency constraints. Now manual allocation respects dependencies in the same manner as automatic allocation FEA: ItEr65OTS04CorreccionsRecursosLimitantes --- .../planner/limiting/entities/Gap.java | 17 ++- .../ILimitingResourceQueueModel.java | 6 +- .../LimitingResourceQueueModel.java | 141 ++++++++++++------ .../ManualAllocationController.java | 18 ++- 4 files changed, 131 insertions(+), 51 deletions(-) diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/limiting/entities/Gap.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/limiting/entities/Gap.java index 61ec0b0c3..568afc800 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/limiting/entities/Gap.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/limiting/entities/Gap.java @@ -25,6 +25,7 @@ import static org.navalplanner.business.workingday.EffortDuration.zero; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -65,6 +66,16 @@ public class Gap implements Comparable { return result; } + public static List onQueue( + LimitingResourceQueue queue, DateAndHour startTime, + DateAndHour endTime) { + + Gap gap = (endTime == null || endTime.compareTo(startTime) <= 0) ? Gap + .untilEnd(queue.getResource(), startTime) : Gap.create( + queue.getResource(), startTime, endTime); + return GapOnQueue.onQueue(queue, Collections.singleton(gap)); + } + private final LimitingResourceQueue originQueue; private final Gap gap; @@ -93,7 +104,11 @@ public class Gap implements Comparable { public static Gap untilEnd(LimitingResourceQueueElement current, DateAndHour startInclusive) { - return new Gap(current.getResource(), startInclusive, null); + return untilEnd(current.getResource(), startInclusive); + } + + private static Gap untilEnd(Resource resource, DateAndHour startInclusive) { + return new Gap(resource, startInclusive, null); } private DateAndHour startTime; diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/ILimitingResourceQueueModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/ILimitingResourceQueueModel.java index 6e4fe00f4..6774111bb 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/ILimitingResourceQueueModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/ILimitingResourceQueueModel.java @@ -21,6 +21,7 @@ package org.navalplanner.web.limitingresources; import java.util.List; +import java.util.Set; import org.navalplanner.business.orders.entities.Order; import org.navalplanner.business.planner.entities.DayAssignment; @@ -55,7 +56,7 @@ import org.zkoss.ganttz.util.Interval; */ public interface ILimitingResourceQueueModel { - boolean nonAppropriativeAllocation( + List nonAppropriativeAllocation( LimitingResourceQueueElement element, LimitingResourceQueue queue, DateAndHour time); /** @@ -127,7 +128,8 @@ public interface ILimitingResourceQueueModel { * @param queue * @param allocationTime */ - void appropriativeAllocation(LimitingResourceQueueElement element, LimitingResourceQueue queue, + Set appropriativeAllocation( + LimitingResourceQueueElement element, LimitingResourceQueue queue, DateAndHour allocationTime); void unschedule(LimitingResourceQueueElement element); diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/LimitingResourceQueueModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/LimitingResourceQueueModel.java index b7be0e463..64975d3f1 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/LimitingResourceQueueModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/LimitingResourceQueueModel.java @@ -415,6 +415,7 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel { @Override public List assignLimitingResourceQueueElement( LimitingResourceQueueElement externalQueueElement) { + InsertionRequirements requirements = queuesState .getRequirementsFor(externalQueueElement); AllocationSpec allocationDone = insertAtGap(requirements); @@ -612,19 +613,46 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel { return Collections.singletonList(each); } - private void applyAllocation(AllocationSpec allocationStillNotDone) { + private void applyAllocation(final AllocationSpec allocationStillNotDone) { + applyAllocation(allocationStillNotDone, new IDayAssignmentBehaviour() { + + @Override + public void allocateDayAssigments() { + ResourceAllocation resourceAllocation = getResourceAllocation(allocationStillNotDone); + Resource resource = getResource(allocationStillNotDone); + + List assignments = allocationStillNotDone.getAssignmentsFor( + resourceAllocation, resource); + resourceAllocation.allocateLimitingDayAssignments(assignments); + } + + private ResourceAllocation getResourceAllocation(AllocationSpec allocation) { + return allocation.getElement().getResourceAllocation(); + } + + private Resource getResource(AllocationSpec allocation) { + return allocation.getQueue().getResource(); + } + + }); + } + + private void applyAllocation(AllocationSpec allocationStillNotDone, + IDayAssignmentBehaviour allocationBehaviour) { + + // Do day allocation + allocationBehaviour.allocateDayAssigments(); + LimitingResourceQueueElement element = allocationStillNotDone - .getElement(); + .getElement(); LimitingResourceQueue queue = allocationStillNotDone.getQueue(); - Resource resource = queue.getResource(); - ResourceAllocation resourceAllocation = element.getResourceAllocation(); - List assignments = allocationStillNotDone - .getAssignmentsFor(resourceAllocation, resource); - resourceAllocation - .allocateLimitingDayAssignments(assignments); + + // Update start and end time of task updateStartAndEndTimes(element, allocationStillNotDone .getStartInclusive(), allocationStillNotDone .getEndExclusive()); + + // Add to queue and mark as modified addLimitingResourceQueueElementIfNeeded(queue, element); markAsModified(element); } @@ -635,43 +663,64 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel { .getEarliestEndDateBecauseOfGantt())); } - private boolean assignLimitingResourceQueueElementToQueueAt( - LimitingResourceQueueElement element, LimitingResourceQueue queue, - DateAndHour startTime, DateAndHour endsAfter) { + private List assignLimitingResourceQueueElementToQueueAt( + final LimitingResourceQueueElement element, + final LimitingResourceQueue queue, final DateAndHour startTime, + final DateAndHour endsAfter) { - // Allocate day assignments and adjust start and end times for element - List dayAssignments = LimitingResourceAllocator - .generateDayAssignments(element.getResourceAllocation(), queue - .getResource(), startTime, endsAfter); - element.getResourceAllocation().allocateLimitingDayAssignments( - dayAssignments); - - DateAndHour endTime = endFor(dayAssignments); - // the assignments can be generated after the required start - startTime = DateAndHour.max(startTime, startFor(dayAssignments)); - if (sameDay(startTime, endTime)) { - endTime = new DateAndHour(endTime.getDate(), startTime.getHour() + endTime.getHour()); + // Check if allocation is possible + InsertionRequirements requirements = queuesState + .getRequirementsFor(element); + List gapOnQueue = GapOnQueue.onQueue(queue, startTime, + endsAfter); + AllocationSpec allocation = requirements.guessValidity(gapOnQueue + .iterator().next()); + if (!allocation.isValid()) { + return Collections.emptyList(); } - updateStartAndEndTimes(element, startTime, endTime); - // Add element to queue - addLimitingResourceQueueElementIfNeeded(queue, element); - markAsModified(element); - return true; + // Do allocation + applyAllocation(allocation, new IDayAssignmentBehaviour() { + + @Override + public void allocateDayAssigments() { + + List assignments = LimitingResourceAllocator + .generateDayAssignments( + element.getResourceAllocation(), + queue.getResource(), startTime, endsAfter); + element.getResourceAllocation().allocateLimitingDayAssignments( + assignments); + } + + }); + + assert allocation.isValid(); + + // Move other tasks to respect dependency constraints + List result = new ArrayList(); + result.add(requirements.getElement()); + + List moved = shift( + queuesState.getPotentiallyAffectedByInsertion(element), + requirements.getElement(), allocation); + + // Return all moved tasks (including the allocated one) + result.addAll(moved); + return result; } - private DateAndHour endFor(List dayAssignments) { - DayAssignment last = dayAssignments.get(dayAssignments.size() - 1); - return new DateAndHour(last.getDay(), 0); - } + /** + * + * Describes how day assignments are going to be generated for an allocation + * + * @author Diego Pino GarcĂ­a + * + */ + private interface IDayAssignmentBehaviour { - private DateAndHour startFor(List dayAssignments) { - return new DateAndHour(dayAssignments - .get(0).getDay(), 0); - } + void allocateDayAssigments(); - private boolean sameDay(DateAndHour startTime, DateAndHour endTime) { - return startTime.getDate().equals(endTime.getDate()); } private void markAsModified(LimitingResourceQueueElement element) { @@ -890,7 +939,7 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel { } @Override - public boolean nonAppropriativeAllocation( + public List nonAppropriativeAllocation( LimitingResourceQueueElement element, LimitingResourceQueue queue, DateAndHour startTime) { @@ -918,9 +967,11 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel { @Override - public void appropriativeAllocation(LimitingResourceQueueElement _element, LimitingResourceQueue _queue, + public Set appropriativeAllocation(LimitingResourceQueueElement _element, LimitingResourceQueue _queue, DateAndHour allocationTime) { + Set result = new HashSet(); + LimitingResourceQueue queue = queuesState.getEquivalent(_queue); LimitingResourceQueueElement element = queuesState.getEquivalent(_element); @@ -938,8 +989,9 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel { final LocalDate startDate = gap.getStartTime().getDate(); if (startDate.equals(allocationTime.getDate())) { - assignLimitingResourceQueueElementToQueueAt(element, queue, - allocationTime, getEndsAfterBecauseOfGantt(element)); + result.addAll(assignLimitingResourceQueueElementToQueueAt( + element, queue, allocationTime, + getEndsAfterBecauseOfGantt(element))); break; } else { LimitingResourceQueueElement elementAtTime = getFirstElementFrom( @@ -954,10 +1006,11 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel { for (LimitingResourceQueueElement each: unscheduledElements) { gap = LimitingResourceAllocator.getFirstValidGap(queue, each); - assignLimitingResourceQueueElementToQueueAt(each, queue, gap - .getStartTime(), getEndsAfterBecauseOfGantt(element)); + result.addAll(assignLimitingResourceQueueElementToQueueAt(each, queue, gap + .getStartTime(), getEndsAfterBecauseOfGantt(element))); } + return result; } @SuppressWarnings("unchecked") diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/ManualAllocationController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/ManualAllocationController.java index af67912be..c1d1124fc 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/ManualAllocationController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/ManualAllocationController.java @@ -22,10 +22,12 @@ package org.navalplanner.web.limitingresources; import static org.navalplanner.web.I18nHelper._; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.commons.lang.Validate; import org.joda.time.LocalDate; @@ -278,15 +280,23 @@ public class ManualAllocationController extends GenericForwardComposer { private void nonAppropriativeAllocation(LimitingResourceQueueElement element, LimitingResourceQueue queue, DateAndHour time) { Validate.notNull(time); - getLimitingResourceQueueModel() + List inserted = getLimitingResourceQueueModel() .nonAppropriativeAllocation(element, queue, time); - limitingResourcesPanel.appendQueueElementToQueue(element); + refreshQueues(inserted); } private void appropriativeAllocation(LimitingResourceQueueElement element, LimitingResourceQueue queue, DateAndHour time) { Validate.notNull(time); - getLimitingResourceQueueModel().appropriativeAllocation(element, queue, time); - limitingResourcesPanel.refreshQueue(queue); + Set inserted = getLimitingResourceQueueModel() + .appropriativeAllocation(element, queue, time); + refreshQueues(inserted); + } + + private void refreshQueues(Collection movedElements) { + for (LimitingResourceQueueElement each : movedElements) { + limitingResourcesPanel.removeDependencyComponentsFor(each); + limitingResourcesPanel.refreshQueue(each.getLimitingResourceQueue()); + } } private DateAndHour getSelectedAllocationTime() {