From 4d79e2d212522eb771a83899590c7b926ee1ed79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Gonz=C3=A1lez=20Fern=C3=A1ndez?= Date: Tue, 6 Sep 2011 17:32:44 +0200 Subject: [PATCH] Make TaskElementAdapter a singleton FEA: ItEr75S11PreventLooseChanges --- .../resources/daos/ResourcesSearcher.java | 2 +- .../web/planner/ITaskElementAdapter.java | 45 - .../web/planner/TaskElementAdapter.java | 1438 +++++++++-------- .../planner/company/CompanyPlanningModel.java | 14 +- .../web/planner/order/OrderPlanningModel.java | 14 +- 5 files changed, 745 insertions(+), 768 deletions(-) delete mode 100644 navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ITaskElementAdapter.java diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourcesSearcher.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourcesSearcher.java index d98c2be11..a8f630880 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourcesSearcher.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourcesSearcher.java @@ -56,7 +56,7 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; @Service -@Scope(BeanDefinition.SCOPE_PROTOTYPE) +@Scope(BeanDefinition.SCOPE_SINGLETON) /** * @author Diego Pino Garcia */ diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ITaskElementAdapter.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ITaskElementAdapter.java deleted file mode 100644 index c6da8c5ad..000000000 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ITaskElementAdapter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of NavalPlan - * - * Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e - * Desenvolvemento Tecnolóxico de Galicia - * Copyright (C) 2010-2011 Igalia, S.L. - * - * 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 . - */ - -package org.navalplanner.web.planner; - -import org.joda.time.LocalDate; -import org.navalplanner.business.planner.entities.TaskElement; -import org.navalplanner.business.scenarios.entities.Scenario; -import org.zkoss.ganttz.adapters.IAdapterToTaskFundamentalProperties; - -/** - * Contract for {@link TaskElementAdapter}
- * @author Óscar González Fernández - */ -public interface ITaskElementAdapter extends IAdapterToTaskFundamentalProperties{ - - void useScenario(Scenario scenario); - - void setInitDate(LocalDate initDate); - - void setDeadline(LocalDate deadline); - - void setPreventCalculateResourcesText(boolean preventCalculateResourcesText); - - boolean isPreventCalculateResourcesText(); - -} diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/TaskElementAdapter.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/TaskElementAdapter.java index 058a56513..e1f9cce60 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/TaskElementAdapter.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/TaskElementAdapter.java @@ -92,6 +92,7 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.zkoss.ganttz.IDatesMapper; import org.zkoss.ganttz.adapters.DomainDependency; +import org.zkoss.ganttz.adapters.IAdapterToTaskFundamentalProperties; import org.zkoss.ganttz.data.DependencyType; import org.zkoss.ganttz.data.GanttDate; import org.zkoss.ganttz.data.GanttDate.Cases; @@ -99,33 +100,22 @@ import org.zkoss.ganttz.data.GanttDate.CustomDate; import org.zkoss.ganttz.data.GanttDate.LocalDateBased; import org.zkoss.ganttz.data.ITaskFundamentalProperties; import org.zkoss.ganttz.data.constraint.Constraint; + /** - * Responsible of adaptating a {@link TaskElement} into a - * {@link ITaskFundamentalProperties}
* @author Óscar González Fernández */ @Component -@Scope(BeanDefinition.SCOPE_PROTOTYPE) -public class TaskElementAdapter implements ITaskElementAdapter { +@Scope(BeanDefinition.SCOPE_SINGLETON) +public class TaskElementAdapter { private static final Log LOG = LogFactory.getLog(TaskElementAdapter.class); - private boolean preventCalculateResourcesText = false; - - public boolean isPreventCalculateResourcesText() { - return preventCalculateResourcesText; - } - - public void setPreventCalculateResourcesText( - boolean preventCalculateResourcesText) { - this.preventCalculateResourcesText = preventCalculateResourcesText; - } - public static List> getStartConstraintsFor( TaskElement taskElement, LocalDate orderInitDate) { if (taskElement instanceof ITaskPositionConstrained) { ITaskPositionConstrained task = (ITaskPositionConstrained) taskElement; - TaskPositionConstraint startConstraint = task.getPositionConstraint(); + TaskPositionConstraint startConstraint = task + .getPositionConstraint(); final PositionConstraintType constraintType = startConstraint .getConstraintType(); switch (constraintType) { @@ -138,7 +128,7 @@ public class TaskElementAdapter implements ITaskElementAdapter { case START_IN_FIXED_DATE: return Collections .singletonList(equalTo(toGantt(startConstraint - .getConstraintDate()))); + .getConstraintDate()))); case START_NOT_EARLIER_THAN: return Collections .singletonList(biggerOrEqualThan(toGantt(startConstraint @@ -168,52 +158,6 @@ public class TaskElementAdapter implements ITaskElementAdapter { return Collections.emptyList(); } - @Autowired - private IAdHocTransactionService transactionService; - - @Autowired - private IOrderElementDAO orderElementDAO; - - @Autowired - private ITaskElementDAO taskDAO; - - @Autowired - private ICriterionDAO criterionDAO; - - @Autowired - private IResourceAllocationDAO resourceAllocationDAO; - - @Autowired - private IResourcesSearcher searcher; - - @Autowired - private IConfigurationDAO configurationDAO; - - private Scenario scenario; - - private LocalDate initDate; - - private LocalDate deadline; - - - @Override - public void useScenario(Scenario scenario) { - this.scenario = scenario; - } - - @Override - public void setInitDate(LocalDate initDate) { - this.initDate = initDate; - } - - @Override - public void setDeadline(LocalDate deadline) { - this.deadline = deadline; - } - - public TaskElementAdapter() { - } - public static GanttDate toGantt(IntraDayDate date) { return toGantt(date, null); } @@ -256,6 +200,48 @@ public class TaskElementAdapter implements ITaskElementAdapter { }); } + public IAdapterToTaskFundamentalProperties createForCompany( + Scenario currentScenario) { + Adapter result = new Adapter(); + result.useScenario(currentScenario); + result.setPreventCalculateResourcesText(true); + return result; + } + + public IAdapterToTaskFundamentalProperties createForOrder( + Scenario currentScenario, Order order) { + Adapter result = new Adapter(); + result.useScenario(currentScenario); + result.setInitDate(asLocalDate(order.getInitDate())); + result.setDeadline(asLocalDate(order.getDeadline())); + return result; + } + + private LocalDate asLocalDate(Date date) { + return date != null ? LocalDate.fromDateFields(date) : null; + } + + @Autowired + private IAdHocTransactionService transactionService; + + @Autowired + private IOrderElementDAO orderElementDAO; + + @Autowired + private ITaskElementDAO taskDAO; + + @Autowired + private ICriterionDAO criterionDAO; + + @Autowired + private IResourceAllocationDAO resourceAllocationDAO; + + @Autowired + private IResourcesSearcher searcher; + + @Autowired + private IConfigurationDAO configurationDAO; + static class GanttDateAdapter extends CustomDate { private static final int DAY_MILLISECONDS = (int) Days.days(1) @@ -341,13 +327,14 @@ public class TaskElementAdapter implements ITaskElementAdapter { @SuppressWarnings("unchecked") private Fraction fractionOfWorkingDayFor(EffortDuration effortDuration) { Duration durationInDay = toMilliseconds(effortDuration); - // cast to int is safe because there are not enough seconds in day + // cast to int is safe because there are not enough seconds in + // day // to overflow Fraction fraction = Fraction.getFraction( (int) durationInDay.getStandardSeconds(), (int) workingDayDuration.getStandardSeconds()); - return (Fraction) Collections.min(Arrays - .asList(fraction, Fraction.ONE)); + return (Fraction) Collections.min(Arrays.asList(fraction, + Fraction.ONE)); } private static Duration toMilliseconds(EffortDuration duration) { @@ -355,751 +342,796 @@ public class TaskElementAdapter implements ITaskElementAdapter { } } - private class TaskElementWrapper implements ITaskFundamentalProperties { + /** + * Responsible of adaptating a {@link TaskElement} into a + * {@link ITaskFundamentalProperties}
+ * @author Óscar González Fernández + */ + public class Adapter implements + IAdapterToTaskFundamentalProperties { - private final TaskElement taskElement; + private Scenario scenario; - private final Scenario currentScenario; + private LocalDate initDate; - protected TaskElementWrapper(Scenario currentScenario, - TaskElement taskElement) { - Validate.notNull(currentScenario); - this.currentScenario = currentScenario; - this.taskElement = taskElement; + private LocalDate deadline; + + private boolean preventCalculateResourcesText = false; + + private void useScenario(Scenario scenario) { + this.scenario = scenario; } - @Override - public void setName(String name) { - taskElement.setName(name); + private void setInitDate(LocalDate initDate) { + this.initDate = initDate; } - @Override - public void setNotes(String notes) { - taskElement.setNotes(notes); + private void setDeadline(LocalDate deadline) { + this.deadline = deadline; } - @Override - public String getName() { - return taskElement.getName(); + public boolean isPreventCalculateResourcesText() { + return preventCalculateResourcesText; } - @Override - public String getNotes() { - return taskElement.getNotes(); + public void setPreventCalculateResourcesText( + boolean preventCalculateResourcesText) { + this.preventCalculateResourcesText = preventCalculateResourcesText; } - @Override - public GanttDate getBeginDate() { - IntraDayDate start = taskElement.getIntraDayStartDate(); - return toGantt(start); + public Adapter() { } - private GanttDate toGantt(IntraDayDate date) { - BaseCalendar calendar = taskElement.getCalendar(); - if (calendar == null) { - return TaskElementAdapter.toGantt(date); + + private class TaskElementWrapper implements ITaskFundamentalProperties { + + private final TaskElement taskElement; + + private final Scenario currentScenario; + + protected TaskElementWrapper(Scenario currentScenario, + TaskElement taskElement) { + Validate.notNull(currentScenario); + this.currentScenario = currentScenario; + this.taskElement = taskElement; } - return TaskElementAdapter - .toGantt(date, calendar.getCapacityOn(PartialDay - .wholeDay(date.getDate()))); - } - @Override - public void setBeginDate(final GanttDate beginDate) { - transactionService - .runOnReadOnlyTransaction(new IOnTransaction() { - @Override - public Void execute() { - stepsBeforePossibleReallocation(); - getDatesHandler(taskElement).moveTo( - toIntraDay(beginDate)); - return null; - } - }); - } + @Override + public void setName(String name) { + taskElement.setName(name); + } - @Override - public GanttDate getEndDate() { - return toGantt(taskElement.getIntraDayEndDate()); - } + @Override + public void setNotes(String notes) { + taskElement.setNotes(notes); + } - @Override - public void setEndDate(final GanttDate endDate) { - transactionService - .runOnReadOnlyTransaction(new IOnTransaction() { - @Override - public Void execute() { - stepsBeforePossibleReallocation(); - getDatesHandler(taskElement).moveEndTo( - toIntraDay(endDate)); - return null; - } - }); - } + @Override + public String getName() { + return taskElement.getName(); + } - @Override - public void resizeTo(final GanttDate endDate) { - transactionService - .runOnReadOnlyTransaction(new IOnTransaction() { - @Override - public Void execute() { - stepsBeforePossibleReallocation(); - updateTaskPositionConstraint(endDate); - getDatesHandler(taskElement).resizeTo( - toIntraDay(endDate)); - return null; - } - }); - } + @Override + public String getNotes() { + return taskElement.getNotes(); + } - IDatesHandler getDatesHandler(TaskElement taskElement) { - return taskElement.getDatesHandler(currentScenario, searcher); - } + @Override + public GanttDate getBeginDate() { + IntraDayDate start = taskElement.getIntraDayStartDate(); + return toGantt(start); + } - private void updateTaskPositionConstraint(GanttDate endDate) { - if (taskElement instanceof ITaskPositionConstrained) { - ITaskPositionConstrained task = (ITaskPositionConstrained) taskElement; - PositionConstraintType constraintType = task - .getPositionConstraint().getConstraintType(); - if (constraintType - .compareTo(PositionConstraintType.FINISH_NOT_LATER_THAN) == 0 - || constraintType - .compareTo(PositionConstraintType.AS_LATE_AS_POSSIBLE) == 0) { - task.explicityMoved(toIntraDay(endDate)); + private GanttDate toGantt(IntraDayDate date) { + BaseCalendar calendar = taskElement.getCalendar(); + if (calendar == null) { + return TaskElementAdapter.toGantt(date); } - } - } - - @Override - public GanttDate getHoursAdvanceEndDate() { - OrderElement orderElement = taskElement.getOrderElement(); - - EffortDuration assignedEffort = EffortDuration.zero(); - if (orderElement.getSumChargedEffort() != null) { - assignedEffort = orderElement.getSumChargedEffort() - .getTotalChargedEffort(); + return TaskElementAdapter.toGantt(date, calendar + .getCapacityOn(PartialDay.wholeDay(date.getDate()))); } - GanttDate result = null; - if(!(taskElement instanceof TaskGroup)) { - result = calculateLimitDate(assignedEffort - .toHoursAsDecimalWithScale(2)); + @Override + public void setBeginDate(final GanttDate beginDate) { + transactionService + .runOnReadOnlyTransaction(new IOnTransaction() { + @Override + public Void execute() { + stepsBeforePossibleReallocation(); + getDatesHandler(taskElement).moveTo( + toIntraDay(beginDate)); + return null; + } + }); } - if (result == null) { - Integer hours = taskElement.getSumOfHoursAllocated(); - if (hours == 0) { - hours = orderElement.getWorkHours(); - if (hours == 0) { - return getBeginDate(); + @Override + public GanttDate getEndDate() { + return toGantt(taskElement.getIntraDayEndDate()); + } + + @Override + public void setEndDate(final GanttDate endDate) { + transactionService + .runOnReadOnlyTransaction(new IOnTransaction() { + @Override + public Void execute() { + stepsBeforePossibleReallocation(); + getDatesHandler(taskElement).moveEndTo( + toIntraDay(endDate)); + return null; + } + }); + } + + @Override + public void resizeTo(final GanttDate endDate) { + transactionService + .runOnReadOnlyTransaction(new IOnTransaction() { + @Override + public Void execute() { + stepsBeforePossibleReallocation(); + updateTaskPositionConstraint(endDate); + getDatesHandler(taskElement).resizeTo( + toIntraDay(endDate)); + return null; + } + }); + } + + IDatesHandler getDatesHandler(TaskElement taskElement) { + return taskElement.getDatesHandler(currentScenario, searcher); + } + + private void updateTaskPositionConstraint(GanttDate endDate) { + if (taskElement instanceof ITaskPositionConstrained) { + ITaskPositionConstrained task = (ITaskPositionConstrained) taskElement; + PositionConstraintType constraintType = task + .getPositionConstraint().getConstraintType(); + if (constraintType + .compareTo(PositionConstraintType.FINISH_NOT_LATER_THAN) == 0 + || constraintType + .compareTo(PositionConstraintType.AS_LATE_AS_POSSIBLE) == 0) { + task.explicityMoved(toIntraDay(endDate)); } } - BigDecimal percentage = assignedEffort - .toHoursAsDecimalWithScale(2).divide( - new BigDecimal(hours), - RoundingMode.DOWN); - result = calculateLimitDate(percentage); - } - return result; - } + @Override + public GanttDate getHoursAdvanceEndDate() { + OrderElement orderElement = taskElement.getOrderElement(); - @Override - public BigDecimal getHoursAdvancePercentage() { - OrderElement orderElement = taskElement.getOrderElement(); - if (orderElement == null) { - return BigDecimal.ZERO; + EffortDuration assignedEffort = EffortDuration.zero(); + if (orderElement.getSumChargedEffort() != null) { + assignedEffort = orderElement.getSumChargedEffort() + .getTotalChargedEffort(); + } + + GanttDate result = null; + if (!(taskElement instanceof TaskGroup)) { + result = calculateLimitDate(assignedEffort + .toHoursAsDecimalWithScale(2)); + } + if (result == null) { + Integer hours = taskElement.getSumOfHoursAllocated(); + + if (hours == 0) { + hours = orderElement.getWorkHours(); + if (hours == 0) { + return getBeginDate(); + } + } + BigDecimal percentage = assignedEffort + .toHoursAsDecimalWithScale(2).divide( + new BigDecimal(hours)); + result = calculateLimitDate(percentage); + + } + + return result; } - EffortDuration totalChargedEffort = orderElement - .getSumChargedEffort() != null ? orderElement - .getSumChargedEffort().getTotalChargedEffort() - : EffortDuration.zero(); - BigDecimal assignedHours = totalChargedEffort - .toHoursAsDecimalWithScale(2); - - BigDecimal estimatedHours = new BigDecimal(taskElement.getSumOfHoursAllocated()) - .setScale(2); - - if (estimatedHours.compareTo(BigDecimal.ZERO) <= 0) { - estimatedHours = new BigDecimal(orderElement.getWorkHours()) - .setScale(2); - if (estimatedHours.compareTo(BigDecimal.ZERO) <= 0) { + @Override + public BigDecimal getHoursAdvancePercentage() { + OrderElement orderElement = taskElement.getOrderElement(); + if (orderElement == null) { return BigDecimal.ZERO; } - } - return assignedHours.divide(estimatedHours, RoundingMode.DOWN); - } - @Override - public GanttDate getAdvanceEndDate(String progressType) { - return getAdvanceEndDate(ProgressType.asEnum(progressType)); - } + EffortDuration totalChargedEffort = orderElement + .getSumChargedEffort() != null ? orderElement + .getSumChargedEffort().getTotalChargedEffort() + : EffortDuration.zero(); + BigDecimal assignedHours = totalChargedEffort + .toHoursAsDecimalWithScale(2); - private GanttDate getAdvanceEndDate(ProgressType progressType) { - BigDecimal advancePercentage = BigDecimal.ZERO; - if (taskElement.getOrderElement() != null) { - advancePercentage = taskElement - .getAdvancePercentage(progressType); - } - return getAdvanceEndDate(advancePercentage); - } + BigDecimal estimatedHours = new BigDecimal( + taskElement.getSumOfHoursAllocated()).setScale(2); - @Override - public GanttDate getAdvanceEndDate() { - BigDecimal advancePercentage = BigDecimal.ZERO; - - if (taskElement.getOrderElement() != null) { - if (isTaskRoot(taskElement)) { - ProgressType progressType = getProgressTypeFromConfiguration(); - advancePercentage = taskElement.getAdvancePercentage(progressType); - - } else { - advancePercentage = taskElement.getAdvancePercentage(); - } - } - return getAdvanceEndDate(advancePercentage); - } - - private boolean isTaskRoot(TaskElement taskElement) { - return taskElement instanceof TaskGroup && taskElement.getParent() == null; - } - - private ProgressType getProgressTypeFromConfiguration() { - return transactionService - .runOnReadOnlyTransaction(new IOnTransaction() { - @Override - public ProgressType execute() { - return configurationDAO.getConfiguration() - .getProgressType(); - } - }); - } - - private GanttDate getAdvanceEndDate(BigDecimal advancePercentage) { - Integer hours = Integer.valueOf(0); - if (taskElement.getOrderElement() != null) { - hours = taskElement.getSumOfHoursAllocated(); - } - - if (taskElement instanceof TaskGroup) { - return calculateLimitDate(advancePercentage); - } - - // Calculate date according to advanceHours or advancePercentage - final Integer advanceHours = advancePercentage.multiply( - new BigDecimal(hours)).intValue(); - GanttDate result = calculateLimitDate(advanceHours); - if (result == null) { - result = calculateLimitDate(advancePercentage); - } - return result; - } - - private GanttDate calculateLimitDate(BigDecimal advancePercentage) { - BaseCalendar calendar = taskElement.getCalendar(); - if (advancePercentage.compareTo(BigDecimal.ZERO) == 0 || calendar==null) { - return getBeginDate(); - } - IntraDayDate start = taskElement.getIntraDayStartDate(); - IntraDayDate end = taskElement.getIntraDayEndDate(); - int daysBetween = start.numberOfDaysUntil(end); - if (daysBetween == 0) { - return calculateLimitDateWhenDaysBetweenAreZero(advancePercentage); - } - int daysAdvance = advancePercentage.multiply( - new BigDecimal(daysBetween)) - .intValue(); - return GanttDate.createFrom(taskElement.getIntraDayStartDate() - .getDate().plusDays(daysAdvance)); - } - - private GanttDate calculateLimitDateWhenDaysBetweenAreZero( - BigDecimal advancePercentage) { - IntraDayDate start = taskElement.getIntraDayStartDate(); - IntraDayDate end = taskElement.getIntraDayEndDate(); - final BaseCalendar calendar = taskElement.getCalendar(); - Iterable daysUntil = start.daysUntil(end); - - EffortDuration total = EffortDuration.sum(daysUntil, - new IEffortFrom() { - @Override - public EffortDuration from(PartialDay each) { - return calendar.getCapacityOn(each); - } - }); - - BigDecimal totalAsSeconds = new BigDecimal(total - .getSeconds()); - EffortDuration advanceLeft = seconds(advancePercentage.multiply( - totalAsSeconds).intValue()); - for (PartialDay each : daysUntil) { - if (advanceLeft.compareTo(calendar.getCapacityOn(each)) <= 0) { - LocalDate dayDate = each.getStart().getDate(); - if (dayDate.equals(start.getDate())) { - return toGantt(IntraDayDate.create(dayDate, - advanceLeft.plus(start.getEffortDuration()))); + if (estimatedHours.compareTo(BigDecimal.ZERO) <= 0) { + estimatedHours = new BigDecimal(orderElement.getWorkHours()) + .setScale(2); + if (estimatedHours.compareTo(BigDecimal.ZERO) <= 0) { + return BigDecimal.ZERO; } - return toGantt(IntraDayDate.create(dayDate, advanceLeft)); } - advanceLeft = advanceLeft.minus(calendar.getCapacityOn(each)); + return assignedHours.divide(estimatedHours, RoundingMode.DOWN); } - return toGantt(end); - } - private GanttDate calculateLimitDate(Integer hours) { - if (hours == null || hours == 0) { - return null; + @Override + public GanttDate getAdvanceEndDate(String progressType) { + return getAdvanceEndDate(ProgressType.asEnum(progressType)); } - EffortDuration hoursLeft = hours(hours); - IntraDayDate result = null; - EffortDuration effortLastDayNotZero = zero(); - Map daysMap = taskElement - .getDurationsAssignedByDay(); - if (daysMap.isEmpty()) { - return null; - } - for (Entry entry : daysMap.entrySet()) { - if (!entry.getValue().isZero()) { - effortLastDayNotZero = entry.getValue(); + private GanttDate getAdvanceEndDate(ProgressType progressType) { + BigDecimal advancePercentage = BigDecimal.ZERO; + if (taskElement.getOrderElement() != null) { + advancePercentage = taskElement + .getAdvancePercentage(progressType); } - EffortDuration decrement = min(entry.getValue(), hoursLeft); - hoursLeft = hoursLeft.minus(decrement); - if (hoursLeft.isZero()) { - if (decrement.equals(entry.getValue())) { + return getAdvanceEndDate(advancePercentage); + } + + @Override + public GanttDate getAdvanceEndDate() { + BigDecimal advancePercentage = BigDecimal.ZERO; + + if (taskElement.getOrderElement() != null) { + if (isTaskRoot(taskElement)) { + ProgressType progressType = getProgressTypeFromConfiguration(); + advancePercentage = taskElement + .getAdvancePercentage(progressType); + + } else { + advancePercentage = taskElement.getAdvancePercentage(); + } + } + return getAdvanceEndDate(advancePercentage); + } + + private boolean isTaskRoot(TaskElement taskElement) { + return taskElement instanceof TaskGroup + && taskElement.getParent() == null; + } + + private ProgressType getProgressTypeFromConfiguration() { + return transactionService + .runOnReadOnlyTransaction(new IOnTransaction() { + @Override + public ProgressType execute() { + return configurationDAO.getConfiguration() + .getProgressType(); + } + }); + } + + private GanttDate getAdvanceEndDate(BigDecimal advancePercentage) { + Integer hours = Integer.valueOf(0); + if (taskElement.getOrderElement() != null) { + hours = taskElement.getSumOfHoursAllocated(); + } + + if (taskElement instanceof TaskGroup) { + return calculateLimitDate(advancePercentage); + } + + // Calculate date according to advanceHours or advancePercentage + final Integer advanceHours = advancePercentage.multiply( + new BigDecimal(hours)).intValue(); + GanttDate result = calculateLimitDate(advanceHours); + if (result == null) { + result = calculateLimitDate(advancePercentage); + } + return result; + } + + private GanttDate calculateLimitDate(BigDecimal advancePercentage) { + BaseCalendar calendar = taskElement.getCalendar(); + if (advancePercentage.compareTo(BigDecimal.ZERO) == 0 + || calendar == null) { + return getBeginDate(); + } + IntraDayDate start = taskElement.getIntraDayStartDate(); + IntraDayDate end = taskElement.getIntraDayEndDate(); + int daysBetween = start.numberOfDaysUntil(end); + if (daysBetween == 0) { + return calculateLimitDateWhenDaysBetweenAreZero(advancePercentage); + } + int daysAdvance = advancePercentage.multiply( + new BigDecimal(daysBetween)).intValue(); + return GanttDate.createFrom(taskElement.getIntraDayStartDate() + .getDate().plusDays(daysAdvance)); + } + + private GanttDate calculateLimitDateWhenDaysBetweenAreZero( + BigDecimal advancePercentage) { + IntraDayDate start = taskElement.getIntraDayStartDate(); + IntraDayDate end = taskElement.getIntraDayEndDate(); + final BaseCalendar calendar = taskElement.getCalendar(); + Iterable daysUntil = start.daysUntil(end); + + EffortDuration total = EffortDuration.sum(daysUntil, + new IEffortFrom() { + @Override + public EffortDuration from(PartialDay each) { + return calendar.getCapacityOn(each); + } + }); + + BigDecimal totalAsSeconds = new BigDecimal(total.getSeconds()); + EffortDuration advanceLeft = seconds(advancePercentage + .multiply(totalAsSeconds).intValue()); + for (PartialDay each : daysUntil) { + if (advanceLeft.compareTo(calendar.getCapacityOn(each)) <= 0) { + LocalDate dayDate = each.getStart().getDate(); + if (dayDate.equals(start.getDate())) { + return toGantt(IntraDayDate + .create(dayDate, advanceLeft.plus(start + .getEffortDuration()))); + } + return toGantt(IntraDayDate + .create(dayDate, advanceLeft)); + } + advanceLeft = advanceLeft.minus(calendar + .getCapacityOn(each)); + } + return toGantt(end); + } + + private GanttDate calculateLimitDate(Integer hours) { + if (hours == null || hours == 0) { + return null; + } + EffortDuration hoursLeft = hours(hours); + IntraDayDate result = null; + EffortDuration effortLastDayNotZero = zero(); + + Map daysMap = taskElement + .getDurationsAssignedByDay(); + if (daysMap.isEmpty()) { + return null; + } + for (Entry entry : daysMap + .entrySet()) { + if (!entry.getValue().isZero()) { + effortLastDayNotZero = entry.getValue(); + } + EffortDuration decrement = min(entry.getValue(), hoursLeft); + hoursLeft = hoursLeft.minus(decrement); + if (hoursLeft.isZero()) { + if (decrement.equals(entry.getValue())) { + result = IntraDayDate.startOfDay(entry.getKey() + .plusDays(1)); + } else { + result = IntraDayDate.create(entry.getKey(), + decrement); + } + break; + } else { result = IntraDayDate.startOfDay(entry.getKey() .plusDays(1)); - } else { - result = IntraDayDate.create(entry.getKey(), decrement); } - break; - } else { - result = IntraDayDate - .startOfDay(entry.getKey().plusDays(1)); } - } - if (!hoursLeft.isZero() && effortLastDayNotZero.isZero()) { - LOG.warn("limit not reached and no day with effort not zero"); - } - if (!hoursLeft.isZero() && !effortLastDayNotZero.isZero()) { - while (!hoursLeft.isZero()) { - hoursLeft = hoursLeft.minus(min(effortLastDayNotZero, - hoursLeft)); - result = result.nextDayAtStart(); + if (!hoursLeft.isZero() && effortLastDayNotZero.isZero()) { + LOG.warn("limit not reached and no day with effort not zero"); } + if (!hoursLeft.isZero() && !effortLastDayNotZero.isZero()) { + while (!hoursLeft.isZero()) { + hoursLeft = hoursLeft.minus(min(effortLastDayNotZero, + hoursLeft)); + result = result.nextDayAtStart(); + } + } + if (result == null) { + return null; + } + return toGantt(result); } - if (result == null) { - return null; - } - return toGantt(result); - } - @Override - public String getTooltipText() { - if (taskElement.isMilestone()) { - return ""; - } - return transactionService - .runOnReadOnlyTransaction(new IOnTransaction() { - - @Override - public String execute() { - orderElementDAO.reattach(taskElement - .getOrderElement()); - return buildTooltipText(); - } - }); - } - - @Override - public String getLabelsText() { - if (taskElement.isMilestone()) { - return ""; - } - return transactionService - .runOnReadOnlyTransaction(new IOnTransaction() { - - @Override - public String execute() { - orderElementDAO.reattach(taskElement - .getOrderElement()); - return buildLabelsText(); - } - }); - } - - @Override - public String getResourcesText() { - if (isPreventCalculateResourcesText() || - taskElement.getOrderElement() == null) { - return ""; - } - try { + @Override + public String getTooltipText() { + if (taskElement.isMilestone()) { + return ""; + } return transactionService - .runOnAnotherReadOnlyTransaction(new IOnTransaction() { + .runOnReadOnlyTransaction(new IOnTransaction() { @Override public String execute() { orderElementDAO.reattach(taskElement .getOrderElement()); - return buildResourcesText(); + return buildTooltipText(); } }); - } catch (Exception e) { - LOG.error("error calculating resources text", e); - return ""; } - } - private Set