Create CriticalPathProgress object, for storing critical path progress

Stores critical path progress duration (by days and by numHours) for a
TaskRoot element

FEA: ItEr63OTS07ReporteAvancesCadeaCritica
This commit is contained in:
Diego Pino Garcia 2010-11-19 15:32:48 +01:00
parent 69083ab87e
commit b3adf2c64c
5 changed files with 220 additions and 68 deletions

View file

@ -0,0 +1,101 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.business.planner.entities;
import java.math.BigDecimal;
import java.util.List;
import org.navalplanner.business.common.BaseEntity;
/**
*
* @author Diego Pino García<dpino@igalia.com>
*
*/
public class CriticalPathProgress extends BaseEntity {
public static CriticalPathProgress create(TaskGroup rootTask) {
return new CriticalPathProgress(rootTask);
}
private TaskGroup rootTask;
private BigDecimal byDuration;
private BigDecimal byNumHours;
protected CriticalPathProgress() {
}
public BigDecimal getByDuration() {
return byDuration;
}
public BigDecimal getByNumHours() {
return byNumHours;
}
private CriticalPathProgress(TaskGroup rootTask) {
this.rootTask = rootTask;
}
public void update(List<Task> criticalPath) {
byDuration = calculateByDuration(criticalPath);
byNumHours = calculateByNumHours(criticalPath);
}
private BigDecimal calculateByDuration(List<Task> criticalPath) {
Integer totalDuration = new Integer(0), duration;
BigDecimal totalProgress = BigDecimal.ZERO, progress;
for (Task each: criticalPath) {
duration = each.getWorkableDays();
progress = each.getAdvancePercentage();
progress = progress.multiply(BigDecimal.valueOf(duration));
totalDuration = totalDuration + duration;
totalProgress = totalProgress.add(progress);
}
return totalProgress.divide(BigDecimal.valueOf(totalDuration), 8,
BigDecimal.ROUND_HALF_EVEN);
}
private BigDecimal calculateByNumHours(List<Task> criticalPath) {
int totalNumHours = 0, numHours;
BigDecimal totalProgress = BigDecimal.ZERO, progress;
for (Task each: criticalPath) {
numHours = each.getAssignedHours();
if (numHours == 0) {
numHours = each.getTotalHours();
}
progress = each.getAdvancePercentage();
progress = progress.multiply(BigDecimal.valueOf(numHours));
totalNumHours += numHours;
totalProgress = totalProgress.add(progress);
}
return totalProgress.divide(BigDecimal.valueOf(totalNumHours), 8,
BigDecimal.ROUND_HALF_EVEN);
}
}

View file

@ -20,6 +20,7 @@
package org.navalplanner.business.planner.entities;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -55,6 +56,22 @@ public class TaskGroup extends TaskElement {
}
private CriticalPathProgress criticalPathProgress;
public BigDecimal getCriticalPathProgressByDuration() {
if (criticalPathProgress == null) {
return BigDecimal.ZERO;
}
return criticalPathProgress.getByDuration();
}
public BigDecimal getCriticalPathProgressByNumHours() {
if (criticalPathProgress == null) {
return BigDecimal.ZERO;
}
return criticalPathProgress.getByNumHours();
}
@SuppressWarnings("unused")
@AssertTrue(message = "order element associated to a task group must be not null")
private boolean theOrderElementMustBeNotNull() {
@ -215,4 +232,12 @@ public class TaskGroup extends TaskElement {
return result;
}
public void updateCriticalPathProgress(List<Task> criticalPath) {
Validate.isTrue(getParent() == null);
if (criticalPathProgress == null) {
criticalPathProgress = CriticalPathProgress.create(this);
}
criticalPathProgress.update(criticalPath);
}
}

View file

