org.sigmah.server.servlet.exporter.models.ProjectModelHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.sigmah.server.servlet.exporter.models.ProjectModelHandler.java

Source

package org.sigmah.server.servlet.exporter.models;

/*
 * #%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.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.rmi.server.ExportException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import javax.persistence.EntityManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sigmah.server.domain.PhaseModel;
import org.sigmah.server.domain.ProjectModel;
import org.sigmah.server.domain.ProjectModelVisibility;
import org.sigmah.server.domain.User;
import org.sigmah.server.domain.category.CategoryElement;
import org.sigmah.server.domain.category.CategoryType;
import org.sigmah.server.domain.element.BudgetElement;
import org.sigmah.server.domain.element.BudgetSubField;
import org.sigmah.server.domain.element.FlexibleElement;
import org.sigmah.server.domain.element.QuestionChoiceElement;
import org.sigmah.server.domain.element.QuestionElement;
import org.sigmah.server.domain.element.ReportElement;
import org.sigmah.server.domain.element.ReportListElement;
import org.sigmah.server.domain.layout.LayoutConstraint;
import org.sigmah.server.domain.layout.LayoutGroup;
import org.sigmah.server.domain.report.ProjectReportModel;
import org.sigmah.shared.dto.referential.ProjectModelStatus;
import org.sigmah.shared.dto.referential.ProjectModelType;

/**
 * Exports and imports project models.
 * 
 * @author Raphal Calabro (rcalabro@ideia.fr) V1.3
 * @author Mehdi Benabdeslam (mehdi.benabdeslam@netapsys.fr) V2.0
 */
public class ProjectModelHandler implements ModelHandler {

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

    private ProjectModelType projectModelType = ProjectModelType.NGO;

    @Override
    public void importModel(InputStream inputStream, EntityManager em, User user) throws Exception {
        ObjectInputStream objectInputStream;
        em.getTransaction().begin();
        try {
            objectInputStream = new ObjectInputStream(inputStream);
            ProjectModel projectModel = (ProjectModel) objectInputStream.readObject();

            // Sets the new model as a draft.
            projectModel.setStatus(ProjectModelStatus.DRAFT);

            final HashMap<Object, Object> modelesReset = new HashMap<Object, Object>();
            final HashSet<Object> modelesImport = new HashSet<Object>();

            projectModel.resetImport();
            saveProjectFlexibleElement(projectModel, em, modelesReset, modelesImport, user);

            // Attaching the new model to the current user's organization
            final ProjectModelVisibility visibility = new ProjectModelVisibility();
            visibility.setModel(projectModel);
            visibility.setType(projectModelType);
            visibility.setOrganization(user.getOrganization());

            final ArrayList<ProjectModelVisibility> visibilities = new ArrayList<ProjectModelVisibility>();
            visibilities.add(visibility);
            projectModel.setVisibilities(visibilities);

            // Set the status to DRAFT
            projectModel.setStatus(ProjectModelStatus.DRAFT);

            // TODO ??
            for (PhaseModel pm : projectModel.getPhaseModels()) {
                for (LayoutGroup lg : pm.getLayout().getGroups()) {
                    for (LayoutConstraint lc : lg.getConstraints()) {
                        FlexibleElement fe = lc.getElement();
                        System.out.println(fe.getClass() + " id " + fe.getId());
                        if (fe instanceof QuestionElement) {
                            for (QuestionChoiceElement qce : ((QuestionElement) fe).getChoices()) {
                                System.out.println(qce.getClass() + " id " + qce.getId());
                            }
                        }
                    }
                }
            }

            em.merge(projectModel);
            em.getTransaction().commit();
            LOG.debug("The project model '" + projectModel.getName() + "' has been imported successfully.");

        } catch (IOException | ClassNotFoundException e) {
            LOG.debug("Error while importing a project model.", e);
            throw new Exception("Error while importing a project model.", e);
        }
    }

