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();