package org.sigmah.server.service; /* * #%L * Sigmah * %% * Copyright (C) 2010 - 2016 URD * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import java.util.*; import org.sigmah.client.util.AdminUtil; import org.sigmah.server.dao.FrameworkDAO; import org.sigmah.server.dao.ProfileDAO; import org.sigmah.server.dao.ProjectModelDAO; import org.sigmah.server.dispatch.impl.UserDispatch.UserExecutionContext; import org.sigmah.server.domain.*; import org.sigmah.server.domain.element.DefaultFlexibleElement; import org.sigmah.server.domain.layout.Layout; import org.sigmah.server.domain.layout.LayoutConstraint; import org.sigmah.server.domain.layout.LayoutGroup; import org.sigmah.server.domain.logframe.LogFrameModel; import org.sigmah.server.domain.profile.Profile; import org.sigmah.server.mapper.Mapper; import org.sigmah.server.service.base.AbstractEntityService; import org.sigmah.server.service.util.ModelUtil; import org.sigmah.server.service.util.PropertyMap; import org.sigmah.shared.dto.PhaseModelDTO; import org.sigmah.shared.dto.ProjectModelDTO; import org.sigmah.shared.dto.referential.DefaultFlexibleElementType; import org.sigmah.shared.dto.referential.ProjectModelStatus; import org.sigmah.shared.dto.referential.ProjectModelType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.inject.Inject; import com.google.inject.Singleton; import java.util.Date; import java.util.HashSet; import org.sigmah.server.computation.ServerDependencyResolver; import org.sigmah.server.domain.element.BudgetRatioElement; import org.sigmah.server.i18n.I18nServer; /** * Handler for updating Project model command. * * @author nrebiai * @author Maxime Lombard (mlombard@ideia.fr) * @author Denis Colliot (dcolliot@ideia.fr) */ @Singleton public class ProjectModelService extends AbstractEntityService<ProjectModel, Integer, ProjectModelDTO> { /** * Logger. */ private final static Logger LOG = LoggerFactory.getLogger(ProjectModelService.class); /** * Injected application mapper. */ @Inject private Mapper mapper; @Inject private ModelUtil modelUtil; /** * Injected {@link ProjectModelDAO}. */ @Inject private ProjectModelDAO projectModelDAO; /** * Injected {@link I18nServer}. Handle localization of lables. */ @Inject private I18nServer i18n; @Inject private ProfileDAO profileDAO; @Inject private FrameworkDAO frameworkDAO; /** * {@inheritDoc} */ @Override public ProjectModel create(PropertyMap properties, final UserExecutionContext context) { final ProjectModelDTO projectModel = (ProjectModelDTO) properties.get(AdminUtil.ADMIN_PROJECT_MODEL); // Only draft models can be changed. if (projectModel == null) { return null; } if (projectModel.getId() != null) { // Properties can only contain actual changes between old version and new one as verification has already been // done. return update(projectModel.getId(), properties, context); } // Create new draft ProjectModel ProjectModel pM = new ProjectModel(); String pMName = (String) properties.get(AdminUtil.PROP_PM_NAME); ProjectModelType pMUse = (ProjectModelType) properties.get(AdminUtil.PROP_PM_USE); pM.setName(pMName); pM.setStatus(ProjectModelStatus.DRAFT); List<ProjectModelVisibility> visibilities = new ArrayList<ProjectModelVisibility>(); ProjectModelVisibility v = new ProjectModelVisibility(); v.setModel(pM); v.setType(pMUse); v.setOrganization(context.getUser().getOrganization()); visibilities.add(v); pM.setVisibilities(visibilities); // Project model details ProjectDetails pMDetails = new ProjectDetails(); Layout pMDetailsLayout = new Layout(); pMDetailsLayout.setColumnsCount(1); pMDetailsLayout.setRowsCount(1); pMDetails.setLayout(pMDetailsLayout); pMDetails.setProjectModel(pM); LayoutGroup detailsGroup = new LayoutGroup(); detailsGroup.setTitle("Default details group"); detailsGroup.setColumn(0); detailsGroup.setRow(0); detailsGroup.setParentLayout(pMDetailsLayout); // Default flexible elements all in default details group int order = 0; for (final DefaultFlexibleElementType type : DefaultFlexibleElementType.values()) { DefaultFlexibleElement defaultElement; if (type == DefaultFlexibleElementType.BUDGET) { continue; } else if (type == DefaultFlexibleElementType.BUDGET_RATIO) { defaultElement = new BudgetRatioElement(); defaultElement.setLabel(i18n.t(context.getLanguage(), "flexibleElementBudgetRatio")); } else { defaultElement = new DefaultFlexibleElement(); } defaultElement.setType(type); defaultElement.setValidates(false); defaultElement.setAmendable(true); em().persist(defaultElement); LayoutConstraint defaultLayoutConstraint = new LayoutConstraint(); defaultLayoutConstraint.setParentLayoutGroup(detailsGroup); defaultLayoutConstraint.setElement(defaultElement); defaultLayoutConstraint.setSortOrder(order++); detailsGroup.addConstraint(defaultLayoutConstraint); } List<LayoutGroup> detailsGroups = new ArrayList<LayoutGroup>(); detailsGroups.add(detailsGroup); pMDetailsLayout.setGroups(detailsGroups); // Banner and groups for banner ProjectBanner pMBanner = new ProjectBanner(); Layout pMBannerLayout = new Layout(); pMBannerLayout.setColumnsCount(3); pMBannerLayout.setRowsCount(2); pMBanner.setLayout(pMBannerLayout); pMBanner.setProjectModel(pM); List<LayoutGroup> bannerGroups = new ArrayList<LayoutGroup>(); for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { LayoutGroup bannerGroup = new LayoutGroup(); bannerGroup.setColumn(i); bannerGroup.setRow(j); bannerGroup.setParentLayout(pMBannerLayout); bannerGroups.add(bannerGroup); } } pMBannerLayout.setGroups(bannerGroups); pM.setProjectDetails(pMDetails); pM.setProjectBanner(pMBanner); projectModelDAO.persist(pM, context.getUser()); // Add a root phase : one model has minimum one phase PhaseModel defaultRootPhase = new PhaseModel(); defaultRootPhase.setName("Default root phase"); defaultRootPhase.setParentProjectModel(pM); defaultRootPhase.setDisplayOrder(0); Layout phaseLayout = new Layout(); phaseLayout.setColumnsCount(1); phaseLayout.setRowsCount(1); LayoutGroup phaseGroup = new LayoutGroup(); phaseGroup.setTitle("Default phase group"); phaseGroup.setColumn(0); phaseGroup.setRow(0); phaseGroup.setParentLayout(phaseLayout); List<LayoutGroup> phaseGroups = new ArrayList<LayoutGroup>(); phaseGroups.add(phaseGroup); phaseLayout.setGroups(phaseGroups); defaultRootPhase.setLayout(phaseLayout); em().persist(defaultRootPhase); LogFrameModel defaultLogFrame = createDefaultLogFrameModel(pM); em().persist(defaultLogFrame); pM.setRootPhaseModel(defaultRootPhase); pM.setLogFrameModel(defaultLogFrame); return projectModelDAO.persist(pM, context.getUser()); } /** * {@inheritDoc} */ @Override public ProjectModel update(final Integer entityId, final PropertyMap changes, final UserExecutionContext context) { LOG.debug("Begins update the model."); ProjectModel model = projectModelDAO.findById(entityId); if (model == null) { throw new IllegalArgumentException("No ProjetModel can be found with id #" + entityId); } if (changes.get(AdminUtil.PROP_PM_NAME) != null) { model.setName((String) changes.get(AdminUtil.PROP_PM_NAME)); } if (changes.get(AdminUtil.PROP_PM_STATUS) != null) { final ProjectModelStatus newStatus = changes.get(AdminUtil.PROP_PM_STATUS); if (frameworkDAO.countNotImplementedElementsByProjectModelId(model.getId()) > 0) { throw new IllegalArgumentException("A framework requirement was not entirely fulfilled."); } model.setStatus(newStatus); } if (changes.get(AdminUtil.PROP_PM_USE) instanceof ProjectModelType) { for (final ProjectModelVisibility v : model.getVisibilities()) { if (context.getUser().getOrganization().getId().equals(v.getOrganization().getId())) { v.setType((ProjectModelType) changes.get(AdminUtil.PROP_PM_USE)); em().merge(v); } } } if (changes.containsKey(AdminUtil.PROP_PM_MAINTENANCE_DATE)) { final Object maintenanceDate = changes.get(AdminUtil.PROP_PM_MAINTENANCE_DATE); if(maintenanceDate instanceof Date) { model.setDateMaintenance((Date)maintenanceDate); } else { model.setDateMaintenance(null); } } if (changes.containsKey(AdminUtil.PROP_PM_DEFAULT_TEAM_MEMBER_PROFILES)) { Object defaultProfileIds = changes.get(AdminUtil.PROP_PM_DEFAULT_TEAM_MEMBER_PROFILES); if (defaultProfileIds instanceof Set) { Set<Integer> profileIds = (Set<Integer>) defaultProfileIds; if (profileIds.isEmpty()) { model.setDefaultTeamMemberProfiles(null); } else { List<Profile> profiles = profileDAO.findByIds(profileIds); model.setDefaultTeamMemberProfiles(profiles); } } else { model.setDefaultTeamMemberProfiles(null); } } model = em().merge(model); // -- // Log Frame Model. // -- if (changes.get(AdminUtil.PROP_LOG_FRAME) != null && (Boolean) changes.get(AdminUtil.PROP_LOG_FRAME)) { LogFrameModel logFrameModel = null; if (model.getLogFrameModel() != null) { logFrameModel = em().find(LogFrameModel.class, model.getLogFrameModel().getId()); } else { logFrameModel = new LogFrameModel(); logFrameModel.setProjectModel(model); } // BUGFIX #758 : Using containsKey instead of != null to verify if a property must be updated. if (changes.containsKey(AdminUtil.PROP_LOG_FRAME_NAME)) { logFrameModel.setName((String) changes.get(AdminUtil.PROP_LOG_FRAME_NAME)); } if (changes.containsKey(AdminUtil.PROP_OBJ_MAX)) { logFrameModel.setSpecificObjectivesMax((Integer) changes.get(AdminUtil.PROP_OBJ_MAX)); } if (changes.containsKey(AdminUtil.PROP_OBJ_MAX_PER_GROUP)) { logFrameModel.setSpecificObjectivesPerGroupMax((Integer) changes.get(AdminUtil.PROP_OBJ_MAX_PER_GROUP)); } if (changes.containsKey(AdminUtil.PROP_OBJ_ENABLE_GROUPS)) { logFrameModel.setEnableSpecificObjectivesGroups((Boolean) changes.get(AdminUtil.PROP_OBJ_ENABLE_GROUPS)); } if (changes.containsKey(AdminUtil.PROP_OBJ_MAX_GROUPS)) { logFrameModel.setSpecificObjectivesGroupsMax((Integer) changes.get(AdminUtil.PROP_OBJ_MAX_GROUPS)); } if (changes.containsKey(AdminUtil.PROP_A_MAX)) { logFrameModel.setActivitiesMax((Integer) changes.get(AdminUtil.PROP_A_MAX)); } if (changes.containsKey(AdminUtil.PROP_A_ENABLE_GROUPS)) { logFrameModel.setEnableActivitiesGroups((Boolean) changes.get(AdminUtil.PROP_A_ENABLE_GROUPS)); } if (changes.containsKey(AdminUtil.PROP_A_MAX_PER_RESULT)) { logFrameModel.setActivitiesPerExpectedResultMax((Integer) changes.get(AdminUtil.PROP_A_MAX_PER_RESULT)); } if (changes.containsKey(AdminUtil.PROP_A_MAX_GROUPS)) { logFrameModel.setActivitiesGroupsMax((Integer) changes.get(AdminUtil.PROP_A_MAX_GROUPS)); } if (changes.containsKey(AdminUtil.PROP_A_MAX_PER_GROUP)) { logFrameModel.setActivitiesPerGroupMax((Integer) changes.get(AdminUtil.PROP_A_MAX_PER_GROUP)); } if (changes.containsKey(AdminUtil.PROP_R_MAX)) { logFrameModel.setExpectedResultsMax((Integer) changes.get(AdminUtil.PROP_R_MAX)); } if (changes.containsKey(AdminUtil.PROP_R_ENABLE_GROUPS)) { logFrameModel.setEnableExpectedResultsGroups((Boolean) changes.get(AdminUtil.PROP_R_ENABLE_GROUPS)); } if (changes.containsKey(AdminUtil.PROP_R_MAX_PER_OBJ)) { logFrameModel.setExpectedResultsPerSpecificObjectiveMax((Integer) changes.get(AdminUtil.PROP_R_MAX_PER_OBJ)); } if (changes.containsKey(AdminUtil.PROP_R_MAX_GROUPS)) { logFrameModel.setExpectedResultsGroupsMax((Integer) changes.get(AdminUtil.PROP_R_MAX_GROUPS)); } if (changes.containsKey(AdminUtil.PROP_R_MAX_PER_GROUP)) { logFrameModel.setExpectedResultsPerGroupMax((Integer) changes.get(AdminUtil.PROP_R_MAX_PER_GROUP)); } if (changes.containsKey(AdminUtil.PROP_P_MAX)) { logFrameModel.setPrerequisitesMax((Integer) changes.get(AdminUtil.PROP_P_MAX)); } if (changes.containsKey(AdminUtil.PROP_P_ENABLE_GROUPS)) { logFrameModel.setEnablePrerequisitesGroups((Boolean) changes.get(AdminUtil.PROP_P_ENABLE_GROUPS)); } if (changes.containsKey(AdminUtil.PROP_P_MAX_GROUPS)) { logFrameModel.setPrerequisitesGroupsMax((Integer) changes.get(AdminUtil.PROP_P_MAX_GROUPS)); } if (changes.containsKey(AdminUtil.PROP_P_MAX_PER_GROUP)) { logFrameModel.setPrerequisitesPerGroupMax((Integer) changes.get(AdminUtil.PROP_P_MAX_PER_GROUP)); } if (model.getLogFrameModel() != null) { logFrameModel = em().merge(logFrameModel); } else { em().persist(logFrameModel); } model.setLogFrameModel(logFrameModel); } // -- // Flexible Element. // -- if (changes.get(AdminUtil.PROP_FX_FLEXIBLE_ELEMENT) != null) { modelUtil.persistFlexibleElement(changes, model); model = projectModelDAO.findById(model.getId()); } // -- // Phases. // -- final PhaseModelDTO phaseDTOToSave = (PhaseModelDTO) changes.get(AdminUtil.PROP_PHASE_MODEL); final Integer displayOrder = (Integer) changes.get(AdminUtil.PROP_PHASE_ORDER); final Boolean root = (Boolean) changes.get(AdminUtil.PROP_PHASE_ROOT); final Integer numRows = (Integer) changes.get(AdminUtil.PROP_PHASE_ROWS); final String guide = (String) changes.get(AdminUtil.PROP_PHASE_GUIDE); if (phaseDTOToSave != null) { PhaseModel phaseToSave; PhaseModel phaseFound = null; for (final PhaseModel phase : model.getPhaseModels()) { if (phaseDTOToSave.getId() != null && phaseDTOToSave.getId().equals(phase.getId())) { phaseFound = phase; } } if(phaseFound != null) { phaseToSave = phaseFound; } else { phaseToSave = new PhaseModel(); } phaseToSave.setName(phaseDTOToSave.getName()); if (displayOrder != null) { phaseToSave.setDisplayOrder(displayOrder); } // Guide if (guide != null) { phaseToSave.setGuide(guide); } // successors final HashSet<PhaseModel> existingPhaseModels = new HashSet<PhaseModel>(phaseToSave.getSuccessors()); for (PhaseModelDTO sucDTO : phaseDTOToSave.getSuccessors()) { if (sucDTO.getId() != null && sucDTO.getId() > 0) { final PhaseModel successor = em().find(PhaseModel.class, sucDTO.getId()); if(!existingPhaseModels.contains(successor)) { phaseToSave.getSuccessors().add(successor); } else { existingPhaseModels.remove(successor); } } } for(final PhaseModel removedSuccessor : existingPhaseModels) { phaseToSave.getSuccessors().remove(removedSuccessor); } if (phaseFound != null) { // phase is old phaseToSave = em().merge(phaseToSave); } else { // create new phase phaseToSave.setParentProjectModel(model); Layout phaseLayout = new Layout(); phaseLayout.setColumnsCount(1); if (numRows != null) phaseLayout.setRowsCount(numRows); else phaseLayout.setRowsCount(1); LayoutGroup phaseGroup = new LayoutGroup(); phaseGroup.setTitle(phaseToSave.getName() + " default group"); phaseGroup.setColumn(0); phaseGroup.setRow(0); phaseGroup.setParentLayout(phaseLayout); List<LayoutGroup> phaseGroups = new ArrayList<LayoutGroup>(); phaseGroups.add(phaseGroup); phaseLayout.setGroups(phaseGroups); phaseToSave.setLayout(phaseLayout); em().persist(phaseToSave); model.addPhase(phaseToSave); } if (root != null && root) { model.setRootPhaseModel(phaseToSave); } else if (root != null && !root && phaseFound != null && model.getRootPhaseModel().getId().equals(phaseFound.getId())) { // Only if phase was root and we want to change it. model.setRootPhaseModel(null); } model = em().merge(model); } return model; } /** * Creates a new {@link LogFrameModel} from the given {@code model}. * * @param model * The project model. * @return The {@link LogFrameModel} instance. */ static LogFrameModel createDefaultLogFrameModel(final ProjectModel model) { final LogFrameModel logFrameModel = new LogFrameModel(); logFrameModel.setName("Default log frame"); logFrameModel.setActivitiesGroupsMax(3); logFrameModel.setActivitiesMax(3); logFrameModel.setActivitiesPerExpectedResultMax(3); logFrameModel.setActivitiesPerGroupMax(3); logFrameModel.setEnableActivitiesGroups(true); logFrameModel.setEnableExpectedResultsGroups(true); logFrameModel.setExpectedResultsGroupsMax(3); logFrameModel.setExpectedResultsMax(3); logFrameModel.setExpectedResultsPerGroupMax(3); logFrameModel.setExpectedResultsPerSpecificObjectiveMax(3); logFrameModel.setSpecificObjectivesGroupsMax(3); logFrameModel.setEnableSpecificObjectivesGroups(true); logFrameModel.setSpecificObjectivesMax(3); logFrameModel.setSpecificObjectivesPerGroupMax(3); logFrameModel.setPrerequisitesGroupsMax(3); logFrameModel.setEnablePrerequisitesGroups(true); logFrameModel.setPrerequisitesMax(3); logFrameModel.setPrerequisitesPerGroupMax(3); logFrameModel.setProjectModel(model); return logFrameModel; } }