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 com.google.inject.Inject;
import com.google.inject.Singleton;
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 javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import org.sigmah.server.dao.ContactDAO;
import org.sigmah.server.dao.CountryDAO;
import org.sigmah.server.dao.base.EntityManagerProvider;
import org.sigmah.server.domain.Contact;
import org.sigmah.server.domain.Country;
import org.sigmah.server.domain.HistoryToken;
import org.sigmah.server.domain.OrgUnit;
import org.sigmah.server.domain.Project;
import org.sigmah.server.domain.ProjectFunding;
import org.sigmah.server.domain.ProjectModel;
import org.sigmah.server.domain.User;
import org.sigmah.server.domain.element.ComputationElement;
import org.sigmah.server.domain.element.DefaultContactFlexibleElement;
import org.sigmah.server.domain.element.DefaultFlexibleElement;
import org.sigmah.server.domain.element.FlexibleElement;
import org.sigmah.server.domain.layout.LayoutGroupIteration;
import org.sigmah.server.domain.value.TripletValue;
import org.sigmah.server.domain.value.Value;
import org.sigmah.server.mapper.Mapper;
import org.sigmah.shared.dto.element.FlexibleElementDTO;
import org.sigmah.shared.dto.element.event.ValueEventWrapper;
import org.sigmah.shared.dto.referential.DefaultContactFlexibleElementType;
import org.sigmah.shared.dto.referential.DefaultFlexibleElementType;
import org.sigmah.shared.dto.referential.ValueEventChangeType;
import org.sigmah.shared.dto.value.TripletValueDTO;
import org.sigmah.shared.util.ValueResultUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Service handling the update of Value objects.
*
* @author Raphaƫl Calabro (raphael.calabro@netapsys.fr)
* @since 2.2
*/
@Singleton
public class ValueService extends EntityManagerProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(ValueService.class);
/**
* Mapper to transform domain objects into DTO.
*/
@Inject
private Mapper mapper;
/**
* Service to compute values of {@link org.sigmah.server.domain.element.ComputationElement} objects.
*/
@Inject
private ComputationService computationService;
/**
* DAO managing {@link org.sigmah.server.domain.Contact} entities.
*/
@Inject
private ContactDAO contactDAO;
/**
* DAO managing {@link org.sigmah.server.domain.Country} entities.
*/
@Inject
private CountryDAO countryDAO;
/**
* Utility method to ease the save process of a basic flexible element.
*
* The history date will be set to the current date and no comment will be
* saved.
*
* @param value
* Value to save.
* @param element
* Flexible element to update.
* @param containerId
* Identifier of the parent container.
* @param iterationId
* Identifier of the iteration to update.
* @param user
* Author of the modification.
* @see #saveValue(java.lang.String, java.util.Date, org.sigmah.server.domain.element.FlexibleElement, java.lang.Integer, java.lang.Integer, org.sigmah.server.domain.User, java.lang.String)
*/
public void saveValue(final String value, final FlexibleElement element, final Integer containerId, final Integer iterationId, final User user) {
saveValue(value, new Date(), element, containerId, iterationId, user, null);
}
/**
* Save the value of the given flexible element. This method is used for
* elements storing a single value.
*
* @param value
* Value to save.
* @param historyDate
* Date of the modification.
* @param element
* Flexible element to update.
* @param containerId
* Identifier of the parent container.
* @param iterationId
* Identifier of the iteration to update.
* @param user
* Author of the modification.
* @param comment
* Comment about the update.
*/
public void saveValue(final String value, final Date historyDate, final FlexibleElement element, final Integer containerId, final Integer iterationId, final User user, final String comment) {
LOGGER.debug("[saveValue] Basic value case.");
// Retrieving the current value
final Value currentValue = retrieveOrCreateValue(containerId, element.getId(), iterationId, user);
currentValue.setValue(value);
// Store the value.
em().merge(currentValue);
// Historize the value.
historize(historyDate, element, containerId, iterationId, user, value, comment);
updateImpactedComputations(element, containerId, user);
}
/**
* Save the given value for the given default flexible element.
*
* @param value
* Value to save.
* @param isProjectCountryChanged
* <code>true</code> if the country was changed by the user.
* @param historyDate
* Date of the modification.
* @param element
* Flexible element to update.
* @param containerId
* Identifier of the parent container.
* @param user
* Author of the modification.
* @param comment
* Comment about the update.
*/
public void saveValue(final String value, final boolean isProjectCountryChanged, final Date historyDate, final DefaultFlexibleElement element, final Integer containerId, final User user, final String comment) {
LOGGER.debug("[execute] Default element case '{}'.", element.getType());
// Saves the value and switch to the next value.
final String oldValue = saveDefaultElement(containerId, element.getType(), value, isProjectCountryChanged);
// Checks if the first value has already been historized or not.
final TypedQuery<HistoryToken> query =
em().createQuery("SELECT h FROM HistoryToken h WHERE h.elementId = :elementId AND h.projectId = :containerId", HistoryToken.class);
query.setParameter("elementId", element.getId());
query.setParameter("containerId", containerId);
final List<HistoryToken> results = query.getResultList();
if (results == null || results.isEmpty()) {
final Date oldDate;
final User oldOwner;
final Project project = em().find(Project.class, containerId);
if (project != null) {
oldDate = project.getLastSchemaUpdate();
oldOwner = project.getOwner();
} else {
oldDate = new Date(historyDate.getTime() - 1);
oldOwner = null;
}
// Historize the first value.
if (oldValue != null) {
historize(oldDate, element, containerId, null, oldOwner, ValueEventChangeType.ADD, oldValue, null, null);
}
}
// Historize the value.
historize(historyDate, element, containerId, null, user, ValueEventChangeType.EDIT, value, null, comment);
}
/**
* Save the given value for the given default contact flexible element.
*
* @param value
* Value to save.
* @param historyDate
* Date of the modification.
* @param element
* Flexible element to update.
* @param contact
* Parent container.
* @param iterationId
* Identifier of the iteration to update.
* @param user
* Author of the modification.
* @param comment
* Comment about the update.
*/
public void saveValue(final String value, final Date historyDate, final DefaultContactFlexibleElement element, final Contact contact, final Integer iterationId, final User user, final String comment) {
LOGGER.debug("[saveValue] Default contact element case '{}'.", element.getType());
if (!element.getType().isUpdatable()) {
return;
}
// Saves the value and switch to the next value.
final String oldValue = saveDefaultElement(contact, element.getType(), value);
// Checks if the first value has already been historized or not.
final TypedQuery<HistoryToken> query =
em().createQuery("SELECT h FROM HistoryToken h WHERE h.elementId = :elementId AND h.projectId = :contactId AND h.layoutGroupIterationId = :iterationId", HistoryToken.class);
query.setParameter("elementId", element.getId());
query.setParameter("contactId", contact.getId());
query.setParameter("iterationId", iterationId);
final List<HistoryToken> results = query.getResultList();
if ((results == null || results.isEmpty()) && oldValue != null) {
// Historize the first value.
historize(contact.getDateCreated(), element, contact.getId(), iterationId, null, ValueEventChangeType.ADD, oldValue, null, null);
}
// Historize the value.
historize(historyDate, element, contact.getId(), iterationId, user, ValueEventChangeType.EDIT, value, null, comment);
}
/**
* Save the value of a {@link org.sigmah.server.domain.element.TripletsListElement}.
*
* @param value
* Triplet value to save.
* @param changeType
* Type of the modification (add, edit or remove).
* @param historyDate
* Date of the modification.
* @param element
* Flexible element to update.
* @param containerId
* Identifier of the parent container.
* @param iterationId
* Identifier of the iteration to update.
* @param user
* Author of the modification.
* @param comment
* Comment about the update.
*/
public void saveValue(final TripletValueDTO value, final ValueEventChangeType changeType, final Date historyDate, final FlexibleElement element, final Integer containerId, final Integer iterationId, final User user, final String comment) {
LOGGER.debug("[saveValue] List value case.");
// Retrieving the current value
final Value currentValue = retrieveOrCreateValue(containerId, element.getId(), iterationId, user);
// The value of the element is a list of ids (default separated).
final List<Integer> ids = ValueResultUtils.splitValuesAsInteger(currentValue.getValue());
LOGGER.debug("[saveValue] The current list of ids is : {}.", ids);
// Cast the update value (as a DTO).
switch (changeType) {
case ADD:
onAdd(value, ids, currentValue, historyDate, element, containerId, iterationId, user, comment);
break;
case REMOVE:
onDelete(value, ids, currentValue, historyDate, element, containerId, iterationId, user, comment);
break;
case EDIT:
onEdit(value, historyDate, element, containerId, iterationId, user, comment);
break;
default:
LOGGER.warn("[saveValue] Unknown command {}.", changeType);
break;
}
LOGGER.debug("[saveValue] The new list of ids is : {}. ", ids);
// Store the value.
em().merge(currentValue);
}
/**
* Save the value of a multivalued flexible element.
*
* @param multivaluedIdsValue
* Value to save.
* @param changeType
* Type of the modification (add, edit or remove).
* @param historyDate
* Date of the modification.
* @param element
* Flexible element to update.
* @param containerId
* Identifier of the parent container.
* @param iterationId
* Identifier of the iteration to update.
* @param user
* Author of the modification.
* @param comment
* Comment about the update.
*/
public void saveValue(final Set<Integer> multivaluedIdsValue, final ValueEventWrapper changeType, final Date historyDate, final FlexibleElement element, final Integer containerId, final Integer iterationId, final User user, final String comment) {
LOGGER.debug("[saveValue] Multivalued ids value case.");
// Retrieving the current value
final Value currentValue = retrieveOrCreateValue(containerId, element.getId(), iterationId, user);
final Set<Integer> ids;
switch (changeType.getChangeType()) {
case ADD:
ids = getCurrentIdsSet(currentValue);
ids.addAll(multivaluedIdsValue);
break;
case REMOVE:
ids = getCurrentIdsSet(currentValue);
ids.removeAll(multivaluedIdsValue);
break;
case EDIT:
ids = multivaluedIdsValue;
break;
default:
throw new IllegalStateException("Unknown ValueEventChangeType : " + changeType.getChangeType());
}
final String serializedValue = ValueResultUtils.mergeElements(new ArrayList<>(ids));
currentValue.setValue(serializedValue);
if (changeType.getChangeType() == ValueEventChangeType.EDIT) {
historize(historyDate, element, containerId, iterationId, user, changeType.getChangeType(), serializedValue, null, comment);
} else {
for (final Integer id : multivaluedIdsValue) {
historize(historyDate, element, containerId, iterationId, user, changeType.getChangeType(), String.valueOf(id), null, comment);
}
}
// Store the value.
em().merge(currentValue);
}
/**
* Parse the given value into a set of identifiers.
*
* @param currentValue
* Value containing a string of identifiers.
* @return A set of identifiers.
*/
private Set<Integer> getCurrentIdsSet(final Value currentValue) {
final Set<Integer> currentIds = new HashSet<>();
if (currentValue != null && currentValue.getValue() != null && !currentValue.getValue().isEmpty()) {
currentIds.addAll(ValueResultUtils.splitValuesAsInteger(currentValue.getValue()));
}
return currentIds;
}
/**
* Finds the current value of the given element from the database and returns it as HTML.
*
* @param containerId
* Identifier of the project.
* @param element
* Element to search.
* @return The value of the given element.
*/
public String getCurrentValueFormatted(int containerId, FlexibleElementDTO element) {
final Value value = retrieveCurrentValue(containerId, element.getId(), null);
if(value != null) {
return element.toHTML(value.getValue());
} else {
return "";
}
}
/**
* Retrieves the value for the given project and the given element.
* If there isn't a value yet, it will be created.
*
* @param containerId
* The project id.
* @param elementId
* The source element id.
* @param user
* The user which launch the command.
* @return The value.
*/
public Value retrieveOrCreateValue(final int containerId, final Integer elementId, final User user) {
return retrieveOrCreateValue(containerId, elementId, null, user);
}
/**
* Retrieves the value for the given project, the given element and the
* given iteration.
*
* If there isn't a value yet, it will be created.
*
* @param containerId
* The project id.
* @param elementId
* The source element id.
* @param iterationId
* The iteration id or <code>null</code> if the element is not located in an iteration.
* @param user
* The user which launch the command.
* @return The value.
*/
public Value retrieveOrCreateValue(final int containerId, final Integer elementId, final Integer iterationId, final User user) {
// Retrieving the current value
Value currentValue = retrieveCurrentValue(containerId, elementId, iterationId);
// Update operation.
if (currentValue != null) {
LOGGER.debug("[execute] Retrieves a value for element #{0}.", elementId);
currentValue.setLastModificationAction('U');
}
// Create operation
else {
LOGGER.debug("[execute] Creates a value for element #{0}.", elementId);
currentValue = new Value();
currentValue.setLastModificationAction('C');
// Parent element
final FlexibleElement element = em().find(FlexibleElement.class, elementId);
currentValue.setElement(element);
// Container
currentValue.setContainerId(containerId);
// Iteration
if (iterationId != null) {
final LayoutGroupIteration iteration = em().find(LayoutGroupIteration.class, iterationId);
currentValue.setLayoutGroupIteration(iteration);
}
}
// Updates the value's fields.
currentValue.setLastModificationDate(new Date());
currentValue.setLastModificationUser(user);
return currentValue;
}
/**
* Retrieves the value for the given container and the given element but
* don't create an empty value if none exists.
*
* @param containerId
* The container id.
* @param elementId
* The source element id.
* @return The value or <code>null</code> if not found.
*/
public Value retrieveCurrentValue(int containerId, Integer elementId, Integer iterationId) {
final Query query;
if(iterationId == null) {
query = em().createQuery("SELECT v FROM Value v WHERE v.containerId = :containerId and v.element.id = :elementId and v.layoutGroupIteration.id IS NULL");
query.setParameter("containerId", containerId);
query.setParameter("elementId", elementId);
} else {
query = em().createQuery("SELECT v FROM Value v WHERE v.element.id = :elementId AND v.layoutGroupIteration.id = :iterationId");
query.setParameter("elementId", elementId);
query.setParameter("iterationId", iterationId);
}
Value currentValue = null;
try {
currentValue = (Value) query.getSingleResult();
} catch (NoResultException nre) {
// No current value
}
return currentValue;
}
/**
* Updates the current project with the new value of a default element.
*
* @param id
* The project id.
* @param type
* The type of the default element.
* @param value
* The new value.
* @return The old value.
*/
private String saveDefaultElement(int id, DefaultFlexibleElementType type, String value, boolean isProjectCountryChanged) {
// All default values are managed as strings.
// See DefaultFlexibleElementDTO.getComponent();
if (value == null) {
LOGGER.error("[saveDefaultElement] The value isn't a string and cannot be considered.");
return null;
}
final String stringValue = value;
// Retrieves container.
final Project project = em().find(Project.class, id);
final OrgUnit orgUnit = em().find(OrgUnit.class, id);
if (project == null && orgUnit == null) {
LOGGER.error("[saveDefaultElement] Container with id '{}' not found.", id);
return null;
}
if (project != null) {
LOGGER.debug("[saveDefaultElement] Found project with code '{}'.", project.getName());
} else {
LOGGER.debug("[saveDefaultElement] Found org unit with code '{}'.", orgUnit.getName());
}
final String oldValue;
switch (type) {
case CODE:
if (project != null) {
oldValue = project.getName();
project.setName(stringValue);
} else {
oldValue = orgUnit.getName();
orgUnit.setName(stringValue);
}
LOGGER.debug("[saveDefaultElement] Set container code to '{}'.", stringValue);
break;
case TITLE:
if (project != null) {
oldValue = project.getFullName();
project.setFullName(stringValue);
} else {
oldValue = orgUnit.getFullName();
orgUnit.setFullName(stringValue);
}
LOGGER.debug("[saveDefaultElement] Set container full name to '{}'.", stringValue);
break;
case START_DATE: {
// Decodes timestamp.
if (project != null) {
oldValue = project.getStartDate() == null ? null : String.valueOf(project.getStartDate().getTime());
if ("".equals(stringValue)) {
project.setStartDate(null);
LOGGER.debug("[saveDefaultElement] Set container start date to null.");
} else {
final long timestamp = Long.valueOf(stringValue);
final Date date = new Date(timestamp);
project.setStartDate(date);
LOGGER.debug("[saveDefaultElement] Set container start date to '{}'.", date);
}
} else {
oldValue = null;
}
}
break;
case END_DATE: {
// Decodes timestamp.
if (project != null) {
oldValue = project.getEndDate() == null ? null : String.valueOf(project.getEndDate().getTime());
if ("".equals(stringValue)) {
project.setEndDate(null);
LOGGER.debug("[saveDefaultElement] Set container end date to null.");
} else {
final long timestamp = Long.valueOf(stringValue);
final Date date = new Date(timestamp);
project.setEndDate(date);
LOGGER.debug("[saveDefaultElement] Set container end date to '{}'.", date);
}
} else {
oldValue = null;
}
}
break;
case COUNTRY: {
if (orgUnit != null) {
if (orgUnit.getOfficeLocationCountry() != null) {
oldValue = String.valueOf(orgUnit.getOfficeLocationCountry().getId());
} else {
oldValue = null;
}
// Retrieves country.
final Country country = em().find(Country.class, Integer.valueOf(stringValue));
orgUnit.setOfficeLocationCountry(country);
LOGGER.debug("[saveDefaultElement] Set container country to '{}'.", country.getName());
} else {
oldValue = null;
}
}
break;
case MANAGER: {
if (project != null) {
oldValue = project.getManager() == null ? null : String.valueOf(project.getManager().getId());
// Retrieves manager.
final User manager = em().find(User.class, Integer.valueOf(stringValue));
project.setManager(manager);
LOGGER.debug("[saveDefaultElement] Set container manager to '{}'.", manager.getName());
} else {
oldValue = null;
}
}
break;
case ORG_UNIT: {
if (project != null) {
OrgUnit old = null;
for (OrgUnit p : project.getPartners()) {
old = p;
break;
}
oldValue = old == null ? null : String.valueOf(old.getId());
// Retrieves manager.
final OrgUnit o = em().find(OrgUnit.class, Integer.valueOf(stringValue));
project.getPartners().clear();
project.getPartners().add(o);
if (isProjectCountryChanged) {
LOGGER.debug("Changing country is true.");
project.setCountry(o.getOfficeLocationCountry());
} else {
LOGGER.debug("Changing country is false.");
}
LOGGER.debug("[saveDefaultElement] Set container org unit to '{}'.", o.getFullName());
} else {
oldValue = null;
}
}
break;
default:
LOGGER.error("[saveDefaultElement] Unknown type '{}' for the default flexible elements.", type);
return null;
}
// Updates container.
if (project != null) {
em().merge(project);
} else {
em().merge(orgUnit);
}
LOGGER.debug("[saveDefaultElement] Updates the container.");
return oldValue;
}
/**
* Updates the given contact with the new value of a default element.
*
* @param contact
* The contact to update.
* @param type
* The type of the default element.
* @param value
* The new value.
* @return The old value.
*/
private String saveDefaultElement(final Contact contact, final DefaultContactFlexibleElementType type, final String value) {
// All default values are managed as strings.
// See DefaultContactFlexibleElementDTO.getComponent();
if (value == null) {
LOGGER.error("[saveDefaultElement] The value isn't a string and cannot be considered.");
return null;
}
String oldValue;
switch (type) {
case COUNTRY:
if (contact.getCountry() == null) {
oldValue = null;
} else {
oldValue = String.valueOf(contact.getCountry().getId());
}
if ("".equals(value)) {
contact.setCountry(null);
} else {
Country country = countryDAO.findById(Integer.parseInt(value));
contact.setCountry(country);
}
LOGGER.debug("[saveDefaultElement] Set container country to '{}'.", value);
break;
case DIRECT_MEMBERSHIP:
if (contact.getParent() == null) {
oldValue = null;
} else {
oldValue = String.valueOf(contact.getParent().getId());
}
if ("".equals(value)) {
contact.setParent(null);
} else {
Contact parent = contactDAO.findById(Integer.parseInt(value));
contact.setParent(parent);
}
LOGGER.debug("[saveDefaultElement] Set container direct membership to '{}'.", value);
break;
case EMAIL_ADDRESS:
oldValue = contact.getEmail();
contact.setEmail(value);
LOGGER.debug("[saveDefaultElement] Set container email to '{}'.", value);
break;
case FIRST_NAME:
oldValue = contact.getFirstname();
contact.setFirstname(value);
LOGGER.debug("[saveDefaultElement] Set container first name to '{}'.", value);
break;
case FAMILY_NAME:
// fall through
case ORGANIZATION_NAME:
oldValue = contact.getName();
contact.setName(value);
LOGGER.debug("[saveDefaultElement] Set container name to '{}'.", value);
break;
case PHONE_NUMBER:
oldValue = contact.getPhoneNumber();
contact.setPhoneNumber(value);
LOGGER.debug("[saveDefaultElement] Set container phone number to '{}'.", value);
break;
case PHOTO:
oldValue = contact.getPhoto();
contact.setPhoto(value);
LOGGER.debug("[saveDefaultElement] Set container photo to '{}'.", value);
break;
case POSTAL_ADDRESS:
oldValue = contact.getPostalAddress();
contact.setPostalAddress(value);
LOGGER.debug("[saveDefaultElement] Set container postal address to '{}'.", value);
break;
// Ignored because they should always be unmodifiable
case CREATION_DATE:
case LOGIN:
case MAIN_ORG_UNIT:
case SECONDARY_ORG_UNITS:
case TOP_MEMBERSHIP:
LOGGER.debug("[saveDefaultElement] Cannot update container {}.", type);
return null;
default:
throw new IllegalStateException("Unknown DefaultContactFlexibleElementType : " + type);
}
LOGGER.debug("[saveDefaultElement] Updates the container.");
contactDAO.update(contact);
return oldValue;
}
/**
* Add case for the update of a {@link org.sigmah.server.domain.element.TripletsListElement}.
*
* @param item
* Added item.
* @param ids
* Current item list of the element.
* @param currentValue
* Current value of the element.
* @param historyDate
* Date of the modification.
* @param element
* Flexible element to update.
* @param containerId
* Identifier of the parent container.
* @param iterationId
* Identifier of the iteration to update.
* @param user
* Author of the modification.
* @param comment
* Comment about the modification.
*/
private void onAdd(final TripletValueDTO item, final List<Integer> ids, final Value currentValue, final Date historyDate, final FlexibleElement element, final Integer containerId, final Integer iterationId, User user, String comment) {
LOGGER.debug("[onAdd] Adds an element to the list.");
// Adds the element.
TripletValue entity = mapper.map(item, new TripletValue());
entity = em().merge(entity);
LOGGER.debug("[onAdd] Successfully create the entity with id #" + entity.getId() + ".");
// Updates the value.
ids.add(entity.getId());
currentValue.setValue(ValueResultUtils.mergeElements(ids));
// Historize the value.
historize(historyDate, element, containerId, iterationId, user, ValueEventChangeType.ADD, null, entity, comment);
}
/**
* Delete case for the update of a {@link org.sigmah.server.domain.element.TripletsListElement}.
*
* @param item
* Added item.
* @param ids
* Current item list of the element.
* @param currentValue
* Current value of the element.
* @param historyDate
* Date of the modification.
* @param element
* Flexible element to update.
* @param containerId
* Identifier of the parent container.
* @param iterationId
* Identifier of the iteration to update.
* @param user
* Author of the modification.
* @param comment
* Comment about the modification.
* @return <code>true</code> if the item was deleted.
*/
private void onDelete(final TripletValueDTO item, final List<Integer> ids, final Value currentValue, final Date historyDate, final FlexibleElement element, final Integer containerId, final Integer iterationId, User user, String comment) {
LOGGER.debug("[onDelete] Removes an element from the list.");
// Retrieves the element.
final TripletValue entity = em().find(TripletValue.class, item.getId());
// Marks the entity as deleted.
entity.delete();
em().merge(entity);
LOGGER.debug("[onDelete] Successfully remove the entity with id #{}.", entity.getId());
// Updates the value.
ids.remove(entity.getId());
currentValue.setValue(ValueResultUtils.mergeElements(ids));
// Historize the value.
historize(historyDate, element, containerId, iterationId, user, ValueEventChangeType.REMOVE, null, entity, comment);
}
/**
* Edit case for the update of a {@link org.sigmah.server.domain.element.TripletsListElement}.
*
* @param item
* Added item.
* @param ids
* Current item list of the element.
* @param currentValue
* Current value of the element.
* @param historyDate
* Date of the modification.
* @param element
* Flexible element to update.
* @param containerId
* Identifier of the parent container.
* @param iterationId
* Identifier of the iteration to update.
* @param user
* Author of the modification.
* @param comment
* Comment about the modification.
* @return <code>true</code> if the item was deleted.
*/
private void onEdit(final TripletValueDTO item, final Date historyDate, final FlexibleElement element, final Integer containerId, final Integer iterationId, User user, String comment) {
LOGGER.debug("[onEdit] Edits an element from the list.");
// Retrieves the element.
final TripletValue entity = mapper.map(item, new TripletValue());
em().merge(entity);
LOGGER.debug("[onEdit] Successfully edit the entity with id #{}.", entity.getId());
// Historize the value.
historize(historyDate, element, containerId, iterationId, user, ValueEventChangeType.EDIT, null, entity, comment);
}
/**
* Add to the history the previous value of the given element.
*
* @param date
* Date of the update.
* @param element
* Updated flexible element.
* @param containerId
* Identifier of the container.
* @param user
* Author of the modification.
* @param singleValue
* Previous value.
* @param comment
* Comment about the modification.
*/
private void historize(final Date date, final FlexibleElement element, final Integer containerId, final Integer iterationId, final User user, final String singleValue, final String comment) {
historize(date, element, containerId, iterationId, user, ValueEventChangeType.EDIT, singleValue, null, comment);
}
/**
* Add to the historic the previous value of the given element.
*
* @param date
* Date of the update.
* @param element
* Updated flexible element.
* @param containerId
* Identifier of the container.
* @param user
* Author of the modification.
* @param type
* Change type (add, edit or remove).
* @param singleValue
* Previous single value.
* @param listValue
* Previous list value.
* @param comment
* Comment about the modification.
*/
private void historize(final Date date, final FlexibleElement element, final Integer containerId, final Integer iterationId, final User user, final ValueEventChangeType type, final String singleValue, final TripletValue listValue, final String comment) {
// Manages history.
if (element != null && element.isHistorable()) {
final HistoryToken historyToken = new HistoryToken();
historyToken.setElementId(element.getId());
historyToken.setProjectId(containerId);
historyToken.setDate(date);
historyToken.setUser(user);
historyToken.setType(type);
historyToken.setComment(comment);
historyToken.setLayoutGroupIterationId(iterationId);
// Sets the value or list value.
if (listValue == null) {
historyToken.setValue(element.asHistoryToken(singleValue));
} else {
historyToken.setValue(element.asHistoryToken(listValue));
}
em().persist(historyToken);
}
}
/**
* Update the computation elements referencing the given element.
*
* @param element
* Flexible element whose value was updated.
* @param containerId
* Identifier of the project containing the flexible element.
* @param user
* User changing the value of the flexible element.
*/
private void updateImpactedComputations(final FlexibleElement element, final Integer containerId, final User user) {
final Collection<ComputationElement> computationElements = computationService.getComputationElementsReferencingElement(element);
if (computationElements.isEmpty()) {
return;
}
final Project project = em().find(Project.class, containerId);
final ArrayList<ProjectFunding> allFundings = new ArrayList<>();
allFundings.addAll(project.getFunded() != null ? project.getFunded() : Collections.<ProjectFunding>emptyList());
allFundings.addAll(project.getFunding() != null ? project.getFunding() : Collections.<ProjectFunding>emptyList());
for (final ComputationElement computationElement : computationElements) {
final ProjectModel parentModel = computationService.getParentProjectModel(computationElement);
if (parentModel != null) {
final Integer parentModelId = parentModel.getId();
for (final ProjectFunding projectFunding : allFundings) {
final Project fundedProject = projectFunding.getFunded();
if (parentModelId.equals(fundedProject.getProjectModel().getId())) {
computationService.updateComputationValueForProject(computationElement, fundedProject, user);
}
final Project fundingProject = projectFunding.getFunding();
if (parentModelId.equals(fundingProject.getProjectModel().getId())) {
computationService.updateComputationValueForProject(computationElement, fundingProject, user);
}
}
}
}
}
}