Package org.libreplan.web.planner.limiting.allocation

Source Code of org.libreplan.web.planner.limiting.allocation.LimitingResourceAllocationModel

/*
* This file is part of LibrePlan
*
* 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 <http://www.gnu.org/licenses/>.
*/

package org.libreplan.web.planner.limiting.allocation;

import static org.libreplan.web.I18nHelper._;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.hibernate.Hibernate;
import org.libreplan.business.common.IAdHocTransactionService;
import org.libreplan.business.common.IOnTransaction;
import org.libreplan.business.orders.daos.IHoursGroupDAO;
import org.libreplan.business.orders.entities.AggregatedHoursGroup;
import org.libreplan.business.orders.entities.HoursGroup;
import org.libreplan.business.orders.entities.TaskSource;
import org.libreplan.business.planner.daos.ITaskElementDAO;
import org.libreplan.business.planner.daos.ITaskSourceDAO;
import org.libreplan.business.planner.entities.GenericResourceAllocation;
import org.libreplan.business.planner.entities.ResourceAllocation;
import org.libreplan.business.planner.entities.Task;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.planner.limiting.entities.LimitingResourceQueueElement;
import org.libreplan.business.resources.daos.ICriterionDAO;
import org.libreplan.business.resources.daos.IResourceDAO;
import org.libreplan.business.resources.entities.Criterion;
import org.libreplan.business.resources.entities.CriterionType;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.ResourceEnum;
import org.libreplan.web.common.IMessagesForUser;
import org.libreplan.web.common.Level;
import org.libreplan.web.planner.order.PlanningStateCreator.PlanningState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zkoss.ganttz.data.GanttDate;
import org.zkoss.ganttz.extensions.IContextWithPlannerTask;

