package org.sigmah.server.service.util;
/*
* #%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 com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.Table;
import javax.persistence.TypedQuery;
import org.sigmah.client.util.AdminUtil;
import org.sigmah.server.computation.ServerComputations;
import org.sigmah.server.computation.ServerDependencyResolver;
import org.sigmah.server.dao.ContactModelDAO;
import org.sigmah.server.domain.ContactModel;
import org.sigmah.server.domain.OrgUnitModel;
import org.sigmah.server.domain.ProjectModel;
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.BudgetRatioElement;
import org.sigmah.server.domain.element.BudgetSubField;
import org.sigmah.server.domain.element.ComputationElement;
import org.sigmah.server.domain.element.DefaultFlexibleElement;
import org.sigmah.server.domain.element.FilesListElement;
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.element.TextAreaElement;
import org.sigmah.server.domain.element.BudgetElement;
import org.sigmah.server.domain.element.BudgetSubField;
import org.sigmah.server.domain.element.ComputationElement;
import org.sigmah.server.domain.element.DefaultFlexibleElement;
import org.sigmah.server.domain.element.FilesListElement;
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.element.TextAreaElement;
import org.sigmah.server.domain.element.*;
import org.sigmah.server.domain.layout.LayoutConstraint;
import org.sigmah.server.domain.layout.LayoutGroup;
import org.sigmah.server.domain.profile.PrivacyGroup;
import org.sigmah.server.domain.report.ProjectReportModel;
import org.sigmah.server.mapper.Mapper;
import org.sigmah.shared.computation.Computation;
import org.sigmah.shared.computation.Computations;
import org.sigmah.shared.computation.DependencyResolver;
import org.sigmah.shared.dto.category.CategoryTypeDTO;
import org.sigmah.shared.dto.element.BudgetSubFieldDTO;
import org.sigmah.shared.dto.element.FlexibleElementDTO;
import org.sigmah.shared.dto.layout.LayoutConstraintDTO;
import org.sigmah.shared.dto.layout.LayoutGroupDTO;
import org.sigmah.shared.dto.profile.PrivacyGroupDTO;
import org.sigmah.shared.dto.referential.ContactModelType;
import org.sigmah.shared.dto.referential.DefaultFlexibleElementType;
import org.sigmah.shared.dto.referential.ElementTypeEnum;
import org.sigmah.shared.dto.referential.LogicalElementType;
import org.sigmah.shared.dto.referential.LogicalElementTypes;
import org.sigmah.shared.dto.report.ReportModelDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Maxime Lombard (mlombard@ideia.fr) (v2.0)
* @author Denis Colliot (dcolliot@ideia.fr) (v2.0)
*/
public class ModelUtil {
/**
* Logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(ModelUtil.class);
private final Provider<EntityManager> entityManagerProvider;
private final Mapper mapper;
private final ContactModelDAO contactModelDAO;
/**
* Injected {@link ServerDependencyResolver}.
*/
@Inject
private ServerDependencyResolver dependencyResolver;
@Inject
public ModelUtil(Provider<EntityManager> entityManagerProvider, Mapper mapper, ContactModelDAO contactModelDAO) {
this.entityManagerProvider = entityManagerProvider;
this.mapper = mapper;
this.contactModelDAO = contactModelDAO;
}
public void persistFlexibleElement(final PropertyMap changes, final Object model) {
if (changes.get(AdminUtil.PROP_FX_FLEXIBLE_ELEMENT) == null) {
return;
}
EntityManager em = entityManagerProvider.get();
// Common attributes
final String name = changes.get(AdminUtil.PROP_FX_NAME);
final String code = changes.get(AdminUtil.PROP_FX_CODE);
final ElementTypeEnum type = changes.get(AdminUtil.PROP_FX_TYPE);
final Boolean isCompulsory = changes.get(AdminUtil.PROP_FX_IS_COMPULSARY);
final PrivacyGroupDTO pg = changes.get(AdminUtil.PROP_FX_PRIVACY_GROUP);
final Boolean amend = changes.get(AdminUtil.PROP_FX_AMENDABLE);
final Boolean exportable = changes.get(AdminUtil.PROP_FX_EXPORTABLE);
// Position
final LayoutGroupDTO group = changes.get(AdminUtil.PROP_FX_GROUP);
final Integer order = changes.get(AdminUtil.PROP_FX_ORDER_IN_GROUP);
final Boolean inBanner = changes.get(AdminUtil.PROP_FX_IN_BANNER);
final Integer posB;
if (changes.get(AdminUtil.PROP_FX_POS_IN_BANNER) instanceof Integer) {
posB = ((Integer) changes.get(AdminUtil.PROP_FX_POS_IN_BANNER)) - 1;
} else {
posB = null;
}
final Map<String, Object> oldLayoutFields = (Map<String, Object>) changes.get(AdminUtil.PROP_FX_OLD_FIELDS);
final LayoutConstraintDTO oldLayoutConstraintDTO = (LayoutConstraintDTO) oldLayoutFields.get(AdminUtil.PROP_FX_LC);
final LayoutConstraintDTO oldBannerLayoutConstraintDTO = (LayoutConstraintDTO) oldLayoutFields.get(AdminUtil.PROP_FX_LC_BANNER);
final ElementTypeEnum oldType = (ElementTypeEnum) oldLayoutFields.get(AdminUtil.PROP_FX_TYPE);
final Integer oldOrder = (Integer) oldLayoutFields.get(AdminUtil.PROP_FX_ORDER_IN_GROUP);
// Specific attributes
final Character textType = changes.get(AdminUtil.PROP_FX_TEXT_TYPE);
final Number maxLimit = changes.get(AdminUtil.PROP_FX_MAX_LIMIT);
final Number minLimit = changes.get(AdminUtil.PROP_FX_MIN_LIMIT);
final Integer length = changes.get(AdminUtil.PROP_FX_LENGTH);
final Boolean decimal = changes.get(AdminUtil.PROP_FX_DECIMAL);
final ReportModelDTO reportModel = changes.get(AdminUtil.PROP_FX_REPORT_MODEL);
final Boolean isMultiple = changes.get(AdminUtil.PROP_FX_Q_MULTIPLE);
final CategoryTypeDTO category = changes.get(AdminUtil.PROP_FX_Q_CATEGORY);
final List<String> qChoices = changes.get(AdminUtil.PROP_FX_Q_CHOICES);
Set<String> qChoicesDisabled = changes.get(AdminUtil.PROP_FX_Q_CHOICES_DISABLED);
final List<BudgetSubFieldDTO> bSubFields = changes.get(AdminUtil.PROP_FX_B_BUDGETSUBFIELDS);
final BudgetSubFieldDTO ratioDividend = changes.get(AdminUtil.PROP_FX_B_BUDGET_RATIO_DIVIDEND);
final BudgetSubFieldDTO ratioDivisor = changes.get(AdminUtil.PROP_FX_B_BUDGET_RATIO_DIVISOR);
final String computationRule = changes.get(AdminUtil.PROP_FX_COMPUTATION_RULE);
final FlexibleElementDTO budgetSpent = changes.get(AdminUtil.PROP_BUDGET_SPENT);
final FlexibleElementDTO budgetPlanned = changes.get(AdminUtil.PROP_BUDGET_PLANNED);
Number contactListLimit = changes.get(AdminUtil.PROP_FX_CONTACT_LIST_LIMIT);
Boolean contactListIsMember = changes.get(AdminUtil.PROP_FX_CONTACT_LIST_IS_MEMBER);
ContactModelType contactListType = changes.get(AdminUtil.PROP_FX_CONTACT_LIST_ALLOWED_TYPE);
Set<Integer> contactListAllowedModelIds = changes.get(AdminUtil.PROP_FX_CONTACT_LIST_ALLOWED_MODEL_IDS);
final FlexibleElementDTO flexibleEltDTO = changes.get(AdminUtil.PROP_FX_FLEXIBLE_ELEMENT);
FlexibleElement flexibleElt = null;
if (flexibleEltDTO.getId() != null && flexibleEltDTO.getId() > 0) {
flexibleElt = em.find(FlexibleElement.class, flexibleEltDTO.getId());
} else {
flexibleElt = (FlexibleElement) createNewFlexibleElement(em, oldType, type, flexibleElt);
}
if(qChoicesDisabled == null) {
qChoicesDisabled = Collections.emptySet();
}
LOG.debug("Saving : (name {}, type {}, group {}, order {}, inBanner {}, posB {}, isCompulsory {}, pg {}, amend {}, exportable {})",
type, group, order, inBanner, posB, isCompulsory, pg, amend, exportable);
LOG.debug("Also Saving : (maxLimit {}, minLimit {}, textType {}, length {}, decimal {}, reportModel {})",
maxLimit, minLimit, textType, length, decimal, reportModel);
Boolean basicChanges = false;
if (flexibleElt != null) {// update flexible element
// //////////////// First, basic attributes
if (name != null) {
flexibleElt.setLabel(name);
basicChanges = true;
}
if (code != null) {
flexibleElt.setCode(code);
basicChanges = true;
}
if (amend != null) {
flexibleElt.setAmendable(amend);
basicChanges = true;
}
if (exportable != null) {
flexibleElt.setExportable(exportable);
basicChanges = true;
}
if (isCompulsory != null) {
flexibleElt.setValidates(isCompulsory);
basicChanges = true;
}
if (pg != null) {
PrivacyGroup pgToPersist = em.find(PrivacyGroup.class, pg.getId());
if (pgToPersist != null) {
flexibleElt.setPrivacyGroup(pgToPersist);
basicChanges = true;
}
} else if(changes.containsKey(AdminUtil.PROP_FX_PRIVACY_GROUP)) {
flexibleElt.setPrivacyGroup(null);
basicChanges = true;
}
if (basicChanges && flexibleElt.getId() != null)
flexibleElt = em.merge(flexibleElt);
else
em.persist(flexibleElt);
}
// ////////////////Position : Change layout_constraint, reorder
// LayoutGroup parentLayoutGroup = em.find(LayoutGroup.class, new
// Integer(oldGroup.getId()).longValue());
if (group != null) { // group changed
LayoutGroup parentLayoutGroup = em.find(LayoutGroup.class, group.getId());
LayoutConstraint newLayoutConstraint = new LayoutConstraint();
if (parentLayoutGroup != null) {
newLayoutConstraint.setElement(flexibleElt);
newLayoutConstraint.setParentLayoutGroup(parentLayoutGroup);
if (oldOrder != null)
newLayoutConstraint.setSortOrder(oldOrder);
if (order != null)
newLayoutConstraint.setSortOrder(order);
if (order == null && oldOrder == null)
newLayoutConstraint.setSortOrder(new Integer(parentLayoutGroup.getConstraints().size()));
if (oldLayoutConstraintDTO != null) {// Merge
newLayoutConstraint.setId(oldLayoutConstraintDTO.getId());
newLayoutConstraint = em.merge(newLayoutConstraint);
} else {// Persist
em.persist(newLayoutConstraint);
}
}
}
// ////////////////Banner
if (inBanner != null) {// Fact of being or not in banner has changed
if (inBanner) {// New to banner
if (model instanceof ProjectModel || model instanceof OrgUnitModel || model instanceof ContactModel) {
changeBanner(em, posB, model, flexibleElt);
}
} else {// delete from banner
if (oldBannerLayoutConstraintDTO != null) {
LayoutConstraint oldBannerLayoutConstraint = mapper.map(oldBannerLayoutConstraintDTO, new LayoutConstraint());
oldBannerLayoutConstraint = em.find(LayoutConstraint.class, oldBannerLayoutConstraint.getId());
em.remove(oldBannerLayoutConstraint);
}
}
} else {// same state on banner
if (posB != null) {// Position has changed means surely element
if (model instanceof ProjectModel || model instanceof OrgUnitModel || model instanceof ContactModel) {
// was already in banner so there's an old
// banner layout constraint
LayoutConstraint oldBannerLayoutConstraint = mapper.map(oldBannerLayoutConstraintDTO, new LayoutConstraint());
changePositionInBanner(em, posB, model, flexibleElt, oldBannerLayoutConstraint);
}
}
}
// ////////////////Type
if (oldType != null && type != null) {
flexibleElt = (FlexibleElement) createNewFlexibleElement(em, oldType, type, flexibleElt);
LOG.debug("Changed type: '{}'.", flexibleElt.getClass());
}
em.flush();
em.clear();
flexibleElt = em.find(FlexibleElement.class, flexibleElt.getId());
// ////////////////Specific changes
Boolean specificChanges = false;
final LogicalElementType logicalElementType = ServerComputations.logicalElementTypeOf(flexibleElt);
if ((ElementTypeEnum.DEFAULT.equals(oldType) && type == null) && DefaultFlexibleElementType.BUDGET == logicalElementType.toDefaultFlexibleElementType()) {
List<BudgetSubField> budgetFieldsToDelete = new ArrayList<BudgetSubField>();
BudgetElement budgetElement = (BudgetElement) flexibleElt;
budgetFieldsToDelete.addAll(budgetElement.getBudgetSubFields());
budgetElement.getBudgetSubFields().clear();
for (BudgetSubFieldDTO budgetFieldDTO : bSubFields) {
if (budgetFieldDTO.getId() != null && budgetFieldDTO.getId() > 0) {
BudgetSubField b = em.find(BudgetSubField.class, budgetFieldDTO.getId());
if (b != null) {
budgetFieldsToDelete.remove(b);
b.setLabel(budgetFieldDTO.getLabel());
b.setFieldOrder(budgetFieldDTO.getFieldOrder());
b = em.merge(b);
budgetElement.getBudgetSubFields().add(b);
}
} else {
BudgetSubField budgetSubFieldToPersist = new BudgetSubField();
budgetSubFieldToPersist.setLabel(budgetFieldDTO.getLabel());
budgetSubFieldToPersist.setFieldOrder(budgetFieldDTO.getFieldOrder());
budgetSubFieldToPersist.setBudgetElement(budgetElement);
em.persist(budgetSubFieldToPersist);
budgetElement.getBudgetSubFields().add(budgetSubFieldToPersist);
}
}
for (BudgetSubField budgetFieldTODelete : budgetFieldsToDelete) {
budgetFieldTODelete.setBudgetElement(null);
em.remove(budgetFieldTODelete);
}
if (ratioDividend != null) {
BudgetSubField budgetRatio = new BudgetSubField();
budgetRatio.setId(ratioDividend.getId());
budgetElement.setRatioDividend(budgetRatio);
}
if (ratioDivisor != null) {
BudgetSubField budgetRatio = new BudgetSubField();
budgetRatio.setId(ratioDivisor.getId());
budgetElement.setRatioDivisor(budgetRatio);
}
flexibleElt = em.merge(budgetElement);
} else if ((ElementTypeEnum.DEFAULT.equals(oldType) && type == null) && DefaultFlexibleElementType.BUDGET_RATIO == logicalElementType.toDefaultFlexibleElementType()) {
BudgetRatioElement budgetRatioElement = (BudgetRatioElement) flexibleElt;
if (budgetSpent != null) {
FlexibleElement flexibleElement = new DefaultFlexibleElement();
flexibleElement.setId(budgetSpent.getId());
budgetRatioElement.setSpentBudget(flexibleElement);
}
if (budgetPlanned != null) {
FlexibleElement flexibleElement = new DefaultFlexibleElement();
flexibleElement.setId(budgetPlanned.getId());
budgetRatioElement.setPlannedBudget(flexibleElement);
}
flexibleElt = em.merge(budgetRatioElement);
} else if (ElementTypeEnum.FILES_LIST.equals(type) || (ElementTypeEnum.FILES_LIST.equals(oldType) && type == null)) {
FilesListElement filesListElement = (FilesListElement) flexibleElt;
// FilesListElement filesListElement =
// em.find(FilesListElement.class, flexibleElt.getId());
if (filesListElement != null) {
if (maxLimit != null) {
filesListElement.setLimit(maxLimit.intValue());
specificChanges = true;
}
if (specificChanges) {
filesListElement = em.merge(filesListElement);
flexibleElt = filesListElement;
}
}
} else if (ElementTypeEnum.TEXT_AREA.equals(type) || (ElementTypeEnum.TEXT_AREA.equals(oldType) && type == null)) {
TextAreaElement textAreaElement = (TextAreaElement) flexibleElt;
if (textAreaElement != null) {
if (maxLimit != null) {
((TextAreaElement) flexibleElt).setMaxValue(maxLimit.longValue());
specificChanges = true;
}
if (minLimit != null) {
((TextAreaElement) flexibleElt).setMinValue(minLimit.longValue());
specificChanges = true;
}
if (length != null) {
((TextAreaElement) flexibleElt).setLength(length);
specificChanges = true;
}
if (decimal != null) {
((TextAreaElement) flexibleElt).setIsDecimal(decimal);
specificChanges = true;
}
if (textType != null) {
((TextAreaElement) flexibleElt).setType(textType);
specificChanges = true;
}
if (specificChanges) {
flexibleElt = em.merge((TextAreaElement) flexibleElt);
}
}
} else if (ElementTypeEnum.REPORT.equals(type) || (ElementTypeEnum.REPORT.equals(oldType) && type == null)) {
ReportElement reportElement = em.find(ReportElement.class, flexibleElt.getId());
if (reportElement != null) {
if (reportModel != null && reportModel.getName() != null) {
ProjectReportModel reportId = findReportModel(em, reportModel.getName());
((ReportElement) flexibleElt).setModel(reportId);
specificChanges = true;
}
if (specificChanges) {
flexibleElt = em.merge((ReportElement) flexibleElt);
}
}
} else if (ElementTypeEnum.REPORT_LIST.equals(type) || (ElementTypeEnum.REPORT_LIST.equals(oldType) && type == null)) {
ReportListElement reportElement = em.find(ReportListElement.class, flexibleElt.getId());
if (reportElement != null) {
// BUGFIX #760: Verifiying that reportModel is not null before accessing its name.
if (reportModel != null && reportModel.getName() != null) {
ProjectReportModel reportId = findReportModel(em, reportModel.getName());
((ReportListElement) flexibleElt).setModel(reportId);
specificChanges = true;
}
if (specificChanges) {
flexibleElt = em.merge((ReportListElement) flexibleElt);
}
}
} else if (ElementTypeEnum.QUESTION.equals(type) || (ElementTypeEnum.QUESTION.equals(oldType) && type == null)) {
QuestionElement questionElement = em.find(QuestionElement.class, flexibleElt.getId());
if (questionElement != null) {
if (isMultiple != null) {
((QuestionElement) flexibleElt).setMultiple(isMultiple);
specificChanges = true;
}
if (category != null) {
for (QuestionChoiceElement choiceElt : ((QuestionElement) flexibleElt).getChoices()) {
em.remove(choiceElt);
}
CategoryType categoryType = em.find(CategoryType.class, category.getId());
if (categoryType != null) {
((QuestionElement) flexibleElt).setCategoryType(categoryType);
List<QuestionChoiceElement> choices = new ArrayList<QuestionChoiceElement>();
int i = 0;
for (CategoryElement catElt : categoryType.getElements()) {
QuestionChoiceElement qChoice = new QuestionChoiceElement();
qChoice.setLabel("");
qChoice.setCategoryElement(catElt);
qChoice.setParentQuestion(questionElement);
qChoice.setSortOrder(i++);
choices.add(qChoice);
}
((QuestionElement) flexibleElt).setChoices(choices);
specificChanges = true;
}
} else if (qChoices != null && qChoices.size() > 0) {
for (QuestionChoiceElement choiceElt : ((QuestionElement) flexibleElt).getChoices()) {
em.remove(choiceElt);
}
((QuestionElement) flexibleElt).setCategoryType(null);
List<QuestionChoiceElement> choices = new ArrayList<QuestionChoiceElement>();
int i = 0;
for (String choiceLabel : qChoices) {
QuestionChoiceElement qChoice = new QuestionChoiceElement();
qChoice.setLabel(choiceLabel);
qChoice.setParentQuestion(questionElement);
qChoice.setSortOrder(i++);
qChoice.setDisabled(qChoicesDisabled.contains(choiceLabel));
choices.add(qChoice);
}
((QuestionElement) flexibleElt).setChoices(choices);
specificChanges = true;
}
if (specificChanges) {
flexibleElt = em.merge((QuestionElement) flexibleElt);
}
}
} else if (type == ElementTypeEnum.COMPUTATION || (type == null && oldType == ElementTypeEnum.COMPUTATION)) {
ComputationElement computationElement = (ComputationElement) flexibleElt;
if (computationElement != null) {
if (computationRule != null) {
final String rule = resolveComputationRule(em, dependencyResolver, model, computationRule);
computationElement.setRule(rule);
specificChanges = true;
removeAllValuesForElement(computationElement, em);
}
if (minLimit != null) {
computationElement.setMinimumValue(minLimit.toString());
specificChanges = true;
}
if (maxLimit != null) {
computationElement.setMaximumValue(maxLimit.toString());
specificChanges = true;
}
if (specificChanges) {
flexibleElt = em.merge(computationElement);
}
}
} else if (type == ElementTypeEnum.CONTACT_LIST || (type == null && oldType == ElementTypeEnum.CONTACT_LIST)) {
ContactListElement contactListElement = (ContactListElement) flexibleElt;
if (contactListElement != null) {
if ((contactListElement.getLimit() > 0 && contactListLimit == null) || (contactListLimit != null && contactListElement.getLimit() != contactListLimit.intValue())) {
contactListElement.setLimit(contactListLimit == null ? 0 : contactListLimit.intValue());
specificChanges = true;
}
if (contactListElement.getAllowedType() != contactListType) {
contactListElement.setAllowedType(contactListType);
specificChanges = true;
}
if (contactListElement.isMember() != contactListIsMember) {
contactListElement.setMember(contactListIsMember);
specificChanges = true;
}
// Let's check if there are newly added or removed allowed contact models
Set<Integer> modelsToCompare = new HashSet<>(contactListAllowedModelIds);
boolean contactModelsModified = false;
for (ContactModel contactModel : contactListElement.getAllowedModels()) {
// If the current contact model cannot be removed from the new set,
// it means that it was removed
if (!modelsToCompare.remove(contactModel.getId())) {
contactModelsModified = true;
break;
}
}
// If there are remaining models in the set, it means these ones were newly added
if (!modelsToCompare.isEmpty()) {
contactModelsModified = true;
}
if (contactModelsModified) {
contactListElement.setAllowedModels(contactModelDAO.findByIds(contactListAllowedModelIds));
specificChanges = true;
}
if (specificChanges) {
flexibleElt = em.merge(contactListElement);
}
}
}
em.flush();
em.clear();
}
/**
* Parse and resolve each dependency contained in the given formula.
*
* @param em
* Instance of the EntityManager
* @param dependencyResolver
* Dependency resolver to use.
* @param model
* Project or org unit model.
* @param computationRule
* Formula to parse and format.
* @return The formula with its dependencies resolved.
* @throws IllegalArgumentException If a dependency could not be resolved.
*/
private static String resolveComputationRule(final EntityManager em, final DependencyResolver dependencyResolver, final Object model, final String computationRule) throws IllegalArgumentException {
if (dependencyResolver != null && model instanceof ProjectModel) {
final ProjectModel projectModel = em.find(ProjectModel.class, ((ProjectModel) model).getId());
final Computation computation = Computations.parse(computationRule, ServerComputations.getAllElementsFromModel(projectModel));
dependencyResolver.resolve(computation);
if (!computation.isResolved()) {
throw new IllegalArgumentException("Computation '" + computationRule + "' could not be resolved.");
}
return computation.toString();
}
return computationRule;
}
private String retrieveTable(final String className) {
final int bI = className.lastIndexOf(".") + 1;
String table = className.substring(bI);
try {
final Class<?> c = Class.forName(className);
final Table tableAnnotation = c.getAnnotation(Table.class);
table = tableAnnotation.name();
} catch (final Exception e) {
LOG.error("Exception while retrieving 'table' annotation from the flexible element of type '" + className + "'.", e);
}
return table;
}
private void changeOldType(final EntityManager em, final ElementTypeEnum type, final FlexibleElement flexibleElement) {
final String oldflexTable = retrieveTable(ElementTypeEnum.getClassName(type));
if (oldflexTable != null) {
// If it is a question element, should delete the child choices
if (oldflexTable.equals("question_element")) {
em.createNativeQuery("Delete from " + "question_choice_element" + " where " + "id_question = :flexId").setParameter("flexId", flexibleElement.getId())
.executeUpdate();
}
em.createNativeQuery("Delete from " + oldflexTable + " where " + "id_flexible_element = :flexId").setParameter("flexId", flexibleElement.getId())
.executeUpdate();
}
}
private Object createNewFlexibleElement(final EntityManager em, final ElementTypeEnum oldType, final ElementTypeEnum type,
final FlexibleElement flexibleElement) {
Object newElement = null;
try {
final Class<?> elementClass = Class.forName(ElementTypeEnum.getClassName(type));
newElement = elementClass.newInstance();
if (flexibleElement != null && flexibleElement.getId() != null && oldType != null) {
LOG.debug("Old Type '{}' (class '{}').", oldType, flexibleElement.getClass());
((FlexibleElement) newElement).setCreationDate(new Date());
((FlexibleElement) newElement).setLabel(flexibleElement.getLabel());
((FlexibleElement) newElement).setPrivacyGroup(flexibleElement.getPrivacyGroup());
((FlexibleElement) newElement).setValidates(flexibleElement.isValidates());
((FlexibleElement) newElement).setAmendable(flexibleElement.isAmendable());
((FlexibleElement) newElement).setExportable(flexibleElement.isExportable());
((FlexibleElement) newElement).setId(flexibleElement.getId());
final String flexTable = retrieveTable(elementClass.getName());
// Update Type
if (flexTable != null) {
changeOldType(em, oldType, flexibleElement);
em.createNativeQuery("INSERT INTO " + flexTable + " (id_flexible_element) " + "Values (:flexId)").setParameter("flexId", flexibleElement.getId())
.executeUpdate();
}
}
} catch (final Exception e) {
LOG.error("Exception while creating new flexible element.", e);
}
return newElement;
}
private void changeBanner(final EntityManager em, final Integer posB, final Object model, final FlexibleElement flexibleElt) {
final LayoutGroup bannerGroup;
if (model instanceof ProjectModel) {
bannerGroup = ((ProjectModel) model).getProjectBanner().getLayout().getGroups().get(posB);
} else if (model instanceof OrgUnitModel) {
bannerGroup = ((OrgUnitModel) model).getBanner().getLayout().getGroups().get(posB);
} else if (model instanceof ContactModel) {
// model.getCard().getLayout().getGroups().get(0) => Avatar in contact card
// model.getCard().getLayout().getGroups().get(1) => Contact information in contact card
bannerGroup = ((ContactModel) model).getCard().getLayout().getGroups().get(1);
// Just change the order of the affected layout constraint
// it's not important that several elements have the same order in the contact card
for (final LayoutConstraint layoutConstraint : bannerGroup.getConstraints()) {
if (flexibleElt.equals(layoutConstraint.getElement())) {
layoutConstraint.setSortOrder(posB + 1);
em.merge(layoutConstraint);
break;
}
}
return;
} else {
throw new UnsupportedOperationException("Invalid model type.");
}
LayoutConstraint newLayoutConstraint = null;
boolean positionTaken = false;
for (final LayoutConstraint lc : bannerGroup.getConstraints()) {
if (posB.equals(lc.getSortOrder())) {
positionTaken = true;
newLayoutConstraint = lc;
lc.setElement(flexibleElt);
newLayoutConstraint = em.merge(lc);
}
}
if (!positionTaken) {
newLayoutConstraint = new LayoutConstraint();
newLayoutConstraint.setElement(flexibleElt);
newLayoutConstraint.setParentLayoutGroup(bannerGroup);
newLayoutConstraint.setSortOrder(new Integer(posB + 1));
em.persist(newLayoutConstraint);
}
}
private void changePositionInBanner(final EntityManager em, final Integer posB, final Object model, final FlexibleElement flexibleElt,
final LayoutConstraint oldBannerLayoutConstraint) {
final LayoutGroup bannerGroup;
if (model instanceof ProjectModel) {
bannerGroup = ((ProjectModel) model).getProjectBanner().getLayout().getGroups().get(posB);
} else if (model instanceof OrgUnitModel) {
bannerGroup = ((OrgUnitModel) model).getBanner().getLayout().getGroups().get(posB);
} else if (model instanceof ContactModel) {
// model.getCard().getLayout().getGroups().get(0) => Avatar in contact card
// model.getCard().getLayout().getGroups().get(1) => Contact information in contact card
bannerGroup = ((ContactModel) model).getCard().getLayout().getGroups().get(1);
// Just change the order of the affected layout constraint
// it's not important that several elements have the same order in the contact card
for (final LayoutConstraint layoutConstraint : bannerGroup.getConstraints()) {
if (flexibleElt.equals(layoutConstraint.getElement())) {
layoutConstraint.setSortOrder(posB + 1);
em.merge(layoutConstraint);
break;
}
}
return;
} else {
throw new UnsupportedOperationException("Invalid model type.");
}
// Delete any constraint that places another flexible element in the same position.
for (final LayoutConstraint lc : bannerGroup.getConstraints()) {
em.remove(lc);
}
oldBannerLayoutConstraint.setElement(flexibleElt);
oldBannerLayoutConstraint.setParentLayoutGroup(bannerGroup);
oldBannerLayoutConstraint.setSortOrder(new Integer(posB + 1));
em.merge(oldBannerLayoutConstraint);
}
private ProjectReportModel findReportModel(final EntityManager em, final String reportName) {
final TypedQuery<ProjectReportModel> query = em.createQuery("SELECT r FROM ProjectReportModel r WHERE r.name = :name", ProjectReportModel.class);
query.setParameter("name", reportName);
try {
return query.getSingleResult();
} catch (final Exception e) {
return null;
}
}
/**
* Removes every value associated with the given flexible element.
*
* @param element
* Element to purge.
*/
private void removeAllValuesForElement(final FlexibleElement element, final EntityManager em) {
em.createQuery("DELETE FROM Value AS v WHERE v.element = :element")
.setParameter("element", element)
.executeUpdate();
}
}