/*
* This file is part of LibrePlan
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2012 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.web.common;
import static org.libreplan.web.I18nHelper._;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Currency;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.lang3.StringUtils;
import org.libreplan.business.calendars.daos.IBaseCalendarDAO;
import org.libreplan.business.calendars.entities.BaseCalendar;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.daos.IConnectorDAO;
import org.libreplan.business.common.daos.IEntitySequenceDAO;
import org.libreplan.business.common.entities.Configuration;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.entities.EntitySequence;
import org.libreplan.business.common.entities.LDAPConfiguration;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.common.entities.ProgressType;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
import org.libreplan.business.workreports.daos.IWorkReportDAO;
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Manuel Rego Casasnovas <mrego@igalia.com>
* @author Cristina Alvarino Perez <cristina.alvarino@comtecsf.es>
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@OnConcurrentModification(goToPage = "/common/configuration.zul")
public class ConfigurationModel implements IConfigurationModel {
/**
* Conversation state.
*/
private Configuration configuration;
private Map<EntityNameEnum, List<EntitySequence>> entitySequences = new HashMap<>();
private static Map<String, String> currencies = getAllCurrencies();
private List<Connector> connectors;
@Autowired
private IConfigurationDAO configurationDAO;
@Autowired
private IBaseCalendarDAO baseCalendarDAO;
@Autowired
private IEntitySequenceDAO entitySequenceDAO;
@Autowired
private IWorkReportDAO workReportDAO;
@Autowired
private IConnectorDAO connectorDAO;
@Autowired
private IJobSchedulerModel jobSchedulerModel;
@Override
@Transactional(readOnly = true)
public List<BaseCalendar> getCalendars() {
return baseCalendarDAO.getBaseCalendars();
}
@Override
public BaseCalendar getDefaultCalendar() {
return configuration == null ? null : configuration.getDefaultCalendar();
}
@Override
@Transactional(readOnly = true)
public void init() {
this.configuration = getCurrentConfiguration();
initEntitySequences();
initLdapConfiguration();
initConnectorConfiguration();
}
private void initEntitySequences() {
this.entitySequences.clear();
for (EntityNameEnum entityName : EntityNameEnum.values()) {
entitySequences.put(entityName, new ArrayList<>());
}
for (EntitySequence entitySequence : entitySequenceDAO.getAll()) {
entitySequences.get(entitySequence.getEntityName()).add(entitySequence);
}
}
private void initLdapConfiguration() {
if (null == configuration.getLdapConfiguration()) {
configuration.setLdapConfiguration(LDAPConfiguration.create());
}
}
private void initConnectorConfiguration() {
connectors = connectorDAO.getAll();
forceLoadConnectors();
}
private void forceLoadConnectors() {
for (Connector connector : connectors) {
connector.getProperties().size();
}
}
private Configuration getCurrentConfiguration() {
Configuration configuration = configurationDAO.getConfiguration();
if (configuration == null) {
configuration = Configuration.create();
}
forceLoad(configuration);
return configuration;
}
private void forceLoad(Configuration configuration) {
forceLoad(configuration.getDefaultCalendar());
forceLoad(configuration.getPersonalTimesheetsTypeOfWorkHours());
forceLoad(configuration.getBudgetDefaultTypeOfWorkHours());
}
private void forceLoad(BaseCalendar calendar) {
if (calendar != null) {
calendar.getName();
}
}
private void forceLoad(TypeOfWorkHours typeOfWorkHours) {
if (typeOfWorkHours != null) {
typeOfWorkHours.getName();
}
}
@Override
public void setDefaultCalendar(BaseCalendar calendar) {
if (configuration != null) {
configuration.setDefaultCalendar(calendar);
}
}
@Override
@Transactional
public void confirm() {
checkEntitySequences();
configurationDAO.save(configuration);
saveConnectors();
try {
storeAndRemoveEntitySequences();
} catch (IllegalStateException e) {
throw new OptimisticLockingFailureException("concurrency problem in entity sequences");
}
}
private void checkEntitySequences() {
// Check if exist at least one sequence for each entity
for (EntityNameEnum entityName : EntityNameEnum.values()) {
String entity = entityName.getDescription();
List<EntitySequence> sequences = entitySequences.get(entityName);
if (sequences.isEmpty()) {
throw new ValidationException(_("At least one {0} sequence is needed", entity));
}
if (!isAnyActive(sequences)) {
throw new ValidationException(_("At least one {0} sequence must be active", entity));
}
if (!checkConstraintPrefixNotRepeated(sequences)) {
throw new ValidationException(_(
"The {0} sequence prefixes cannot be repeated", entityName.getDescription()));
}
}
}
private boolean checkConstraintPrefixNotRepeated(List<EntitySequence> sequences) {
Set<String> prefixes = new HashSet<>();
for (EntitySequence sequence : sequences) {
String prefix = sequence.getPrefix();
if (prefixes.contains(prefix)) {
return false;
}
prefixes.add(prefix);
}
return true;
}
private boolean isAnyActive(List<EntitySequence> sequences) {
for (EntitySequence entitySequence : sequences) {
if (entitySequence.isActive()) {
return true;
}
}
return false;
}
private void storeAndRemoveEntitySequences() {
Collection<List<EntitySequence>> sequencesCollection = entitySequences.values();
List<EntitySequence> sequences = new ArrayList<>();
for (List<EntitySequence> list : sequencesCollection) {
sequences.addAll(list);
}
removeEntitySequences(sequences);
storeEntitySequences(sequences);
}
public void removeEntitySequences(final List<EntitySequence> sequences) {
// First one is necessary to remove the deleted sequences
List<EntitySequence> toRemove = entitySequenceDAO.findEntitySequencesNotIn(sequences);
for (final EntitySequence entitySequence : toRemove) {
try {
entitySequenceDAO.remove(entitySequence);
} catch (InstanceNotFoundException e) {
throw new ValidationException(_("Some sequences to be removed do not exist"));
} catch (IllegalArgumentException e) {
throw new ValidationException(e.getMessage());
}
}
}
public void storeEntitySequences(List<EntitySequence> sequences) {
// It updates the sequences that are not active first
List<EntitySequence> toSaveAfter = new ArrayList<>();
for (EntitySequence entitySequence : sequences) {
if ( entitySequence.isActive() ) {
toSaveAfter.add(entitySequence);
} else {
entitySequenceDAO.save(entitySequence);
}
}
for (EntitySequence entitySequence : toSaveAfter) {
entitySequenceDAO.save(entitySequence);
}
}
@Override
@Transactional(readOnly = true)
public void cancel() {
init();
}
@Override
public String getCompanyCode() {
if (configuration == null) {
return null;
}
return configuration.getCompanyCode();
}
@Override
public void setCompanyCode(String companyCode) {
if (configuration != null) {
configuration.setCompanyCode(companyCode);
}
}
@Override
public Boolean getGenerateCodeForCriterion() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForCriterion();
}
@Override
public void setGenerateCodeForCriterion(Boolean generateCodeForCriterion) {
if (configuration != null) {
configuration.setGenerateCodeForCriterion(generateCodeForCriterion);
}
}
@Override
public Boolean isAutocompleteLogin() {
if (configuration == null) {
return null;
}
return (configuration.isAutocompleteLogin() && (!configuration.getChangedDefaultAdminPassword()));
}
@Override
public void setAutocompleteLogin(Boolean autocompleteLogin) {
if (configuration != null) {
configuration.setAutocompleteLogin(autocompleteLogin);
}
}
@Override
public Boolean isChangedDefaultPasswdAdmin() {
return configuration != null ? configuration.getChangedDefaultAdminPassword() : false;
}
@Override
public Boolean getGenerateCodeForWorkReportType() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForWorkReportType();
}
@Override
public void setGenerateCodeForWorkReportType(Boolean generateCodeForWorkReportType) {
if (configuration != null) {
configuration.setGenerateCodeForWorkReportType(generateCodeForWorkReportType);
}
}
@Override
public Boolean getGenerateCodeForCalendarExceptionType() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForCalendarExceptionType();
}
@Override
public void setGenerateCodeForCalendarExceptionType(Boolean generateCodeForCalendarExceptionType) {
if (configuration != null) {
configuration.setGenerateCodeForCalendarExceptionType(generateCodeForCalendarExceptionType);
}
}
@Override
public void setGenerateCodeForCostCategory(Boolean generateCodeForCostCategory) {
if (configuration != null) {
configuration.setGenerateCodeForCostCategory(generateCodeForCostCategory);
}
}
@Override
public Boolean getGenerateCodeForCostCategory() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForCostCategory();
}
@Override
public Boolean getGenerateCodeForLabel() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForLabel();
}
@Override
public void setGenerateCodeForLabel(Boolean generateCodeForLabel) {
if (configuration != null) {
configuration.setGenerateCodeForLabel(generateCodeForLabel);
}
}
@Override
public Boolean getGenerateCodeForWorkReport() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForWorkReport();
}
@Override
public void setGenerateCodeForWorkReport(Boolean generateCodeForWorkReport) {
if (configuration != null) {
configuration.setGenerateCodeForWorkReport(generateCodeForWorkReport);
}
}
@Override
public Boolean getGenerateCodeForResources() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForResources();
}
@Override
public void setGenerateCodeForResources(Boolean generateCodeForResources) {
if (configuration != null) {
configuration.setGenerateCodeForResources(generateCodeForResources);
}
}
@Override
public Boolean getGenerateCodeForTypesOfWorkHours() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForTypesOfWorkHours();
}
@Override
public void setGenerateCodeForTypesOfWorkHours(Boolean generateCodeForTypesOfWorkHours) {
if (configuration != null) {
configuration.setGenerateCodeForTypesOfWorkHours(generateCodeForTypesOfWorkHours);
}
}
@Override
public Boolean getGenerateCodeForMaterialCategories() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForMaterialCategories();
}
@Override
public void setGenerateCodeForMaterialCategories(Boolean generateCodeForMaterialCategories) {
if (configuration != null) {
configuration.setGenerateCodeForMaterialCategories(generateCodeForMaterialCategories);
}
}
@Override
public Boolean getGenerateCodeForUnitTypes() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForUnitTypes();
}
@Override
public void setGenerateCodeForBaseCalendars(Boolean generateCodeForBaseCalendars) {
if (configuration != null) {
configuration.setGenerateCodeForBaseCalendars(generateCodeForBaseCalendars);
}
}
@Override
public Boolean getGenerateCodeForBaseCalendars() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForBaseCalendars();
}
@Override
public void setGenerateCodeForUnitTypes(Boolean generateCodeForUnitTypes) {
if (configuration != null) {
configuration.setGenerateCodeForUnitTypes(generateCodeForUnitTypes);
}
}
@Override
public Boolean getGenerateCodeForExpenseSheets() {
if (configuration == null) {
return null;
}
return configuration.getGenerateCodeForExpenseSheets();
}
@Override
public void setGenerateCodeForExpenseSheets(Boolean generateCodeForExpenseSheets) {
if (configuration != null) {
configuration.setGenerateCodeForExpenseSheets(generateCodeForExpenseSheets);
}
}
@Override
public Boolean isMonteCarloMethodTabVisible() {
if (configuration == null) {
return null;
}
return configuration.isMonteCarloMethodTabVisible();
}
@Override
public void setMonteCarloMethodTabVisible(Boolean visible) {
if (configuration != null) {
configuration.setMonteCarloMethodTabVisible(visible);
}
}
public List<EntitySequence> getEntitySequences(EntityNameEnum entityName) {
return entitySequences.get(entityName);
}
public void addEntitySequence(EntityNameEnum entityName, String prefix, Integer digits) {
List<EntitySequence> sequences = entitySequences.get(entityName);
EntitySequence entitySequence = EntitySequence.create(prefix, entityName, digits);
if (sequences.isEmpty()) {
entitySequence.setActive(true);
}
sequences.add(entitySequence);
}
public void removeEntitySequence(EntitySequence entitySequence) throws IllegalArgumentException {
entitySequences.get(entitySequence.getEntityName()).remove(entitySequence);
}
public boolean checkPrefixFormat(EntitySequence sequence) {
return (sequence.isWithoutLowBarConstraint() && sequence.isPrefixWithoutWhiteSpacesConstraint());
}
@Override
public List<ProgressType> getProgressTypes() {
return ProgressType.getAll();
}
@Override
public void setProgressType(ProgressType progressType) {
configuration.setProgressType(progressType);
}
@Override
public ProgressType getProgressType() {
return configuration.getProgressType();
}
@Override
public String getCompanyLogoURL() {
return configuration.getCompanyLogoURL();
}
@Override
public void setCompanyLogoURL(String companyLogoURL) {
configuration.setCompanyLogoURL(companyLogoURL);
}
@Override
public void setLdapConfiguration(LDAPConfiguration ldapConfiguration) {
configuration.setLdapConfiguration(ldapConfiguration);
}
@Override
public LDAPConfiguration getLdapConfiguration() {
return configuration.getLdapConfiguration();
}
@Override
public boolean isCheckNewVersionEnabled() {
return configuration.isCheckNewVersionEnabled();
}
@Override
public void setCheckNewVersionEnabled(boolean checkNewVersionEnabled) {
configuration.setCheckNewVersionEnabled(checkNewVersionEnabled);
}
private static Map<String, String> getAllCurrencies() {
Map<String, String> currencies = new TreeMap<>();
for (Locale locale : Locale.getAvailableLocales()) {
if (StringUtils.isNotBlank(locale.getCountry())) {
Currency currency = Currency.getInstance(locale);
currencies.put(currency.getCurrencyCode(), currency.getSymbol(locale));
}
}
return currencies;
}
@Override
public Set<String> getCurrencies() {
return currencies.keySet();
}
@Override
public String getCurrencySymbol(String currencyCode) {
return currencies.get(currencyCode);
}
@Override
public String getCurrencyCode() {
return configuration.getCurrencyCode();
}
@Override
public void setCurrency(String currencyCode) {
if (configuration != null) {
configuration.setCurrencyCode(currencyCode);
configuration.setCurrencySymbol(currencies.get(currencyCode));
}
}
@Override
public TypeOfWorkHours getPersonalTimesheetsTypeOfWorkHours() {
return configuration.getPersonalTimesheetsTypeOfWorkHours();
}
@Override
public void setPersonalTimesheetsTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours) {
if (configuration != null) {
configuration.setPersonalTimesheetsTypeOfWorkHours(typeOfWorkHours);
}
}
@Override
public PersonalTimesheetsPeriodicityEnum getPersonalTimesheetsPeriodicity() {
return configuration.getPersonalTimesheetsPeriodicity();
}
@Override
public void setPersonalTimesheetsPeriodicity(PersonalTimesheetsPeriodicityEnum personalTimesheetsPeriodicity) {
configuration.setPersonalTimesheetsPeriodicity(personalTimesheetsPeriodicity);
}
@Override
@Transactional(readOnly = true)
public boolean isAnyPersonalTimesheetAlreadySaved() {
return !workReportDAO.isAnyPersonalTimesheetAlreadySaved();
}
@Override
public Integer getSecondsPlanningWarning() {
return configuration.getSecondsPlanningWarning();
}
@Override
public void setSecondsPlanningWarning(Integer secondsPlanningWarning) {
configuration.setSecondsPlanningWarning(secondsPlanningWarning);
}
@Override
public String getRepositoryLocation() {
return configuration.getRepositoryLocation();
}
@Override
public void setRepositoryLocation(String location) {
configuration.setRepositoryLocation(location);
}
private void saveConnectors() {
for (Connector connector : connectors) {
connectorDAO.save(connector);
}
}
@Override
public List<Connector> getConnectors() {
return Collections.unmodifiableList(connectors);
}
@Override
public Connector getConnectorByName(String name) {
if (name == null || connectors == null) {
return null;
}
for (Connector connector : connectors) {
if (connector.getName().equals(name)) {
return connector;
}
}
return null;
}
@Override
public boolean scheduleOrUnscheduleJobs(Connector connector) {
return jobSchedulerModel.scheduleOrUnscheduleJobs(connector);
}
@Override
public TypeOfWorkHours getBudgetDefaultTypeOfWorkHours() {
return configuration.getBudgetDefaultTypeOfWorkHours();
}
@Override
public void setBudgetDefaultTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours) {
if (configuration != null) {
configuration.setBudgetDefaultTypeOfWorkHours(typeOfWorkHours);
}
}
@Override
public Boolean getEnabledAutomaticBudget() {
if (configuration == null) {
return null;
}
return (configuration.isEnabledAutomaticBudget());
}
@Override
public void setEnabledAutomaticBudget(Boolean enabledAutomaticBudget) {
if (configuration != null) {
configuration.setEnabledAutomaticBudget(enabledAutomaticBudget);
}
}
}