/**
* Revenue Settlement and Sharing System GE
* Copyright (C) 2011-2014, Javier Lucio - lucio@tid.es
* Telefonica Investigacion y Desarrollo, S.A.
*
* Copyright (C) 2015 CoNWeT Lab., Universidad Politécnica de Madrid
*
* 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 es.upm.fiware.rss.service;
import es.upm.fiware.rss.algorithm.AlgorithmFactory;
import es.upm.fiware.rss.algorithm.AlgorithmProcessor;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import es.upm.fiware.rss.dao.DbeAggregatorDao;
import es.upm.fiware.rss.dao.DbeAppProviderDao;
import es.upm.fiware.rss.dao.ModelProviderDao;
import es.upm.fiware.rss.dao.SetRevenueShareConfDao;
import es.upm.fiware.rss.exception.RSSException;
import es.upm.fiware.rss.exception.UNICAExceptionType;
import es.upm.fiware.rss.model.DbeAggregator;
import es.upm.fiware.rss.model.DbeAppProvider;
import es.upm.fiware.rss.model.ModelProvider;
import es.upm.fiware.rss.model.ModelProviderId;
import es.upm.fiware.rss.model.RSSModel;
import es.upm.fiware.rss.model.SetRevenueShareConf;
import es.upm.fiware.rss.model.SetRevenueShareConfId;
import es.upm.fiware.rss.model.StakeholderModel;
@Service
@Transactional(rollbackFor = Exception.class)
public class RSSModelsManager {
/***
* Logging system.
*/
private final Logger logger = LoggerFactory.getLogger(RSSModelsManager.class);
/**
*
*/
@Autowired
private DbeAppProviderDao appProviderDao;
/**
*
*/
@Autowired
private SetRevenueShareConfDao revenueShareConfDao;
@Autowired
private DbeAggregatorDao aggregatorDao;
@Autowired
private ModelProviderDao modelProviderDao;
/**
* Check whether a given revenue sharing model exists in the database
* identified by it aggregator, provider owner and product class
* @param aggregatorId
* @param providerId
* @param productClass
* @return true if the model identified by aggregatorId, providerId and productClass exists
*/
public boolean existModel(String aggregatorId, String providerId, String productClass) {
boolean res = true;
List<SetRevenueShareConf> result = revenueShareConfDao.getRevenueModelsByParameters(aggregatorId,
providerId, productClass);
if (null == result || result.isEmpty()) {
res = false;
}
return res;
}
/**
* Retrives a list of revenue sharing models filtered by aggregator, provider
* and product class
*
* @param aggregatorId, Id of the aggregator
* @param appProviderId, Id if the provider owener of the revenue sharing models
* @param productClass, Product class where the models are applied
* @return
* @throws RSSException
*/
public List<RSSModel> getRssModels(String aggregatorId, String appProviderId,
String productClass) throws RSSException {
logger.debug("Into getRssModels() method");
// Validate owner provider
if (null != appProviderId && !appProviderId.isEmpty()) {
checkValidAppProvider(aggregatorId, appProviderId);
}
List<RSSModel> models = new ArrayList<>();
List<SetRevenueShareConf> result = revenueShareConfDao.getRevenueModelsByParameters(aggregatorId,
appProviderId, productClass);
// convert result to api model.
if (null != result && !result.isEmpty()) {
for (SetRevenueShareConf model : result) {
models.add(convertIntoApiModel(model));
}
}
return models;
}
private SetRevenueShareConfId buildRSModelId(RSSModel rssModel) {
// Create new model id
SetRevenueShareConfId id = new SetRevenueShareConfId();
DbeAppProvider provider = this.appProviderDao.
getProvider(rssModel.getAggregatorId(), rssModel.getOwnerProviderId());
id.setModelOwner(provider);
id.setProductClass(rssModel.getProductClass());
return id;
}
private SetRevenueShareConf fillRSModelInfo(RSSModel rssModel,
SetRevenueShareConf model) {
model.setAlgorithmType(rssModel.getAlgorithmType());
// Create aggregator sharing object
DbeAggregator aggregator = this.aggregatorDao.getById(rssModel.getAggregatorId());
model.setAggregator(aggregator);
model.setAggregatorValue(rssModel.getAggregatorValue());
model.setOwnerValue(rssModel.getOwnerValue());
// Set stakeholders
if (rssModel.getStakeholders() != null) {
Set<ModelProvider> stakeholders = new HashSet<>();
for (StakeholderModel stakeholderModel: rssModel.getStakeholders()) {
DbeAppProvider stakeholder = this.appProviderDao.
getProvider(rssModel.getAggregatorId(), stakeholderModel.getStakeholderId());
// Build stakeholder id
ModelProviderId stModelId = new ModelProviderId();
stModelId.setStakeholder(stakeholder);
stModelId.setModel(model);
// Build stakeholder
ModelProvider stModel = new ModelProvider();
stModel.setId(stModelId);
stModel.setModelValue(stakeholderModel.getModelValue());
// Add stakeholder to the set
stakeholders.add(stModel);
}
model.setStakeholders(stakeholders);
}
return model;
}
private SetRevenueShareConf buildRSModel(RSSModel rssModel) {
SetRevenueShareConfId id = this.buildRSModelId(rssModel);
// Create new model
SetRevenueShareConf model = new SetRevenueShareConf();
model.setId(id);
return this.fillRSModelInfo(rssModel, model);
}
/**
* Creates a new RS Model.
*
* @param rssModel
* @return
* @throws RSSException
*/
public RSSModel createRssModel(RSSModel rssModel) throws RSSException {
logger.debug("Into createRssModel() method");
// check valid rssModel
checkValidRSSModel(rssModel);
// Build database model for RS Model
SetRevenueShareConf model = this.buildRSModel(rssModel);
Set<SetRevenueShareConf> models = model.getId().getModelOwner().getModels();
if (null == models) {
models = new HashSet<>();
}
models.add(model);
// Persist models in the database
// Save new RS model into database
try {
this.revenueShareConfDao.create(model);
} catch (org.hibernate.NonUniqueObjectException e) {
String[] args = {"A model with the same Product Class already exists"};
throw new RSSException(UNICAExceptionType.RESOURCE_ALREADY_EXISTS, args);
}
// Save model provider relationships for stakeholders
for(ModelProvider st: model.getStakeholders()) {
this.modelProviderDao.create(st);
}
// return model
return rssModel;
}
/**
* Update RSS model.
*
* @param rssModel
* @return
* @throws Exception
*/
public RSSModel updateRssModel(RSSModel rssModel) throws Exception {
logger.debug("Into updateRssModel() method");
// check valid rssModel
checkValidRSSModel(rssModel);
// Get exisintg RS model
SetRevenueShareConfId id = this.buildRSModelId(rssModel);
SetRevenueShareConf model = revenueShareConfDao.getById(id);
// Check if the model does not exists
if (null == model) {
String[] args = {"Non existing Rss Model."};
throw new RSSException(UNICAExceptionType.NON_EXISTENT_RESOURCE_ID, args);
}
// Save model into database
revenueShareConfDao.update(this.fillRSModelInfo(rssModel, model));
// return model
return rssModel;
}
/**
* Delete RSS models.
*
* @param aggregatorId
* @param appProviderId
* @param productClass
* @throws Exception
*/
public void deleteRssModel(String aggregatorId, String appProviderId, String productClass) throws Exception {
logger.debug("Into deleteRssModel() method");
// check valid appProvider
if (null == aggregatorId || aggregatorId.trim().isEmpty()) {
String[] args = {"aggregatorId."};
throw new RSSException(UNICAExceptionType.NON_EXISTENT_RESOURCE_ID, args);
}
if (appProviderId != null && !appProviderId.trim().isEmpty()) {
checkValidAppProvider(aggregatorId, appProviderId);
}
// Get models
List<SetRevenueShareConf> result = revenueShareConfDao.getRevenueModelsByParameters(aggregatorId,
appProviderId, productClass);
// Remeve models
if (null != result && !result.isEmpty()) {
for (SetRevenueShareConf model : result) {
// Remove Stakeholders
if (null != model.getStakeholders()) {
for (ModelProvider st: model.getStakeholders()) {
modelProviderDao.delete(st);
}
}
revenueShareConfDao.delete(model);
}
}
}
/**
* Check that a appProviderId is valid for the current aggregator.
*
* @param aggregatorId
* @param appProviderId
* @throws RSSException
*/
public void checkValidAppProvider(String aggregatorId, String appProviderId)
throws RSSException {
logger.debug("Into checkValidAppProvider mehtod : aggregator:{} provider:{}", aggregatorId, appProviderId);
DbeAppProvider provider = appProviderDao.getProvider(aggregatorId, appProviderId);
if (null == provider) {
String[] args = {"Non existing: appProviderId"};
throw new RSSException(UNICAExceptionType.NON_EXISTENT_RESOURCE_ID, args);
}
// Check that the given aggregator id is the provider one
if (!provider.getId().getAggregator().getTxEmail().equalsIgnoreCase(aggregatorId)) {
String[] args = {"The provider " + appProviderId +
" does not belong to the store owned by " + aggregatorId };
throw new RSSException(UNICAExceptionType.INVALID_PARAMETER, args);
}
}
private void checkField (String field, String name) throws RSSException{
if (null == field || field.isEmpty()) {
String[] args = {"Required parameters not found: " + name};
throw new RSSException(UNICAExceptionType.NON_EXISTENT_RESOURCE_ID, args);
}
}
private void checkNumberField(BigDecimal number, String name) throws RSSException{
if (null == number) {
String[] args = {"Required parameters not found: " + name};
throw new RSSException(UNICAExceptionType.NON_EXISTENT_RESOURCE_ID, args);
}
}
/**
* Check that a RssModels contains all required Information.
*
* @param rssModel
* @throws RSSException
*/
public void checkValidRSSModel(RSSModel rssModel) throws RSSException {
logger.debug("Into checkValidRSSModel mehtod");
// Validate basic fields
this.checkField(rssModel.getAggregatorId(), "aggregatorId");
this.checkField(rssModel.getOwnerProviderId(), "ownerProviderId");
this.checkNumberField(rssModel.getOwnerValue(), "ownerValue");
this.checkField(rssModel.getAlgorithmType(), "algorithmType");
this.checkNumberField(rssModel.getAggregatorValue(), "aggregatorValue");
this.checkField(rssModel.getProductClass(), "productClass");
// Check valid provider owner
this.checkValidAppProvider(rssModel.getAggregatorId(), rssModel.getOwnerProviderId());
// Check stakeholders fields if existing
if (rssModel.getStakeholders() != null) {
for (StakeholderModel stModel: rssModel.getStakeholders()) {
this.checkField(stModel.getStakeholderId(), "stakeholderId");
this.checkNumberField(stModel.getModelValue(), "modelValue");
this.checkValidAppProvider(rssModel.getAggregatorId(), stModel.getStakeholderId());
// Check that the stakeholder is not the owner provider
if (stModel.getStakeholderId().equalsIgnoreCase(rssModel.getOwnerProviderId())) {
String[] args = {"The RS model owner cannot be included as stakeholder"};
throw new RSSException(UNICAExceptionType.INVALID_PARAMETER, args);
}
}
}
// Check algorithm specific restrictions
AlgorithmFactory algorithmFactory = new AlgorithmFactory();
AlgorithmProcessor processor = algorithmFactory.
getAlgorithmProcessor(rssModel.getAlgorithmType());
processor.validateModel(rssModel);
}
/**
* Converts the model from objects to the bean that is serialized by the API.
*
* @param model
* @return
*/
public RSSModel convertIntoApiModel(SetRevenueShareConf model) {
RSSModel rssModel = new RSSModel();
// Fill basic revenue sharing model info
rssModel.setOwnerProviderId(
model.getId().getModelOwner().
getId().getTxAppProviderId()
);
rssModel.setOwnerValue(model.getOwnerValue());
rssModel.setAggregatorId(model.getAggregator().getTxEmail());
rssModel.setAggregatorShare(model.getAggregatorValue());
rssModel.setAlgorithmType(model.getAlgorithmType());
rssModel.setProductClass(model.getId().getProductClass());
// Fill stakeholders list
List<StakeholderModel> stakeholdersList = new ArrayList<>();
for (ModelProvider stk: model.getStakeholders()) {
StakeholderModel stModel = new StakeholderModel();
stModel.setStakeholderId(stk.getStakeholder().getId().getTxAppProviderId());
stModel.setModelValue(stk.getModelValue());
stakeholdersList.add(stModel);
}
rssModel.setStakeholders(stakeholdersList);
return rssModel;
}
}