    @Override
    public String exportModel(OutputStream outputStream, String identifier, EntityManager em) throws Exception {

        String name = "";

        if (identifier == null) {
            throw new ExportException("The identifier is missing.");
        }

        final Integer projectModelId = Integer.parseInt(identifier);

        final ProjectModel hibernateModel = em.find(ProjectModel.class, projectModelId);

        if (hibernateModel == null)
            throw new ExportException("No project model is associated with the identifier '" + identifier + "'.");

        name = hibernateModel.getName();

        // Removing superfluous links
        hibernateModel.setVisibilities(null);

        // Stripping hibernate proxies from the model.
        final ProjectModel realModel = Realizer.realize(hibernateModel);

        // Serialization
        try {

            final ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(realModel);

        } catch (Exception ex) {
            throw new Exception("An error occured while serializing the project model " + projectModelId, ex);
        }

        return name;
    }

    /**
     * Define the default project model type used when importing a project model.
     * 
     * @param projectModelType
     */
    public void setProjectModelType(ProjectModelType projectModelType) {
        this.projectModelType = projectModelType;
    }

    /**
     * Save the flexible elements of imported project model.
     * 
     * @param projectModel
     *          the imported project model
     * @param em
     *          the entity manager
     */
    private void saveProjectFlexibleElement(ProjectModel projectModel, EntityManager em,
            HashMap<Object, Object> modelesReset, HashSet<Object> modelesImport, User user) {

        // ProjectModel --> Banner --> Layout --> Groups --> Constraints
        if (projectModel.getProjectBanner() != null && projectModel.getProjectBanner().getLayout() != null) {

            final List<LayoutGroup> bannerLayoutGroups = projectModel.getProjectBanner().getLayout().getGroups();
            saveLayoutGroups(bannerLayoutGroups, em, modelesReset, modelesImport, user);
        }

        // ProjectModel --> Detail --> Layout --> Groups --> Constraints
        if (projectModel.getProjectDetails() != null && projectModel.getProjectDetails().getLayout() != null) {

            final List<LayoutGroup> detailLayoutGroups = projectModel.getProjectDetails().getLayout().getGroups();
            saveLayoutGroups(detailLayoutGroups, em, modelesReset, modelesImport, user);
        }

        // ProjectModel --> Phases --> Layout --> Groups --> Constraints
        List<PhaseModel> phases = projectModel.getPhaseModels();
        if (phases != null) {
            projectModel.setPhaseModels(null);
            em.persist(projectModel);
            for (PhaseModel phase : phases) {
                phase.setParentProjectModel(projectModel);
                if (phase.getLayout() != null) {

                    final List<LayoutGroup> phaseLayoutGroups = phase.getLayout().getGroups();
                    saveLayoutGroups(phaseLayoutGroups, em, modelesReset, modelesImport, user);
                }
                if (phase.getDefinition() != null) {
                    em.persist(phase.getDefinition());
                }
                em.persist(phase);
            }
            projectModel.setPhaseModels(phases);
        }
    }