/**
* Provides logical operations for limiting resource assignations in @{Task}
*
* @author Diego Pino García <dpino@igalia.com>
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class LimitingResourceAllocationModel implements ILimitingResourceAllocationModel {

    @Autowired
    private IHoursGroupDAO hoursGroupDAO;

    @Autowired
    private ITaskSourceDAO taskSourceDAO;

    @Autowired
    private ICriterionDAO criterionDAO;

    @Autowired
    private ITaskElementDAO taskDAO;

    @Autowired
    private IResourceDAO resourceDAO;

    @Autowired
    private IAdHocTransactionService transactionService;

    private IContextWithPlannerTask<TaskElement> context;

    private Task task;

    private PlanningState planningState;

    private List<LimitingAllocationRow> limitingAllocationRows = new ArrayList<LimitingAllocationRow>();

    private LimitingResourceAllocationController limitingResourceAllocationController;

    @Override
    @Transactional(readOnly=true)
    public void init(IContextWithPlannerTask<TaskElement> context, Task task,
            PlanningState planningState) {
        this.context = context;
        this.task = task;
        this.planningState = planningState;

        initializeCriteria(task);
        limitingAllocationRows = LimitingAllocationRow.toRows(task);
    }

    private void initializeCriteria(Task task) {
        for (ResourceAllocation<?> each: task.getLimitingResourceAllocations()) {
            if (isGeneric(each)) {
                initializeCriteria((GenericResourceAllocation) each);
            }
        }
    }

    private boolean isGeneric(ResourceAllocation<?> resourceAllocation) {
        return resourceAllocation instanceof GenericResourceAllocation;
    }

    private void initializeCriteria(GenericResourceAllocation generic) {
        for (Criterion each : generic.getCriterions()) {
            initializeCriterion(each);
        }
    }

    private void initializeCriterion(Criterion criterion) {
        criterionDAO.reattach(criterion);
        Hibernate.initialize(criterion.getType());
    }

    @Override
    @Transactional(readOnly=true)
    public Integer getOrderHours() {
        if (task == null) {
            return 0;
        }
        return AggregatedHoursGroup.sum(getHoursAggregatedByCriteria());
    }

    @Override
    @Transactional(readOnly = true)
    public void addGeneric(ResourceEnum resourceType,
            Collection<? extends Criterion> criteria,
            Collection<? extends Resource> resources) {

        if (resources.isEmpty()) {
            getMessagesForUser()
                    .showMessage(Level.ERROR,
                            _("there are no resources for required criteria: {0}. " +
                                    "So the generic allocation can't be added",
                            Criterion.getCaptionFor(resourceType, criteria)));
        }

        if (resources.size() >= 1) {
            if (planningState != null) {
                planningState.reassociateResourcesWithSession();
            }
            addGenericResourceAllocation(resourceType, criteria,
                    reloadResources(resources));
        }
    }

    private List<Resource> reloadResources(
            Collection<? extends Resource> resources) {
        List<Resource> result = new ArrayList<Resource>();
        for (Resource each: resources) {
            result.add(resourceDAO.findExistingEntity(each.getId()));
        }
        return result;
    }

    private IMessagesForUser getMessagesForUser() {
        return limitingResourceAllocationController.getMessagesForUser();
    }

    private void addGenericResourceAllocation(ResourceEnum resourceType,
            Collection<? extends Criterion> criteria,
            Collection<? extends Resource> resources) {

        if (isNew(criteria, resources)) {
            limitingAllocationRows.clear();
            limitingAllocationRows.add(LimitingAllocationRow.create(
                    resourceType, criteria, resources, task,
                    LimitingAllocationRow.DEFAULT_PRIORITY));
        }
    }

    private boolean isNew(Collection<? extends Criterion> criteria,
            Collection<? extends Resource> resources) {
        LimitingAllocationRow allocationRow = getLimitingAllocationRow();

        if (allocationRow == null || allocationRow.isSpecific()) {
            return true;
        }

        Set<Long> allocatedResourcesIds = allocationRow.getResourcesIds();
        for (Resource each: resources) {
            if (!allocatedResourcesIds.contains(each.getId())) {
                return true;
            }
        }

        Set<Long> allocatedCriteriaIds = allocationRow.getCriteriaIds();
        for (Criterion each: criteria) {
            if (!allocatedCriteriaIds.contains(each.getId())) {
                return true;
            }
        }
        return false;
    }

    @Override
    @Transactional(readOnly = true)
    public void addSpecific(Collection<? extends Resource> resources) {

        if (!areAllLimitingResources(resources)) {
            getMessagesForUser().showMessage(Level.ERROR,
                    _("All resources must be queue-based"));
            return;
        }

        if (resources.size() >= 1) {
            if (planningState != null) {
                planningState.reassociateResourcesWithSession();
            }
            List<Resource> reloaded = reloadResources(
                    Collections.singleton(getFirstChild(resources)));
            addSpecificResourceAllocation(getFirstChild(reloaded));
        }
    }

    private boolean areAllLimitingResources(
            Collection<? extends Resource> resources) {
        for (Resource resource : resources) {
            if (!resource.isLimitingResource()) {
                return false;
            }
        }
        return true;
    }

    public Resource getFirstChild(Collection<? extends Resource> collection) {
        return collection.iterator().next();
    }

    private void addSpecificResourceAllocation(Resource resource) {
        if (isNew(resource)) {
            limitingAllocationRows.clear();
            LimitingAllocationRow allocationRow = LimitingAllocationRow.create(
                    resource, task, LimitingAllocationRow.DEFAULT_PRIORITY);
            limitingAllocationRows.add(allocationRow);
        }
    }

    private boolean isNew(Resource resource) {
        LimitingAllocationRow allocationRow = getLimitingAllocationRow();

        if (allocationRow == null || allocationRow.isGeneric()) {
            return true;
        }

        final Resource taskResource = getAssociatedResource();
        if (taskResource != null) {
            return (!resource.getId().equals(taskResource.getId()));
        }
        return true;
    }

    private Resource getAssociatedResource() {
        ResourceAllocation<?> resourceAllocation = getAssociatedResourceAllocation();
        if (resourceAllocation != null) {
            List<Resource> resources = resourceAllocation.getAssociatedResources();
            if (resources != null && resources.size() >= 1) {
                return (Resource) resources.iterator().next();
            }
        }
        return null;
    }

    private ResourceAllocation<?> getAssociatedResourceAllocation() {
        LimitingAllocationRow allocationRow = getLimitingAllocationRow();
        if (allocationRow != null) {
            return allocationRow.getResourceAllocation();
        }
        return null;
    }

    private LimitingAllocationRow getLimitingAllocationRow() {
        if (limitingAllocationRows.size() >= 1) {
            return limitingAllocationRows.get(0);
        }
        return null;
    }

    @Override
    public List<LimitingAllocationRow> getResourceAllocationRows() {
        return Collections.unmodifiableList(limitingAllocationRows);
    }

    @Override
    @Transactional(readOnly = true)
    public List<AggregatedHoursGroup> getHoursAggregatedByCriteria() {
        reattachTaskSource();
        List<AggregatedHoursGroup> result = task.getTaskSource()
                .getAggregatedByCriterions();
        ensuringAccesedPropertiesAreLoaded(result);
        return result;
    }

    private void ensuringAccesedPropertiesAreLoaded(
            List<AggregatedHoursGroup> result) {
        for (AggregatedHoursGroup each : result) {
            each.getCriterionsJoinedByComma();
            each.getHours();
        }
    }

    /**
     * Re-attach {@link TaskSource}
     */
    private void reattachTaskSource() {
        TaskSource taskSource = task.getTaskSource();
        taskSourceDAO.reattach(taskSource);
        Set<HoursGroup> hoursGroups = taskSource.getHoursGroups();
        for (HoursGroup hoursGroup : hoursGroups) {
            reattachHoursGroup(hoursGroup);
        }
    }

    private void reattachHoursGroup(HoursGroup hoursGroup) {
        hoursGroupDAO.reattachUnmodifiedEntity(hoursGroup);
        hoursGroup.getPercentage();
        reattachCriteria(hoursGroup.getValidCriterions());
    }

    private void reattachCriteria(Set<Criterion> criterions) {
        for (Criterion criterion : criterions) {
            reattachCriterion(criterion);
        }
    }

    private void reattachCriterion(Criterion criterion) {
        criterionDAO.reattachUnmodifiedEntity(criterion);
        criterion.getName();
        reattachCriterionType(criterion.getType());
    }

    private void reattachCriterionType(CriterionType criterionType) {
        criterionType.getName();
    }

    @Override
    @Transactional(readOnly=true)
    public void confirmSave() {
        applyAllocationWithDateChangesNotification(new IOnTransaction<Void>() {
            @Override
            public Void execute() {
                taskDAO.reattach(task);

                ResourceAllocation<?> resourceAllocation = getAssociatedResourceAllocation();
                if (resourceAllocation != null) {
                    if (resourceAllocation.isNewObject()) {
                        addAssociatedLimitingResourceQueueElement(task,
                                resourceAllocation);
                    } else {
                        if (!resourceAllocation.hasAssignments()) {
                            task.resizeToHours(resourceAllocation
                                    .getIntendedTotalHours());
                        }
                    }
                }
                taskDAO.save(task);
                return null;
            }
        });
    }

    private void applyAllocationWithDateChangesNotification(
            IOnTransaction<?> allocationDoer) {
        if (context != null) {
            org.zkoss.ganttz.data.Task ganttTask = context.getTask();
            transactionService.runOnReadOnlyTransaction(allocationDoer);
            ganttTask.enforceDependenciesDueToPositionPotentiallyModified();
        } else {
            // Update hours of a Task from Limiting Resource view
            transactionService.runOnReadOnlyTransaction(allocationDoer);
        }
    }

    private void addAssociatedLimitingResourceQueueElement(Task task, ResourceAllocation<?> resourceAllocation) {
        LimitingResourceQueueElement element = LimitingResourceQueueElement.create();
        resourceAllocation.setLimitingResourceQueueElement(element);
        task.setResourceAllocation(resourceAllocation);
    }

    @Override
    public void setLimitingResourceAllocationController(
            LimitingResourceAllocationController limitingResourceAllocationController) {
        this.limitingResourceAllocationController = limitingResourceAllocationController;
    }

}
TOP

Related Classes of org.libreplan.web.planner.limiting.allocation.LimitingResourceAllocationModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.