AppSettingsServiceImpl.java

/*
 * Copyright 2021 Global Crop Diversity Trust
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gringlobal.service.impl;

import java.util.List;
import java.util.Optional;

import org.apache.commons.compress.utils.Lists;
import org.gringlobal.api.exception.NotFoundElement;
import org.apache.commons.lang3.StringUtils;
import org.gringlobal.model.AppResource;
import org.gringlobal.model.AppSetting;
import org.gringlobal.model.QAppSetting;
import org.gringlobal.model.QSysLang;
import org.gringlobal.model.SysLang;
import org.gringlobal.persistence.AppResourceRepository;
import org.gringlobal.persistence.AppResourceRepository.AppResourceInfo;
import org.gringlobal.persistence.AppSettingRepository;
import org.gringlobal.persistence.SysLangRepository;
import org.gringlobal.service.AppSettingsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author Matija Obreza
 * @author Maxym Borodenko
 */
@Service
@Transactional(readOnly = true)
public class AppSettingsServiceImpl extends CRUDServiceImpl<AppSetting, AppSettingRepository> implements AppSettingsService {

	@Autowired
	private ConversionService conversionService;

	@Autowired
	private SysLangRepository sysLangRepository;

	@Autowired
	private AppSettingRepository appSettingRepository;

	@Autowired
	private AppResourceRepository appResourceRepository;

	@Override
	public List<AppSetting> settingList() {
		return appSettingRepository.findAll();
	}

	@Override
	public List<AppResource> resourceList() {
		return appResourceRepository.findAll();
	}

	@Override
	public List<AppResourceInfo> listResources(String appName, SysLang language) {
		SysLang defaultLanguage = sysLangRepository.findOne(QSysLang.sysLang.ietfTag.eq("en-US")).orElse(null);
		return appResourceRepository.listAppResources(appName, defaultLanguage, language == null ? defaultLanguage : language);
	}

	@Override
	@Transactional
	@PreAuthorize("hasAuthority('GROUP_ADMINS')")
	public AppSetting ensureAppSetting(String categoryTag, String name, String value) {
		try {
			AppSetting setting = getSetting(categoryTag, name);
			if (StringUtils.isNotBlank(setting.getValue())) {
				return setting;
			} else {
				// set default value
				setting.setValue(value);
				return update(setting);
			}
		} catch (NotFoundElement ex) {
			return create(new AppSetting(categoryTag, name, value));
		}
	}

	/**
	 * Gets the {@link AppSetting} by category and name. The return value is
	 * converted to the requested type.
	 *
	 * @param <T> the generic type
	 * @param categoryTag the category tag
	 * @param name the name
	 * @param type the requested return type of the setting value
	 * @return the {@link Optional} value, empty when setting is not declared or it
	 * has a <code>null</code> value
	 */
	@Override
	public <T> Optional<T> getSetting(String categoryTag, String name, Class<T> type) {
		var qAs = QAppSetting.appSetting;
		var appSetting = appSettingRepository.findOne(qAs.name.eq(name).and(categoryTag == null ? qAs.categoryTag.isNull() : qAs.categoryTag.eq(categoryTag))).orElse(null);

		if (appSetting == null || appSetting.getValue() == null) {
			// No setting
			return Optional.empty();
		}

		if (conversionService.canConvert(String.class, type)) {
			return Optional.of(conversionService.convert(appSetting.getValue(), type));
		} else {
			throw new UnsupportedOperationException("Cannot convert String to " + type.getName());
		}
	}

	@Override
	public AppSetting getSetting(String categoryTag, String name) {
		var qAs = QAppSetting.appSetting;
		var appSetting = appSettingRepository.findOne(qAs.name.eq(name).and(categoryTag == null ? qAs.categoryTag.isNull() : qAs.categoryTag.eq(categoryTag))).orElse(null);
		if (appSetting == null) {
			throw new NotFoundElement("No setting " + name + " for categoryTag=" + categoryTag);
		}
		return appSetting;
	}

	@Override
	public AppSetting getSetting(String categoryTag, String name, Integer sortOrder) {
		var qAs = QAppSetting.appSetting;
		var appSetting = appSettingRepository.findOne(
			qAs.name.eq(name)
				.and(categoryTag == null ? qAs.categoryTag.isNull() : qAs.categoryTag.eq(categoryTag))
				.and(sortOrder == null ? qAs.sortOrder.isNull() : qAs.sortOrder.eq(sortOrder))
		).orElse(null);
		if (appSetting == null) {
			throw new NotFoundElement("No setting " + name + " for categoryTag=" + categoryTag);
		}
		return appSetting;
	}

	@Override
	public List<AppSetting> getSettings(String categoryTag, String name) {
		var qAs = QAppSetting.appSetting;
		var appSettings = Lists.newArrayList(appSettingRepository.findAll(qAs.name.eq(name).and(categoryTag == null ? qAs.categoryTag.isNull() : qAs.categoryTag.eq(categoryTag))).iterator());
		if (appSettings.isEmpty()) {
			throw new NotFoundElement("No settings with name " + name + " for categoryTag=" + categoryTag);
		}
		return appSettings;
	}

	@Override
	@Transactional
	@PreAuthorize("hasAuthority('GROUP_ADMINS')")
	public AppSetting create(AppSetting source) {
		source.setId(null);
		return repository.save(source);
	}

	@Override
	@Transactional
	@PreAuthorize("hasAuthority('GROUP_ADMINS')")
	public AppSetting update(AppSetting updated, AppSetting target) {
		target.setCategoryTag(updated.getCategoryTag());
		target.setSortOrder(updated.getSortOrder());
		target.setName(updated.getName());
		target.setValue(updated.getValue());
		return repository.save(target);
	}

	@Override
	@Transactional
	@PreAuthorize("hasAuthority('GROUP_ADMINS')")
	public AppSetting remove(AppSetting entity) {
		return super.remove(entity);
	}
}