@ -96,6 +96,8 @@
<joined-subclass name="TaskGroup">
<key column="TASK_ELEMENT_ID"></key>
<one-to-one name="criticalPathProgress" class="CriticalPathProgress" cascade="all" />
<!-- Indexed on the other side -->
<list name="taskElements" cascade="all">
<key column="parent" not-null="false"></key>
@ -118,6 +120,20 @@
</joined-subclass>
</class>
<!-- CriticalPathProgress -->
<class name="CriticalPathProgress" table="CRITICAL_PATH_PROGRESS">
<id name="id" column="CRITICAL_PATH_PROGRESS_ID">
<generator class="foreign">
<param name="property">rootTask</param>
</generator>
</id>
<one-to-one name="rootTask" class="TaskGroup" constrained="true"
cascade="all" lazy="false" />
<property name="byDuration" column="BY_DURATION" />
<property name="byNumHours" column="BY_NUM_HOURS" />
</class>
<class name="Dependency">
<id name="id" type="long" access="property">
<generator class="hilo"></generator>

View file

@ -395,8 +395,7 @@ public abstract class OrderPlanningModel implements IOrderPlanningModel {
setupLoadChart(chartLoadTimeplot, planner, configuration, saveCommand);
setupEarnedValueChart(chartEarnedValueTimeplot, earnedValueChartFiller, planner, configuration, saveCommand);
ProgressType progressType = configurationDAO.getConfiguration().getProgressType();
setupOverallProgress(chartComponent, progressType, planner, configuration, saveCommand);
setupOverallProgress(chartComponent, planner, configuration, saveCommand);
planner.addGraphChangeListenersFromConfiguration(configuration);
}
@ -510,9 +509,18 @@ public abstract class OrderPlanningModel implements IOrderPlanningModel {
setEventListenerConfigurationCheckboxes(earnedValueChart);
}
private void setupOverallProgress(Tabbox chartComponent,
final ProgressType progressType, Planner planner, PlannerConfiguration<TaskElement> configuration,
ISaveCommand saveCommand) {
private void setupOverallProgress(Tabbox chartComponent, Planner planner, PlannerConfiguration<TaskElement> configuration,
final ISaveCommand saveCommand) {
saveCommand.addListener(new IAfterSaveListener() {
@Override
public void onAfterSave() {
// FIXME: Should create overallProgressContent if it's null
if (overallProgressContent != null) {
overallProgressContent.update();
}
}
});
chartComponent.addEventListener(Events.ON_SELECT, new EventListener() {
@ -523,7 +531,7 @@ public abstract class OrderPlanningModel implements IOrderPlanningModel {
if (isOverAllProgressSelected(selectedTab)) {
if (overallProgressContent == null) {
final Tabpanel tabpanel = getSelectedPanel(selectedTab);
overallProgressContent = new OverAllProgressContent(tabpanel, progressType);
overallProgressContent = new OverAllProgressContent(tabpanel);
}
overallProgressContent.update();
}
@ -1553,7 +1561,7 @@ public abstract class OrderPlanningModel implements IOrderPlanningModel {
private Label lbAdvancePercentage;
public OverAllProgressContent(Tabpanel tabpanel, ProgressType progressType) {
public OverAllProgressContent(Tabpanel tabpanel) {
progressCriticalPathByDuration = (Progressmeter) tabpanel.getFellowIfAny("progressCriticalPathByDuration");
lbCriticalPathByDuration = (Label) tabpanel.getFellowIfAny("lbCriticalPathByDuration");
progressCriticalPathByNumHours = (Progressmeter) tabpanel.getFellowIfAny("progressCriticalPathByNumHours");

View file

@ -148,8 +148,8 @@ public class SaveCommand implements ISaveCommand {
private void notifyUserThatSavingIsDone() {
try {
Messagebox.show(_("Scheduling saved"), _("Information"), Messagebox.OK,
Messagebox.INFORMATION);
Messagebox.show(_("Scheduling saved"), _("Information"),
Messagebox.OK, Messagebox.INFORMATION);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
@ -193,18 +193,18 @@ public class SaveCommand implements ISaveCommand {
}
private void saveRootTaskIfNecessary() {
TaskGroup rootTask = state.getRootTask();
if (!state.getTasksToSave().isEmpty()) {
TaskGroup rootTask = state.getRootTask();
updateRootTaskPosition(rootTask);
updateCriticalPathProgress(rootTask);
taskElementDAO.save(rootTask);
}
updateCriticalPathProgress(rootTask);
taskElementDAO.save(rootTask);
}
private void updateCriticalPathProgress(TaskGroup rootTask) {
List criticalPath = state.getPlanner().getCriticalPath();
BigDecimal byDuration = CriticalPathProgress.calculateByDuration(criticalPath);
System.out.println("### updateCriticalPathProgress: " + byDuration);
final List<Task> criticalPath = state.getPlanner().getCriticalPath();
rootTask.updateCriticalPathProgress(criticalPath);
}
private void updateRootTaskPosition(TaskGroup rootTask) {
@ -243,10 +243,9 @@ public class SaveCommand implements ISaveCommand {
private void updateLimitingResourceQueueElementDates(Task task) {
LimitingResourceQueueElement limiting = task
.getAssociatedLimitingResourceQueueElementIfAny();
Date initDate = state
.getRootTask().getOrderElement().getInitDate();
limiting.updateDates(initDate, task
.getDependenciesWithThisDestination());
Date initDate = state.getRootTask().getOrderElement().getInitDate();
limiting.updateDates(initDate,
task.getDependenciesWithThisDestination());
}
private void removeEmptyConsolidation(TaskElement taskElement) {
@ -270,24 +269,24 @@ public class SaveCommand implements ISaveCommand {
private boolean isEmptyConsolidation(final Consolidation consolidation) {
return transactionService
.runOnTransaction(new IOnTransaction<Boolean>() {
@Override
public Boolean execute() {
@Override
public Boolean execute() {
consolidationDAO.reattach(consolidation);
if (consolidation instanceof CalculatedConsolidation) {
SortedSet<CalculatedConsolidatedValue> consolidatedValues = ((CalculatedConsolidation) consolidation)
.getCalculatedConsolidatedValues();
return consolidatedValues.isEmpty();
}
if (consolidation instanceof NonCalculatedConsolidation) {
SortedSet<NonCalculatedConsolidatedValue> consolidatedValues = ((NonCalculatedConsolidation) consolidation)
.getNonCalculatedConsolidatedValues();
return consolidatedValues.isEmpty();
}
return false;
consolidationDAO.reattach(consolidation);
if (consolidation instanceof CalculatedConsolidation) {
SortedSet<CalculatedConsolidatedValue> consolidatedValues = ((CalculatedConsolidation) consolidation)
.getCalculatedConsolidatedValues();
return consolidatedValues.isEmpty();
}
if (consolidation instanceof NonCalculatedConsolidation) {
SortedSet<NonCalculatedConsolidatedValue> consolidatedValues = ((NonCalculatedConsolidation) consolidation)
.getNonCalculatedConsolidatedValues();
return consolidatedValues.isEmpty();
}
return false;
}
});
}
});
}
// newly added TaskElement such as milestones must be called
@ -298,7 +297,8 @@ public class SaveCommand implements ISaveCommand {
}
dontPoseAsTransient(taskElement.getDependenciesWithThisOrigin());
dontPoseAsTransient(taskElement.getDependenciesWithThisDestination());
Set<ResourceAllocation<?>> resourceAllocations = taskElement.getSatisfiedResourceAllocations();
Set<ResourceAllocation<?>> resourceAllocations = taskElement
.getSatisfiedResourceAllocations();
dontPoseAsTransientAndChildrenObjects(resourceAllocations);
if (!taskElement.isLeaf()) {
for (TaskElement each : taskElement.getChildren()) {
@ -320,19 +320,19 @@ public class SaveCommand implements ISaveCommand {
private void updateLimitingQueueDependencies(Task t) {
for (Dependency each: t.getDependenciesWithThisOrigin()) {
for (Dependency each : t.getDependenciesWithThisOrigin()) {
addLimitingDependencyIfNeeded(each);
removeLimitingDependencyIfNeeded(each);
}
}
private void addLimitingDependencyIfNeeded(Dependency d) {
if (d.isDependencyBetweenLimitedAllocatedTasks() &&
!d.hasLimitedQueueDependencyAssociated()) {
LimitingResourceQueueElement origin =
calculateQueueElementFromDependency((Task) d.getOrigin());
LimitingResourceQueueElement destiny =
calculateQueueElementFromDependency((Task) d.getDestination());
if (d.isDependencyBetweenLimitedAllocatedTasks()
&& !d.hasLimitedQueueDependencyAssociated()) {
LimitingResourceQueueElement origin = calculateQueueElementFromDependency((Task) d
.getOrigin());
LimitingResourceQueueElement destiny = calculateQueueElementFromDependency((Task) d
.getDestination());
LimitingResourceQueueDependency queueDependency = LimitingResourceQueueDependency
.create(origin, destiny, d,
@ -343,20 +343,21 @@ public class SaveCommand implements ISaveCommand {
}
}
private LimitingResourceQueueElement
calculateQueueElementFromDependency(Task t) {
private LimitingResourceQueueElement calculateQueueElementFromDependency(
Task t) {
LimitingResourceQueueElement result = null;
// TODO: Improve this method: One Task can only have one
// limiting resource allocation
Set<ResourceAllocation<?>> allocations = t.getLimitingResourceAllocations();
Set<ResourceAllocation<?>> allocations = t
.getLimitingResourceAllocations();
if (allocations.isEmpty() || allocations.size() != 1) {
throw new ValidationException("Incorrect limiting resource " +
"allocation configuration");
throw new ValidationException("Incorrect limiting resource "
+ "allocation configuration");
}
for (ResourceAllocation<?> r: allocations) {
for (ResourceAllocation<?> r : allocations) {
result = r.getLimitingResourceQueueElement();
}
@ -364,22 +365,22 @@ public class SaveCommand implements ISaveCommand {
}
private void removeLimitingDependencyIfNeeded(Dependency d) {
if (!d.isDependencyBetweenLimitedAllocatedTasks() &&
(d.hasLimitedQueueDependencyAssociated())) {
LimitingResourceQueueDependency queueDependency =
d.getQueueDependency();
queueDependency.getHasAsOrigin().remove(queueDependency);
queueDependency.getHasAsDestiny().remove(queueDependency);
d.setQueueDependency(null);
try {
limitingResourceQueueDependencyDAO.
remove(queueDependency.getId());
} catch (InstanceNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("Trying to delete instance " +
" does not exist");
}
if (!d.isDependencyBetweenLimitedAllocatedTasks()
&& (d.hasLimitedQueueDependencyAssociated())) {
LimitingResourceQueueDependency queueDependency = d
.getQueueDependency();
queueDependency.getHasAsOrigin().remove(queueDependency);
queueDependency.getHasAsDestiny().remove(queueDependency);
d.setQueueDependency(null);
try {
limitingResourceQueueDependencyDAO.remove(queueDependency
.getId());
} catch (InstanceNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("Trying to delete instance "
+ " does not exist");
}
}
}
private void dontPoseAsTransient(OrderElement orderElement) {
@ -468,10 +469,12 @@ public class SaveCommand implements ISaveCommand {
private static void dontPoseAsTransient(LimitingResourceQueueElement element) {
if (element != null) {
for (LimitingResourceQueueDependency d: element.getDependenciesAsOrigin()) {
for (LimitingResourceQueueDependency d : element
.getDependenciesAsOrigin()) {
d.dontPoseAsTransientObjectAnymore();
}
for (LimitingResourceQueueDependency d: element.getDependenciesAsDestiny()) {
for (LimitingResourceQueueDependency d : element
.getDependenciesAsDestiny()) {
d.dontPoseAsTransientObjectAnymore();
}
element.dontPoseAsTransientObjectAnymore();
@ -538,8 +541,7 @@ public class SaveCommand implements ISaveCommand {
private boolean userAcceptsCreateANewOrderVersion() {
try {
int status = Messagebox
.show(
_("Confirm creating a new order version for this scenario and derived. Are you sure?"),
.show(_("Confirm creating a new order version for this scenario and derived. Are you sure?"),
_("New order version"), Messagebox.OK
| Messagebox.CANCEL, Messagebox.QUESTION);
return (Messagebox.OK == status);