    private void saveLayoutGroups(final List<LayoutGroup> layoutGroups, EntityManager em,
            HashMap<Object, Object> modelesReset, HashSet<Object> modelesImport, User user) {

        final HashSet<Integer> reportModelsId = new HashSet<Integer>();

        if (layoutGroups != null) {
            for (LayoutGroup layoutGroup : layoutGroups) {

                final List<LayoutConstraint> layoutConstraints;
                if (layoutGroup != null)
                    layoutConstraints = layoutGroup.getConstraints();
                else
                    layoutConstraints = null;

                if (layoutConstraints != null) {
                    // Iterating over the constraints
                    for (LayoutConstraint layoutConstraint : layoutConstraints) {
                        if (layoutConstraint != null && layoutConstraint.getElement() != null) {
                            final FlexibleElement element = layoutConstraint.getElement();

                            // Do not persist an element twice.
                            if (em.contains(element)) {
                                continue;
                            }

                            // Initialize export flags of flexible element
                            element.initializeExportFlags();

                            // If the current element is a QuestionElement
                            if (element instanceof QuestionElement) {
                                final QuestionElement questionElement = (QuestionElement) element;
                                List<QuestionChoiceElement> questionChoiceElements = questionElement.getChoices();
                                CategoryType type = questionElement.getCategoryType();
                                if (questionChoiceElements != null || type != null) {

                                    questionElement.setChoices(null);
                                    questionElement.setCategoryType(null);
                                    em.persist(questionElement);

                                    // Save QuestionChoiceElement with their
                                    // QuestionElement parent(saved above)
                                    if (questionChoiceElements != null) {
                                        for (QuestionChoiceElement questionChoiceElement : questionChoiceElements) {
                                            if (questionChoiceElement != null) {
                                                questionChoiceElement.setId(null);
                                                questionChoiceElement.setParentQuestion(questionElement);
                                                CategoryElement categoryElement = questionChoiceElement
                                                        .getCategoryElement();
                                                if (categoryElement != null) {
                                                    questionChoiceElement.setCategoryElement(null);

                                                    em.persist(questionChoiceElement);
                                                    saveProjectModelCategoryElement(categoryElement, em,
                                                            modelesReset, modelesImport);
                                                    questionChoiceElement.setCategoryElement(categoryElement);
                                                    em.merge(questionChoiceElement);
                                                } else {
                                                    em.persist(questionChoiceElement);
                                                }
                                            }
                                        }
                                        // Set saved QuestionChoiceElement to
                                        // QuestionElement parent and update it
                                        questionElement.setChoices(questionChoiceElements);
                                    }

                                    // Save the Category type of QuestionElement
                                    // parent(saved above)
                                    if (type != null) {
                                        if (em.find(CategoryType.class, type.getId()) == null) {
                                            List<CategoryElement> typeElements = type.getElements();
                                            if (typeElements != null) {
                                                type.setElements(null);
                                                em.merge(type);
                                                for (CategoryElement categoryElement : typeElements) {
                                                    if (em.find(CategoryElement.class,
                                                            categoryElement.getId()) == null) {
                                                        categoryElement.setParentType(type);
                                                        saveProjectModelCategoryElement(categoryElement, em,
                                                                modelesReset, modelesImport);
                                                    }
                                                }
                                                type.setElements(typeElements);
                                                em.merge(type);
                                            }
                                        }
                                        // Set the saved CategoryType to
                                        // QuestionElement parent and update it
                                        questionElement.setCategoryType(type);
                                    }
                                    // Update the QuestionElement parent
                                    em.merge(questionElement);

                                } else {
                                    em.persist(element);
                                }
                            }
                            // Report element
                            else if (element instanceof ReportElement) {
                                final ReportElement reportElement = (ReportElement) element;
                                final ProjectReportModel oldModel = reportElement.getModel();

                                if (oldModel != null) {
                                    final int oldModelId = oldModel.getId();
                                    final ProjectReportModel newModel;

                                    if (!reportModelsId.contains(oldModelId)) {
                                        oldModel.resetImport(new HashMap<Object, Object>(), new HashSet<Object>());
                                        oldModel.setOrganization(user.getOrganization());
                                        newModel = oldModel;
                                        ProjectReportModelHandler.saveProjectReportModelElement(newModel, em);
                                        em.persist(newModel);
                                        reportElement.setModel(newModel);
                                        em.persist(reportElement);
                                        reportModelsId.add(reportElement.getModel().getId());
                                    }
                                    // If the report model has been already
                                    // saved, it is re-used.
                                    else {
                                        newModel = em.find(ProjectReportModel.class, oldModelId);
                                        reportElement.setModel(newModel);
                                        em.persist(reportElement);
                                    }

                                }

                            }
                            // Reports list element
                            else if (element instanceof ReportListElement) {
                                final ReportListElement reportListElement = (ReportListElement) element;
                                final ProjectReportModel oldModel = reportListElement.getModel();

                                if (oldModel != null) {
                                    final int oldModelId = oldModel.getId();
                                    final ProjectReportModel newModel;

                                    if (!reportModelsId.contains(oldModelId)) {
                                        oldModel.resetImport(new HashMap<Object, Object>(), new HashSet<Object>());
                                        oldModel.setOrganization(user.getOrganization());
                                        newModel = oldModel;
                                        ProjectReportModelHandler.saveProjectReportModelElement(newModel, em);
                                        em.persist(newModel);
                                        reportListElement.setModel(newModel);
                                        em.persist(reportListElement);
                                        reportModelsId.add(reportListElement.getModel().getId());
                                    }
                                    // If the report model has been already
                                    // saved, it is re-used.
                                    else {
                                        newModel = em.find(ProjectReportModel.class, oldModelId);
                                        reportListElement.setModel(newModel);
                                        em.persist(reportListElement);
                                    }
                                }
                            }
                            // Budget element
                            else if (element instanceof BudgetElement) {
                                final BudgetElement budgetElement = (BudgetElement) element;

                                final List<BudgetSubField> subFields = budgetElement.getBudgetSubFields();
                                final BudgetSubField ratioDividend = budgetElement.getRatioDividend();
                                final BudgetSubField ratioDivisor = budgetElement.getRatioDivisor();

                                budgetElement.setBudgetSubFields(null);
                                budgetElement.setRatioDividend(null);
                                budgetElement.setRatioDivisor(null);

                                em.persist(budgetElement);

                                final ArrayList<BudgetSubField> allSubFields = new ArrayList<BudgetSubField>(
                                        subFields);
                                allSubFields.add(ratioDividend);
                                allSubFields.add(ratioDivisor);

                                for (final BudgetSubField subField : allSubFields) {
                                    subField.setBudgetElement(budgetElement);
                                    em.persist(budgetElement);
                                }
                                budgetElement.setBudgetSubFields(subFields);
                                budgetElement.setRatioDividend(ratioDividend);
                                budgetElement.setRatioDivisor(ratioDivisor);
                                em.merge(budgetElement);
                            }
                            // Others elements
                            else {
                                em.persist(layoutConstraint.getElement());
                            }
                        }
                    }
                }
            }
        }

    }

