ItEr59S08CUAsignacionRecursosLimitantesItEr58S10: Handle outcoming dependencies to already assigned elements
This commit is contained in:
parent
cd0cfc04b6
commit
5f3d6fe72d
5 changed files with 136 additions and 35 deletions
|
|
@ -38,10 +38,8 @@ import org.navalplanner.business.resources.entities.LimitingResourceQueue;
|
|||
import org.navalplanner.business.resources.entities.Resource;
|
||||
|
||||
/**
|
||||
*
|
||||
* Entity which represents an element in the queue which represents
|
||||
* the limiting resources.
|
||||
*
|
||||
* Entity which represents an element in the queue which represents the limiting
|
||||
* resources.
|
||||
* @author Diego Pino Garcia <dpino@igalia.com>
|
||||
* @author Javier Moran Rua <jmoran@igalia.com>
|
||||
*/
|
||||
|
|
@ -61,11 +59,9 @@ public class LimitingResourceQueueElement extends BaseEntity {
|
|||
|
||||
private long creationTimestamp;
|
||||
|
||||
private Set<LimitingResourceQueueDependency> dependenciesAsOrigin =
|
||||
new HashSet<LimitingResourceQueueDependency>();
|
||||
private Set<LimitingResourceQueueDependency> dependenciesAsOrigin = new HashSet<LimitingResourceQueueDependency>();
|
||||
|
||||
private Set<LimitingResourceQueueDependency> dependenciesAsDestiny =
|
||||
new HashSet<LimitingResourceQueueDependency>();
|
||||
private Set<LimitingResourceQueueDependency> dependenciesAsDestiny = new HashSet<LimitingResourceQueueDependency>();
|
||||
|
||||
public static LimitingResourceQueueElement create() {
|
||||
return create(new LimitingResourceQueueElement());
|
||||
|
|
@ -91,7 +87,8 @@ public class LimitingResourceQueueElement extends BaseEntity {
|
|||
return limitingResourceQueue;
|
||||
}
|
||||
|
||||
public void setLimitingResourceQueue(LimitingResourceQueue limitingResourceQueue) {
|
||||
public void setLimitingResourceQueue(
|
||||
LimitingResourceQueue limitingResourceQueue) {
|
||||
this.limitingResourceQueue = limitingResourceQueue;
|
||||
}
|
||||
|
||||
|
|
@ -175,9 +172,10 @@ public class LimitingResourceQueueElement extends BaseEntity {
|
|||
} else if (d.getHasAsDestiny().equals(this)) {
|
||||
dependenciesAsDestiny.add(d);
|
||||
} else {
|
||||
throw new IllegalArgumentException("It cannot be added a dependency" +
|
||||
" in which the current queue element is neither origin" +
|
||||
" not desinty");
|
||||
throw new IllegalArgumentException(
|
||||
"It cannot be added a dependency"
|
||||
+ " in which the current queue element is neither origin"
|
||||
+ " not desinty");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,26 +60,22 @@ public interface ILimitingResourceQueueModel {
|
|||
|
||||
/**
|
||||
* Assigns a {@link LimitingResourceQueueElement} to its corresponding
|
||||
* {@link LimitingResourceQueue}
|
||||
*
|
||||
* There is one and only one queue for every limiting resource. An element
|
||||
* is assigned to its queue searching by element.resource.
|
||||
*
|
||||
* Allocation within the queue is done by finding the first gap in the queue
|
||||
* that fits the initial intented hours assigned to
|
||||
* element.resourceallocation.
|
||||
*
|
||||
* The method also generates {@link DayAssignment} once the allocation is
|
||||
* done
|
||||
*
|
||||
* Returns true if the process was successful. The only case were an
|
||||
* allocation cannot be done is if there's not any queue that can hold the
|
||||
* element (only for a generic allocation, there's not any queue that
|
||||
* matches the criteria of the element)
|
||||
*
|
||||
* {@link LimitingResourceQueue} There is one and only one queue for every
|
||||
* limiting resource. An element is assigned to its queue searching by
|
||||
* element.resource. Allocation within the queue is done by finding the
|
||||
* first gap in the queue that fits the initial intented hours assigned to
|
||||
* element.resourceallocation. The method also generates
|
||||
* {@link DayAssignment} once the allocation is done Returns the inserted
|
||||
* queue elements. More than one can be inserted because inserting
|
||||
* <code>element</code> can imply to move its sucessors.<br />
|
||||
* The only case were an allocation cannot be done is if there's not any
|
||||
* queue that can hold the element (only for a generic allocation, there's
|
||||
* not any queue that matches the criteria of the element). In this case an
|
||||
* empty list is returned
|
||||
* @param element
|
||||
*/
|
||||
boolean assignLimitingResourceQueueElement(LimitingResourceQueueElement element);
|
||||
List<LimitingResourceQueueElement> assignLimitingResourceQueueElement(
|
||||
LimitingResourceQueueElement element);
|
||||
|
||||
ZoomLevel calculateInitialZoomLevel();
|
||||
|
||||
|
|
|
|||
|
|
@ -390,9 +390,22 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean assignLimitingResourceQueueElement(
|
||||
public List<LimitingResourceQueueElement> assignLimitingResourceQueueElement(
|
||||
LimitingResourceQueueElement externalQueueElement) {
|
||||
GapRequirements requirements = queuesState.getRequirementsFor(externalQueueElement);
|
||||
List<LimitingResourceQueueElement> result = new ArrayList<LimitingResourceQueueElement>();
|
||||
for (LimitingResourceQueueElement each : queuesState
|
||||
.getInsertionsToBeDoneFor(externalQueueElement)) {
|
||||
GapRequirements requirements = queuesState.getRequirementsFor(each);
|
||||
boolean inserted = insert(requirements);
|
||||
if (!inserted) {
|
||||
break;
|
||||
}
|
||||
result.add(requirements.getElement());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean insert(GapRequirements requirements) {
|
||||
List<GapOnQueue> potentiallyValidGapsFor = queuesState
|
||||
.getPotentiallyValidGapsFor(requirements);
|
||||
boolean generic = requirements.getElement().isGeneric();
|
||||
|
|
|
|||
|
|
@ -406,10 +406,16 @@ public class LimitingResourcesController extends GenericForwardComposer {
|
|||
LimitingResourceQueueElementDTO dto) {
|
||||
|
||||
LimitingResourceQueueElement element = dto.getOriginal();
|
||||
if (limitingResourceQueueModel
|
||||
.assignLimitingResourceQueueElement(element)) {
|
||||
List<LimitingResourceQueueElement> inserted = limitingResourceQueueModel
|
||||
.assignLimitingResourceQueueElement(element);
|
||||
if (!inserted.isEmpty()) {
|
||||
Util.reloadBindings(gridUnassignedLimitingResourceQueueElements);
|
||||
limitingResourcesPanel.appendQueueElementToQueue(element);
|
||||
for (LimitingResourceQueueElement each : inserted) {
|
||||
// FIXME visually wrong if an element jumps from a queue to
|
||||
// another
|
||||
limitingResourcesPanel.refreshQueue(each
|
||||
.getLimitingResourceQueue());
|
||||
}
|
||||
} else {
|
||||
showErrorMessage(_("Cannot allocate selected element. There is not any queue " +
|
||||
"that matches resource allocation criteria at any interval of time"));
|
||||
|
|
|
|||
|
|
@ -23,13 +23,16 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.jgrapht.DirectedGraph;
|
||||
import org.jgrapht.alg.CycleDetector;
|
||||
import org.jgrapht.graph.SimpleDirectedGraph;
|
||||
import org.jgrapht.traverse.TopologicalOrderIterator;
|
||||
import org.navalplanner.business.common.BaseEntity;
|
||||
import org.navalplanner.business.planner.entities.GenericResourceAllocation;
|
||||
import org.navalplanner.business.planner.entities.ResourceAllocation;
|
||||
|
|
@ -119,6 +122,8 @@ public class QueuesState {
|
|||
LimitingResourceQueueDependency dependency) {
|
||||
LimitingResourceQueueElement origin = dependency.getHasAsOrigin();
|
||||
LimitingResourceQueueElement destination = dependency.getHasAsDestiny();
|
||||
result.addVertex(origin);
|
||||
result.addVertex(destination);
|
||||
result.addEdge(origin, destination, dependency);
|
||||
}
|
||||
|
||||
|
|
@ -242,4 +247,87 @@ public class QueuesState {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param externalQueueElement
|
||||
* the queue element to insert
|
||||
* @return the list of elements that must be reinserted due to the insertion
|
||||
* of <code>externalQueueElement</code>
|
||||
*/
|
||||
public List<LimitingResourceQueueElement> getInsertionsToBeDoneFor(
|
||||
LimitingResourceQueueElement externalQueueElement) {
|
||||
LimitingResourceQueueElement queueElement = getEquivalent(externalQueueElement);
|
||||
DirectedGraph<LimitingResourceQueueElement, LimitingResourceQueueDependency> subGraph = buildOutgoingGraphFor(queueElement);
|
||||
CycleDetector<LimitingResourceQueueElement, LimitingResourceQueueDependency> cycleDetector = cycleDetector(subGraph);
|
||||
if (cycleDetector.detectCycles()) {
|
||||
throw new IllegalStateException("subgraph has cycles");
|
||||
}
|
||||
List<LimitingResourceQueueElement> result = new ArrayList<LimitingResourceQueueElement>();
|
||||
result.add(queueElement);
|
||||
result.addAll(getElementsOrderedTopologically(subGraph));
|
||||
unassignFromQueues(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private DirectedGraph<LimitingResourceQueueElement, LimitingResourceQueueDependency> buildOutgoingGraphFor(
|
||||
LimitingResourceQueueElement queueElement) {
|
||||
SimpleDirectedGraph<LimitingResourceQueueElement, LimitingResourceQueueDependency> result = instantiateDirectedGraph();
|
||||
buildOutgoingGraphFor(result, queueElement);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void buildOutgoingGraphFor(
|
||||
DirectedGraph<LimitingResourceQueueElement, LimitingResourceQueueDependency> result,
|
||||
LimitingResourceQueueElement element) {
|
||||
Set<LimitingResourceQueueDependency> outgoingEdgesOf = graph
|
||||
.outgoingEdgesOf(element);
|
||||
for (LimitingResourceQueueDependency each : outgoingEdgesOf) {
|
||||
addDependency(result, each);
|
||||
buildOutgoingGraphFor(result, each.getHasAsDestiny());
|
||||
}
|
||||
}
|
||||
|
||||
private CycleDetector<LimitingResourceQueueElement, LimitingResourceQueueDependency> cycleDetector(
|
||||
DirectedGraph<LimitingResourceQueueElement, LimitingResourceQueueDependency> subGraph) {
|
||||
return new CycleDetector<LimitingResourceQueueElement, LimitingResourceQueueDependency>(
|
||||
subGraph);
|
||||
}
|
||||
|
||||
private List<LimitingResourceQueueElement> getElementsOrderedTopologically(
|
||||
DirectedGraph<LimitingResourceQueueElement, LimitingResourceQueueDependency> subGraph) {
|
||||
return onlyAssigned(toList(topologicalIterator(subGraph)));
|
||||
}
|
||||
|
||||
private TopologicalOrderIterator<LimitingResourceQueueElement, LimitingResourceQueueDependency> topologicalIterator(
|
||||
DirectedGraph<LimitingResourceQueueElement, LimitingResourceQueueDependency> subGraph) {
|
||||
return new TopologicalOrderIterator<LimitingResourceQueueElement, LimitingResourceQueueDependency>(
|
||||
subGraph);
|
||||
}
|
||||
|
||||
private static <T> List<T> toList(final Iterator<T> iterator) {
|
||||
List<T> result = new ArrayList<T>();
|
||||
while (iterator.hasNext()) {
|
||||
result.add(iterator.next());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<LimitingResourceQueueElement> onlyAssigned(
|
||||
List<LimitingResourceQueueElement> list) {
|
||||
List<LimitingResourceQueueElement> result = new ArrayList<LimitingResourceQueueElement>();
|
||||
for (LimitingResourceQueueElement each : list) {
|
||||
if (!each.isDetached()) {
|
||||
result.add(each);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void unassignFromQueues(List<LimitingResourceQueueElement> result) {
|
||||
for (LimitingResourceQueueElement each : result) {
|
||||
if (!each.isDetached()) {
|
||||
unassingFromQueue(each);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue