Package org.libreplan.business.templates.entities

Source Code of org.libreplan.business.templates.entities.OrderElementTemplate

/*
* 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.business.templates.entities;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.NonUniqueResultException;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.Min;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.Valid;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.libreplan.business.advance.entities.AdvanceAssignmentTemplate;
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
import org.libreplan.business.common.BaseEntity;
import org.libreplan.business.common.Registry;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.labels.entities.Label;
import org.libreplan.business.materials.entities.MaterialAssignment;
import org.libreplan.business.materials.entities.MaterialAssignmentTemplate;
import org.libreplan.business.orders.entities.HoursGroup;
import org.libreplan.business.orders.entities.ICriterionRequirable;
import org.libreplan.business.orders.entities.InfoComponent;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.OrderLineGroup;
import org.libreplan.business.orders.entities.SchedulingState;
import org.libreplan.business.orders.entities.SchedulingState.ITypeChangedListener;
import org.libreplan.business.orders.entities.SchedulingState.Type;
import org.libreplan.business.qualityforms.entities.QualityForm;
import org.libreplan.business.requirements.entities.CriterionRequirement;
import org.libreplan.business.requirements.entities.DirectCriterionRequirement;
import org.libreplan.business.requirements.entities.IndirectCriterionRequirement;
import org.libreplan.business.templates.daos.IOrderElementTemplateDAO;
import org.libreplan.business.trees.ITreeNode;
import org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException;

/**
* @author Óscar González Fernández <ogonzalez@igalia.com>
*
*/
public abstract class OrderElementTemplate extends BaseEntity implements
        ICriterionRequirable, ITreeNode<OrderElementTemplate> {

    private static final Log LOG = LogFactory
            .getLog(OrderElementTemplate.class);

    private SchedulingState.Type schedulingStateType;

    private InfoComponent infoComponent;

    private Integer startAsDaysFromBeginning;

    private Integer deadlineAsDaysFromBeginning;

    private OrderLineGroupTemplate parent;

    private Set<CriterionRequirement> criterionRequirements = new HashSet<CriterionRequirement>();

    private Set<MaterialAssignmentTemplate> materialAssignments = new HashSet<MaterialAssignmentTemplate>();

    private Set<Label> labels = new HashSet<Label>();

    private Set<QualityForm> qualityForms = new HashSet<QualityForm>();

    private Set<AdvanceAssignmentTemplate> advanceAssignmentTemplates = new HashSet<AdvanceAssignmentTemplate>();

    private SchedulingState schedulingState;

    private OrderElement origin;

    public static <T extends OrderElementTemplate> T create(T beingBuilt,
            OrderElement origin) {
        InfoComponent infoComponentCopied = origin.getInfoComponent().copy();
        Order order = origin.getOrder();
        Days fromBeginningToStart = daysBetween(order.getInitDate(), origin
                .getInitDate());
        Days fromBeginningToEnd = daysBetween(order.getInitDate(), origin
                .getDeadline());
        beingBuilt.setMaterialAssignments(copyMaterialAssignmentsFrom(beingBuilt, origin
                .getMaterialAssignments()));
        beingBuilt.setCriterionRequirements(copyDirectCriterionRequirements(
                beingBuilt, origin.getDirectCriterionRequirement()));
        beingBuilt.addLabels(origin.getLabels());
        beingBuilt.setQualityForms(origin.getQualityForms());
        beingBuilt.setAdvanceAssignmentTemplates(copyDirectAdvanceAssignments(
                beingBuilt, origin.getDirectAdvanceAssignments()));
        beingBuilt.setInfoComponent(infoComponentCopied);
        beingBuilt.setSchedulingStateType(origin.getSchedulingStateType());
        assignDates(beingBuilt, fromBeginningToStart, fromBeginningToEnd);
        beingBuilt.setOrigin(origin);
        return create(beingBuilt);
    }

    /**
     *
     * Copy only {@link DirectCriterionRequirement}
     *
     * @param beingBuilt
     * @param criterionRequirements
     * @return
     */
    private static Set<CriterionRequirement> copyDirectCriterionRequirements(OrderElementTemplate beingBuilt,
            Collection<DirectCriterionRequirement> criterionRequirements) {
        Set<CriterionRequirement> result = new HashSet<CriterionRequirement>();

        for (DirectCriterionRequirement each: criterionRequirements) {
            final DirectCriterionRequirement directCriterionRequirement = (DirectCriterionRequirement) each;
            DirectCriterionRequirement newDirectCriterionRequirement = DirectCriterionRequirement
                    .copyFrom(directCriterionRequirement, beingBuilt);

            result.add(newDirectCriterionRequirement);
        }
        return result;
    }

    private static Set<AdvanceAssignmentTemplate> copyDirectAdvanceAssignments(
            OrderElementTemplate beingBuilt,
            Set<DirectAdvanceAssignment> directAdvanceAssignments) {
        Set<AdvanceAssignmentTemplate> result = new HashSet<AdvanceAssignmentTemplate>();
        for (DirectAdvanceAssignment each : directAdvanceAssignments) {
            result.add(AdvanceAssignmentTemplate.convert(beingBuilt, each));
        }
        return result;
    }

    public static <T extends OrderElementTemplate> T createNew(T beingBuilt) {
        beingBuilt.setInfoComponent(new InfoComponent());
        assignDates(beingBuilt, null, null);
        return create(beingBuilt);
    }

    private static Set<MaterialAssignmentTemplate> copyMaterialAssignmentsFrom(OrderElementTemplate beingBuilt,
            Collection<? extends MaterialAssignment> assignments) {
        Set<MaterialAssignmentTemplate> result = new HashSet<MaterialAssignmentTemplate>();
        for (MaterialAssignment each : assignments) {
            result.add(MaterialAssignmentTemplate.copyFrom(each, beingBuilt));
        }
        return result;
    }

    private static void assignDates(OrderElementTemplate beingBuilt,
            Days fromBeginningToStart, Days fromBeginningToEnd) {
        Validate.isTrue(isNullOrPositive(fromBeginningToStart));
        Validate.isTrue(isNullOrPositive(fromBeginningToEnd));
        beingBuilt.startAsDaysFromBeginning = daysToInteger(fromBeginningToStart);
        beingBuilt.deadlineAsDaysFromBeginning = daysToInteger(fromBeginningToEnd);
    }

    private static Days daysBetween(Date start, Date end) {
        if (start == null || end == null) {
            return null;
        }
        return Days.daysBetween(asDateTime(start), asDateTime(end));
    }

    private static DateTime asDateTime(Date date) {
        return new DateTime(date);
    }

    private static boolean isNullOrPositive(Days days) {
        return days == null || days.getDays() >= 0;
    }

    private static Integer daysToInteger(Days days) {
        return days != null ? days.getDays() : null;
    }

    protected <T extends OrderElement> T setupElementParts(T orderElement) {
        setupInfoComponent(orderElement);
        setupDates(orderElement);
        setupCriterionRequirements(orderElement);
        setupMaterialAssignments(orderElement);
        setupLabels(orderElement);
        setupQualityForms(orderElement);
        setupAdvances(orderElement);
        return orderElement;
    }

    protected <T extends OrderElement> T setupSchedulingStateType(T orderElement) {
        orderElement.initializeType(schedulingStateType);
        return orderElement;
    }

    protected <T extends OrderElement> T setupVersioningInfo(
            OrderLineGroup parent, T orderElement) {
        orderElement.useSchedulingDataFor(parent.getCurrentOrderVersion());
        return orderElement;
    }

    private void setupInfoComponent(OrderElement orderElement) {
        // orderElement.setCode(getCode());
        orderElement.setName(getName());
        orderElement.setDescription(getDescription());
    }

    private <T> void setupDates(OrderElement orderElement) {
        Date orderInitDate = orderElement.getOrder().getInitDate();
        if (getStartAsDaysFromBeginning() != null) {
            orderElement.setInitDate(plusDays(orderInitDate,
                    getStartAsDaysFromBeginning()));
        }
        if (getDeadlineAsDaysFromBeginning() != null) {
            orderElement.setDeadline(plusDays(orderInitDate,
                    getDeadlineAsDaysFromBeginning()));
        }
    }

    private Date plusDays(Date date, Integer days) {
        LocalDate localDate = new LocalDate(date);
        return localDate.plusDays(days).toDateTimeAtStartOfDay().toDate();
    }

    private void setupCriterionRequirements(OrderElement orderElement) {
        for (DirectCriterionRequirement each : getDirectCriterionRequirements()) {
            if (orderElement.canAddCriterionRequirement(each)) {
                orderElement.addCriterionRequirement(DirectCriterionRequirement
                        .copyFrom(each, orderElement));
            }
        }
    }

    private void setupMaterialAssignments(OrderElement orderElement) {
        for (MaterialAssignmentTemplate each : materialAssignments) {
            orderElement.addMaterialAssignment(each
                    .createAssignment(orderElement));
        }
    }

    private void setupLabels(OrderElement orderElement) {
        for (Label each : getLabels()) {
            if (orderElement.checkAncestorsNoOtherLabelRepeated(each)) {
                orderElement.addLabel(each);
            }
        }
    }

    private void setupQualityForms(OrderElement orderElement) {
        for (QualityForm each : qualityForms) {
            orderElement.addTaskQualityForm(each);
        }
    }

    private void setupAdvances(OrderElement orderElement) {
        for (AdvanceAssignmentTemplate each : advanceAssignmentTemplates) {
            try {
                orderElement.addAdvanceAssignment(each
                        .createAdvanceAssignment(orderElement));
            } catch (Exception e) {
                String errorMessage = "error adding advance assignment to newly instantiated orderElement. Ignoring it";
                LOG.warn(errorMessage, e);
            }
        }
    }

    public abstract OrderElement createElement(OrderLineGroup parent);

    public SchedulingState getSchedulingState() {
        if (schedulingState == null) {
            schedulingState = SchedulingState.createSchedulingState(
                    getSchedulingStateType(),
                    getChildrenStates(), new ITypeChangedListener() {
                        @Override
                        public void typeChanged(Type newType) {
                            schedulingStateType = newType;
                        }
                    });
        }
        return schedulingState;
    }

    private List<SchedulingState> getChildrenStates() {
        List<SchedulingState> result = new ArrayList<SchedulingState>();
        for (OrderElementTemplate each : getChildren()) {
            result.add(each.getSchedulingState());
        }
        return result;
    }

    public SchedulingState.Type getSchedulingStateType() {
        if (schedulingStateType == null) {
            schedulingStateType = Type.NO_SCHEDULED;
        }
        return schedulingStateType;
    }

    protected void setSchedulingStateType(SchedulingState.Type schedulingStateType) {
        this.schedulingStateType = schedulingStateType;
    }

    public OrderLineGroupTemplate getParent() {
        return parent;
    }

    protected void setParent(OrderLineGroupTemplate parent) {
        this.parent = parent;
    }

    protected InfoComponent getInfoComponent() {
        if (infoComponent == null) {
            infoComponent = new InfoComponent();
        }
        return infoComponent;
    }

    protected void setInfoComponent(InfoComponent infoComponent) {
        this.infoComponent = infoComponent;
    }

    /**
     * @return a description of the type or template this object is
     */
    public abstract String getType();

    public abstract List<OrderElementTemplate> getChildrenTemplates();

    @Min(0)
    public Integer getDeadlineAsDaysFromBeginning() {
        return deadlineAsDaysFromBeginning;
    }

    @Min(0)
    public Integer getStartAsDaysFromBeginning() {
        return startAsDaysFromBeginning;
    }

    public void setStartAsDaysFromBeginning(Integer days) {
        this.startAsDaysFromBeginning = days;
    }

    public void setDeadlineAsDaysFromBeginning(Integer days) {
        this.deadlineAsDaysFromBeginning = days;
    }

    public String getDescription() {
        return getInfoComponent().getDescription();
    }

    public void setDescription(String description) {
        getInfoComponent().setDescription(description);
    }

    @NotEmpty(message = "name not specified")
    public String getName() {
        return getInfoComponent().getName();
    }

    public void setName(String name) {
        getInfoComponent().setName(name);
    }

    @Override
    public OrderElementTemplate getThis() {
        return this;
    }

    protected void copyTo(OrderElementTemplate result) {
        result.setName(getName());
        result.setDescription(getDescription());
        result.setDeadlineAsDaysFromBeginning(getDeadlineAsDaysFromBeginning());
        result.setStartAsDaysFromBeginning(getStartAsDaysFromBeginning());
    }

    @Valid
    public Set<MaterialAssignmentTemplate> getMaterialAssignments() {
        return Collections.unmodifiableSet(materialAssignments);
    }

    protected void setMaterialAssignments(Set<MaterialAssignmentTemplate> materialAssigments) {
        this.materialAssignments = materialAssignments;
    }

    public void addMaterialAssignment(
            MaterialAssignmentTemplate materialAssignment) {
        Validate.notNull(materialAssignment);
        materialAssignments.add(materialAssignment);
    }

    public void removeMaterialAssignment(
            MaterialAssignmentTemplate materialAssignment) {
        materialAssignments.remove(materialAssignment);
    }

    public BigDecimal getTotalMaterialAssigmentPrice() {
        BigDecimal result = BigDecimal.ZERO;
        for (MaterialAssignmentTemplate each : materialAssignments) {
            result = result.add(each.getTotalPrice());
        }
        return result;
    }

    public BigDecimal getTotalMaterialAssigmentUnits() {
        BigDecimal result = BigDecimal.ZERO;
        for (MaterialAssignmentTemplate each : materialAssignments) {
            if (each.getUnits() != null) {
                result = result.add(each.getUnits());
            }
        }
        return result;
    }

    public abstract boolean isLeaf();

    @Valid
    public Set<Label> getLabels() {
        return Collections.unmodifiableSet(labels);
    }

    public void addLabel(Label label){
        Validate.notNull(label);
        this.labels.add(label);
    }

    public void addLabels(Collection<Label> labels){
        Validate.notNull(labels);
        this.labels.addAll(labels);
    }

    public void removeLabel(Label label) {
        this.labels.remove(label);
    }

    public Set<QualityForm> getQualityForms() {
        return Collections.unmodifiableSet(qualityForms);
    }

    protected void setQualityForms(Set<QualityForm> qualityForms) {
        this.qualityForms = qualityForms;
    }

    public void addQualityForm(QualityForm qualityForm) {
        qualityForms.add(qualityForm);
    }

    public void removeQualityForm(QualityForm qualityForm) {
        qualityForms.remove(qualityForm);
    }

    @Valid
    public Set<AdvanceAssignmentTemplate> getAdvanceAssignmentTemplates() {
        return Collections.unmodifiableSet(advanceAssignmentTemplates);
    }

    protected void setAdvanceAssignmentTemplates(
            Set<AdvanceAssignmentTemplate> advanceAssignmentTemplates) {
        this.advanceAssignmentTemplates = advanceAssignmentTemplates;
    }

    public boolean isRoot() {
        return getParent() == null;
    }

    @AssertTrue(message = "template name is already in use")
    public boolean isUniqueRootTemplateNameConstraint() {
        if (getParent() != null) {
            return true;
        }

        IOrderElementTemplateDAO orderElementTemplateDAO = Registry
                .getOrderElementTemplateDAO();
        if (isNewObject()) {
            return !orderElementTemplateDAO
                    .existsRootByNameAnotherTransaction(this);
        } else {
            try {
                OrderElementTemplate template = orderElementTemplateDAO
                        .findUniqueRootByName(getName());
                return template.getId().equals(getId());
            } catch (InstanceNotFoundException e) {
                return true;
            }
            catch (NonUniqueResultException e) {
                return false;
            } catch (HibernateOptimisticLockingFailureException e) {
                return true;
            }
        }
    }

    public List<OrderElementTemplate> getAllChildren() {
        List<OrderElementTemplate> children = getChildrenTemplates();
        List<OrderElementTemplate> result = new ArrayList<OrderElementTemplate>();
        for (OrderElementTemplate orderElement : children) {
            result.add(orderElement);
            result.addAll(orderElement.getAllChildren());
        }
        return result;
    }

    @Valid
    @Override
    public Set<CriterionRequirement> getCriterionRequirements() {
        return Collections.unmodifiableSet(criterionRequirements);
    }

    protected void setCriterionRequirements(Set<CriterionRequirement> criterionRequirements) {
        this.criterionRequirements = criterionRequirements;
    }

    public abstract List<HoursGroup> getHoursGroups();

    public abstract Integer getWorkHours();

    /**
     * Operations for manipulating CriterionRequirement
     */

    protected CriterionRequirementTemplateHandler criterionRequirementHandler =
        CriterionRequirementTemplateHandler.getInstance();

    public void setValidCriterionRequirement(IndirectCriterionRequirement requirement, boolean valid){
        requirement.setValid(valid);
        criterionRequirementHandler.propagateValidCriterionRequirement(this,
                requirement.getParent(), valid);
    }

    public void removeDirectCriterionRequirement(DirectCriterionRequirement criterionRequirement){
        criterionRequirementHandler.propagateRemoveCriterionRequirement(this,
                criterionRequirement);
        removeCriterionRequirement(criterionRequirement);

    }

    @Override
    public void removeCriterionRequirement(CriterionRequirement requirement) {
        criterionRequirements.remove(requirement);
        if (requirement instanceof IndirectCriterionRequirement) {
            ((IndirectCriterionRequirement)requirement).getParent().
                    getChildren().remove((IndirectCriterionRequirement)requirement);
        }
    }

    @Override
    public void addCriterionRequirement(
            CriterionRequirement criterionRequirement) {
        criterionRequirementHandler.addCriterionRequirement(this,
                criterionRequirement);
    }

    public void addDirectCriterionRequirement(
            CriterionRequirement criterionRequirement) {
        criterionRequirementHandler.addDirectCriterionRequirement(this, criterionRequirement);
    }

    public void addIndirectCriterionRequirement(
            IndirectCriterionRequirement criterionRequirement) {
        criterionRequirementHandler.addIndirectCriterionRequirement(this,
                criterionRequirement);
    }

    protected void basicAddCriterionRequirement(
            CriterionRequirement criterionRequirement) {
            criterionRequirement.setOrderElementTemplate(this);
            this.criterionRequirements.add(criterionRequirement);
    }

    public void updateCriterionRequirements() {
        criterionRequirementHandler.updateMyCriterionRequirements(this);
        criterionRequirementHandler.propagateUpdateCriterionRequirements(this);
    }

    public boolean canAddCriterionRequirement(
            DirectCriterionRequirement newRequirement) {
        return criterionRequirementHandler.canAddCriterionRequirement(this,
                newRequirement);
    }

    protected Set<IndirectCriterionRequirement> getIndirectCriterionRequirement() {
        return criterionRequirementHandler.getIndirectCriterionRequirement(criterionRequirements);
    }

    public Set<DirectCriterionRequirement> getDirectCriterionRequirements() {
        return criterionRequirementHandler
                .getDirectCriterionRequirement(criterionRequirements);
    }

    public Order getOrder() {
        return (parent != null) ? parent.getOrder() : null;
    }

    public OrderElement getOrigin() {
        return origin;
    }

    public void setOrigin(OrderElement origin) {
        this.origin = origin;
    }

    public abstract BigDecimal getBudget();

    public abstract boolean isOrderTemplate();

    @Override
    public boolean isUpdatedFromTimesheets() {
        return false;
    }

    @Override
    public boolean isJiraIssue() {
        return false;
    }

}
TOP

Related Classes of org.libreplan.business.templates.entities.OrderElementTemplate

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.