    /**
     * Save the category element of a question choice element.
     * 
     * @param categoryElement
     *          the category element to save.
     * @param em
     *          the entity manager.
     */
    private void saveProjectModelCategoryElement(CategoryElement categoryElement, EntityManager em,
            HashMap<Object, Object> modelesReset, HashSet<Object> modelesImport) {
        if (!modelesImport.contains(categoryElement)) {
            modelesImport.add(categoryElement);

            if (!modelesReset.containsKey(categoryElement)) {
                CategoryElement key = categoryElement;
                modelesReset.put(key, categoryElement);
                categoryElement.setId(null);

                CategoryType parentType = categoryElement.getParentType();
                if (!modelesImport.contains(parentType)) {
                    modelesImport.add(parentType);

                    if (!modelesReset.containsKey(parentType)) {
                        CategoryType parentKey = parentType;
                        modelesReset.put(parentKey, parentType);
                        parentType.setId(null);

                        List<CategoryElement> elements = parentType.getElements();
                        if (elements != null) {
                            parentType.setElements(null);
                            em.persist(parentType);
                            for (CategoryElement element : elements) {
                                categoryElement.setParentType(parentType);
                                saveProjectModelCategoryElement(element, em, modelesReset, modelesImport);
                            }
                            parentType.setElements(elements);
                            em.merge(parentType);
                        } else {
                            em.persist(parentType);
                        }
                    } else {
                        parentType = (CategoryType) modelesReset.get(parentType);
                    }
                }
                categoryElement.setParentType(parentType);
                em.persist(categoryElement);
            } else {
                categoryElement = (CategoryElement) modelesReset.get(categoryElement);
            }
        }
    }
}