JPASettingServiceImpl.java
/*
*
* * Copyright (C) 2003-2017 eXo Platform SAS.
* *
* * 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 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/>.
*
*/
package org.exoplatform.settings.jpa;
import static org.exoplatform.settings.jpa.EntityConverter.convertContextToContextEntity;
import static org.exoplatform.settings.jpa.EntityConverter.convertScopeToScopeEntity;
import java.util.*;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.exoplatform.commons.api.persistence.DataInitializer;
import org.exoplatform.commons.api.persistence.ExoTransactional;
import org.exoplatform.commons.api.settings.SettingService;
import org.exoplatform.commons.api.settings.SettingValue;
import org.exoplatform.commons.api.settings.data.Context;
import org.exoplatform.commons.api.settings.data.EventType;
import org.exoplatform.commons.api.settings.data.Scope;
import org.exoplatform.commons.api.settings.data.SettingContext;
import org.exoplatform.commons.api.settings.data.SettingData;
import org.exoplatform.commons.api.settings.data.SettingKey;
import org.exoplatform.commons.api.settings.data.SettingScope;
import org.exoplatform.commons.event.impl.EventManagerImpl;
import org.exoplatform.services.listener.Event;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.settings.jpa.dao.SettingContextDAO;
import org.exoplatform.settings.jpa.dao.SettingScopeDAO;
import org.exoplatform.settings.jpa.dao.SettingsDAO;
import org.exoplatform.settings.jpa.entity.ContextEntity;
import org.exoplatform.settings.jpa.entity.ScopeEntity;
import org.exoplatform.settings.jpa.entity.SettingsEntity;
/**
* Created by The eXo Platform SAS Author : eXoPlatform exo@exoplatform.com Mar
* 07, 2017
*/
public class JPASettingServiceImpl implements SettingService {
private static final Log LOG = ExoLogger.getLogger(JPASettingServiceImpl.class);
private SettingsDAO settingsDAO;
private SettingContextDAO settingContextDAO;
private SettingScopeDAO settingScopeDAO;
private final EventManagerImpl<JPASettingServiceImpl, SettingData> eventManager;
/**
* JPASettingServiceImpl must depend on DataInitializer to make sure data
* structure is created before initializing it
*/
public JPASettingServiceImpl(SettingsDAO settingsDAO,
SettingContextDAO settingContextDAO,
SettingScopeDAO settingScopeDAO,
EventManagerImpl<JPASettingServiceImpl, SettingData> eventManager,
DataInitializer dataInitializer) {
this.settingsDAO = settingsDAO;
this.settingContextDAO = settingContextDAO;
this.settingScopeDAO = settingScopeDAO;
this.eventManager = eventManager;
}
/**
* {@inheritDoc}
*/
@Override
@ExoTransactional
public void set(Context context, Scope scope, String key, SettingValue<?> value) {
validateContextArgument(context);
validateScopeArgument(scope);
validateArgumentNullability(key, "setting name is null");
validateArgumentNullability(value, "setting value is null");
try {
if (context == null) {
LOG.warn("Context is null, can't save setting key={}, value={}", key, value.getValue());
return;
}
if (scope == null) {
scope = Scope.GLOBAL.id(null);
}
LOG.debug("=== setting save, contextType={}, contextName={}, scopeType={} and scopeName={} and key={} and value={}",
context.getName(),
context.getId(),
scope.getName(),
scope.getId(),
key,
value.getValue());
ContextEntity contextEntity = settingContextDAO.getContextByTypeAndName(context.getName(), context.getId());
boolean contextAndScopeFound = true;
if (contextEntity == null) {
contextAndScopeFound = false;
contextEntity = settingContextDAO.create(convertContextToContextEntity(context));
}
ScopeEntity scopeEntity = settingScopeDAO.getScopeByTypeAndName(scope.getName(), scope.getId());
if (scopeEntity == null) {
contextAndScopeFound = false;
scopeEntity = convertScopeToScopeEntity(scope);
scopeEntity = settingScopeDAO.create(scopeEntity);
}
SettingsEntity settingsEntity = null;
if (contextAndScopeFound) {
// If context or scope not found, the setting doesn't exist consequently
// So no need to request database for the setting
settingsEntity = settingsDAO.getSettingByContextAndScopeAndKey(context.getName(),
context.getId(),
scope.getName(),
scope.getId(),
key);
}
if (settingsEntity == null) {
settingsDAO.create(new SettingsEntity().setScope(scopeEntity)
.setContext(contextEntity)
.setName(key)
.setValue(value.getValue().toString()));
} else {
settingsEntity.setValue(value.getValue().toString());
settingsDAO.update(settingsEntity);
}
// broadcast event
SettingData data = new SettingData(EventType.SETTING_SET, new SettingKey(context, scope, key), value);
eventManager.broadcastEvent(new Event<JPASettingServiceImpl, SettingData>(data.getEventType().toString(), this, data));
} catch (Exception e) {
LOG.error("An error occurred while saving setting: contextType=" + context.getName() + ", contextName=" + context.getId()
+ ", scopeType=" + scope.getName() + " and scopeName=" + scope.getId() + " and key=" + key + " and value="
+ value.getValue(), e);
}
}
/**
* {@inheritDoc}
*/
@Override
@ExoTransactional
public void remove(Context context, Scope scope, String key) {
validateContextArgument(context);
validateScopeArgument(scope);
validateArgumentNullability(key, "setting name is null");
SettingsEntity setting = settingsDAO.getSettingByContextAndScopeAndKey(context.getName(),
context.getId(),
scope.getName(),
scope.getId(),
key);
if (setting != null) {
settingsDAO.delete(setting);
SettingData data = new SettingData(EventType.SETTING_REMOVE_KEY, new SettingKey(context, scope, key));
eventManager.broadcastEvent(new Event<JPASettingServiceImpl, SettingData>(data.getEventType().toString(), this, data));
}
}
/**
* {@inheritDoc}
*/
@Override
@ExoTransactional
public void remove(Context context, Scope scope) {
validateContextArgument(context);
validateScopeArgument(scope);
List<SettingsEntity> settings = settingsDAO.getSettingsByContextAndScope(context.getName(),
context.getId(),
scope.getName(),
scope.getId());
settingsDAO.deleteAll(settings);
SettingData data = new SettingData(EventType.SETTING_REMOVE_SCOPE, new SettingScope(context, scope));
eventManager.broadcastEvent(new Event<JPASettingServiceImpl, SettingData>(data.getEventType().toString(), this, data));
}
/**
* {@inheritDoc}
*/
@Override
@ExoTransactional
public void remove(Context context) {
validateContextArgument(context);
List<SettingsEntity> settings = settingsDAO.getSettingsByContextTypeAndName(context.getName(), context.getId());
settingsDAO.deleteAll(settings);
SettingData data = new SettingData(EventType.SETTING_REMOVE_CONTEXT, new SettingContext(context));
eventManager.broadcastEvent(new Event<JPASettingServiceImpl, SettingData>(data.getEventType().toString(), this, data));
}
/**
* {@inheritDoc}
*/
@Override
@ExoTransactional
public SettingValue<?> get(Context context, Scope scope, String key) {
validateContextArgument(context);
validateScopeArgument(scope);
validateArgumentNullability(key, "setting name is null");
SettingsEntity setting = settingsDAO.getSettingByContextAndScopeAndKey(context.getName(),
context.getId(),
scope.getName(),
scope.getId(),
key);
if (setting == null) {
return null; // Property doesn't exist
} else {
return SettingValue.create((String) setting.getValue());
}
}
/**
* {@inheritDoc}
*/
@ExoTransactional
@Override
public void save(Context context) {
validateContextArgument(context);
ContextEntity contextEntity = settingContextDAO.getContextByTypeAndName(context.getName(), context.getId());
if (contextEntity == null) {
contextEntity = new ContextEntity();
contextEntity.setType(context.getName());
contextEntity.setName(context.getId());
settingContextDAO.create(contextEntity);
}
}
/**
* {@inheritDoc}
*/
@ExoTransactional
@Override
public Map<Scope, Map<String, SettingValue<String>>> getSettingsByContext(Context context) {
validateContextArgument(context);
Collection<SettingsEntity> settings = settingsDAO.getSettingsByContextTypeAndName(context.getName(), context.getId());
if (settings == null || settings.isEmpty()) {
return Collections.emptyMap();
} else {
Map<Scope, Map<String, SettingValue<String>>> settingsByScopeByName =
settings.stream()
.collect(Collectors.groupingBy(setting -> new Scope(setting.getScope()
.getType(),
setting.getScope()
.getName()),
Collectors.toMap(setting -> setting.getName(),
setting -> SettingValue.create((String) setting.getValue()))));
return settingsByScopeByName;
}
}
/**
* {@inheritDoc}
*/
@Override
public long countContextsByType(String contextType) {
validateArgumentNullability(contextType, "context type is null");
return settingContextDAO.countContextsByType(contextType);
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getContextNamesByType(String contextType, int offset, int limit) {
validateArgumentNullability(contextType, "context type is null");
return settingContextDAO.getContextNamesByType(contextType, offset, limit);
}
/**
* {@inheritDoc}
*/
@ExoTransactional
@Override
public Set<String> getEmptyContextsByTypeAndScopeAndSettingName(String contextType,
String scopeType,
String scopeName,
String settingName,
int offset,
int limit) {
validateArgumentNullability(contextType, "context type is null");
validateArgumentNullability(scopeType, "scope type is null");
validateArgumentNullability(settingName, "setting name is null");
List<ContextEntity> emptyContexts = settingContextDAO.getEmptyContextsByScopeAndContextType(contextType,
scopeType,
scopeName,
settingName,
offset,
limit);
return emptyContexts.stream().map(context -> context.getName()).collect(Collectors.toSet());
}
/**
* {@inheritDoc}
*/
@ExoTransactional
@Override
public List<Context> getContextsByTypeAndScopeAndSettingName(String contextType,
String scopeType,
String scopeName,
String settingName,
int offset,
int limit) {
validateArgumentNullability(contextType, "context type is null");
validateArgumentNullability(scopeType, "scope type is null");
validateArgumentNullability(settingName, "setting name is null");
List<ContextEntity> contexts = settingContextDAO.getContextsByTypeAndSettingNameAndScope(contextType,
scopeType,
scopeName,
settingName,
offset,
limit);
return contexts.stream().map(context -> new Context(context.getType(), context.getName())).collect(Collectors.toList());
}
@ExoTransactional
public long countSettingsByNameAndValueAndScope(Scope scope, String key, String value) {
validateScopeArgument(scope);
validateArgumentNullability(key, "setting name is null");
validateArgumentNullability(value, "setting value is null");
return settingsDAO.countSettingsByNameAndValueAndScope(scope.getName(), scope.getId(), key, value);
}
private void validateScopeArgument(Scope scope) {
if (scope == null) {
throw new IllegalArgumentException("scope is null");
}
validateArgumentNullability(scope.getName(), "scope name is null");
}
private void validateContextArgument(Context context) {
if (context == null) {
throw new IllegalArgumentException("context is null");
}
validateArgumentNullability(context.getId(), "context id is null");
validateArgumentNullability(context.getName(), "context name is null");
}
private void validateArgumentNullability(String arg, String message) {
if (StringUtils.isBlank(arg)) {
throw new IllegalArgumentException(message);
}
}
private void validateArgumentNullability(Object obj, String message) {
if (obj == null) {
throw new IllegalArgumentException(message);
}
}
@Override
public Map<String, SettingValue> getSettingsByContextAndScope(String contextType,
String contextName,
String scopeType,
String scopeName) {
Map<String, SettingValue> settingsKeyValue = new HashMap<>();
List<SettingsEntity> settingsList = settingsDAO.getSettingsByContextAndScope(contextType, contextName, scopeType, scopeName);
settingsList.stream().forEach(setting -> settingsKeyValue.put(setting.getName(), SettingValue.create(setting.getValue())));
return settingsKeyValue;
}
}