tenant configuration changes

This commit is contained in:
Efstratios Giannopoulos 2024-04-23 18:09:31 +03:00
parent e7a500e3ec
commit f5b0af516a
30 changed files with 687 additions and 164 deletions

View File

@ -17,6 +17,9 @@ public class EventBroker {
public void emit(ApiKeyStaleEvent event) {
this.applicationEventPublisher.publishEvent(event);
}
public void emit(TenantConfigurationTouchedEvent event) {
this.applicationEventPublisher.publishEvent(event);
}
public void emit(TenantTouchedEvent event) {
this.applicationEventPublisher.publishEvent(event);

View File

@ -0,0 +1,44 @@
package eu.eudat.event;
import eu.eudat.commons.enums.TenantConfigurationType;
import java.util.UUID;
public class TenantConfigurationTouchedEvent {
public TenantConfigurationTouchedEvent() {
}
public TenantConfigurationTouchedEvent(UUID tenantId, String tenantCode, TenantConfigurationType type) {
this.tenantId = tenantId;
this.tenantCode = tenantCode;
this.type = type;
}
private UUID tenantId;
private String tenantCode;
private TenantConfigurationType type;
public UUID getTenantId() {
return tenantId;
}
public void setTenantId(UUID tenantId) {
this.tenantId = tenantId;
}
public TenantConfigurationType getType() {
return type;
}
public void setType(TenantConfigurationType type) {
this.type = type;
}
public String getTenantCode() {
return tenantCode;
}
public void setTenantCode(String tenantCode) {
this.tenantCode = tenantCode;
}
}

View File

@ -1,23 +0,0 @@
package eu.eudat.model.file;
import eu.eudat.file.transformer.interfaces.FileTransformerConfiguration;
import java.util.List;
public class TransformerCacheModel {
private List<FileTransformerConfiguration> configurations;
public TransformerCacheModel() {
}
public TransformerCacheModel(List<FileTransformerConfiguration> formats) {
this.configurations = formats;
}
public List<FileTransformerConfiguration> getConfigurations() {
return configurations;
}
public void setConfigurations(List<FileTransformerConfiguration> configurations) {
this.configurations = configurations;
}
}

View File

@ -4,6 +4,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties({DepositProperties.class, DepositCacheOptions.class})
@EnableConfigurationProperties({DepositProperties.class})
public class DepositConfiguration {
}

View File

@ -15,12 +15,14 @@ public class DepositConfigurationCacheService extends CacheService<DepositConfig
public DepositConfigurationCacheValue() {
}
public DepositConfigurationCacheValue(String repositoryId, DepositConfiguration configuration) {
public DepositConfigurationCacheValue(String repositoryId, String tenantCode, DepositConfiguration configuration) {
this.repositoryId = repositoryId;
this.configuration = configuration;
this.tenantCode = tenantCode == null ? "" : tenantCode;
}
private String repositoryId;
private String tenantCode;
public String getRepositoryId() {
return repositoryId;
@ -39,6 +41,14 @@ public class DepositConfigurationCacheService extends CacheService<DepositConfig
public void setConfiguration(DepositConfiguration configuration) {
this.configuration = configuration;
}
public String getTenantCode() {
return tenantCode;
}
public void setTenantCode(String tenantCode) {
this.tenantCode = tenantCode;
}
}
@ -54,13 +64,14 @@ public class DepositConfigurationCacheService extends CacheService<DepositConfig
@Override
public String keyOf(DepositConfigurationCacheValue value) {
return this.buildKey(value.getRepositoryId());
return this.buildKey(value.getRepositoryId(), value.getTenantCode());
}
public String buildKey(String subject) {
public String buildKey(String repositoryId, String tenantCod) {
HashMap<String, String> keyParts = new HashMap<>();
keyParts.put("$repositoryId$", subject);
keyParts.put("$repositoryId$", repositoryId);
keyParts.put("$tenantCode$", tenantCod);
return this.generateKey(keyParts);
}
}

View File

@ -6,14 +6,21 @@ import eu.eudat.model.persist.deposit.DepositRequest;
import eu.eudat.model.deposit.DepositConfiguration;
import gr.cite.tools.fieldset.FieldSet;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
public interface DepositService {
List<eu.eudat.model.deposit.DepositConfiguration> getAvailableConfigurations(FieldSet fieldSet);
List<eu.eudat.model.deposit.DepositConfiguration> getAvailableConfigurations(FieldSet fieldSet) throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException;
EntityDoi deposit(DepositRequest dmpDepositModel) throws Exception;
String getLogo(String repositoryId);
String getLogo(String repositoryId) throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException;
String authenticate(DepositAuthenticateRequest model);
String authenticate(DepositAuthenticateRequest model) throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException;
}

View File

@ -9,16 +9,22 @@ import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.enums.ContactInfoType;
import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.enums.StorageType;
import eu.eudat.commons.enums.TenantConfigurationType;
import eu.eudat.commons.notification.NotificationProperties;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.commons.types.deposit.DepositSourceEntity;
import eu.eudat.commons.types.notification.*;
import eu.eudat.commons.types.tenantconfiguration.DepositTenantConfigurationEntity;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.DmpEntity;
import eu.eudat.data.DmpUserEntity;
import eu.eudat.data.TenantConfigurationEntity;
import eu.eudat.data.UserEntity;
import eu.eudat.depositinterface.repository.DepositClient;
import eu.eudat.depositinterface.repository.DepositConfiguration;
import eu.eudat.event.TenantConfigurationTouchedEvent;
import eu.eudat.event.UserAddedToTenantEvent;
import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEvent;
import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEventHandler;
import eu.eudat.model.EntityDoi;
@ -30,14 +36,14 @@ import eu.eudat.model.persist.StorageFilePersist;
import eu.eudat.model.persist.deposit.DepositAuthenticateRequest;
import eu.eudat.model.persist.deposit.DepositRequest;
import eu.eudat.model.persist.EntityDoiPersist;
import eu.eudat.query.DmpQuery;
import eu.eudat.query.DmpUserQuery;
import eu.eudat.query.UserContactInfoQuery;
import eu.eudat.query.UserQuery;
import eu.eudat.model.tenantconfiguration.TenantConfiguration;
import eu.eudat.query.*;
import eu.eudat.service.encryption.EncryptionService;
import eu.eudat.service.entitydoi.EntityDoiService;
import eu.eudat.service.storage.StorageFileProperties;
import eu.eudat.service.storage.StorageFileService;
import eu.eudat.service.filetransformer.FileTransformerService;
import eu.eudat.service.tenant.TenantProperties;
import gr.cite.commons.web.oidc.filter.webflux.TokenExchangeCacheService;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.commons.web.oidc.filter.webflux.TokenExchangeFilterFunction;
@ -54,14 +60,20 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.event.EventListener;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import java.io.IOException;
import java.net.URI;
import java.net.URLConnection;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;
@ -89,6 +101,11 @@ public class DepositServiceImpl implements DepositService {
private final JsonHandlingService jsonHandlingService;
private final NotificationProperties notificationProperties;
private final NotifyIntegrationEventHandler eventHandler;
private final TenantScope tenantScope;
private final EncryptionService encryptionService;
private final TenantProperties tenantProperties;
private final DepositSourcesCacheService depositSourcesCacheService;
@Autowired
public DepositServiceImpl(DepositProperties depositProperties,
TokenExchangeCacheService tokenExchangeCacheService,
@ -96,7 +113,7 @@ public class DepositServiceImpl implements DepositService {
EntityDoiService doiService,
QueryFactory queryFactory,
MessageSource messageSource,
BuilderFactory builderFactory, DepositConfigurationCacheService depositConfigurationCacheService, FileTransformerService fileTransformerService, StorageFileService storageFileService, UserScope userScope, ValidatorFactory validatorFactory, StorageFileProperties storageFileProperties, AuthorizationContentResolver authorizationContentResolver, ConventionService conventionService, JsonHandlingService jsonHandlingService, NotificationProperties notificationProperties, NotifyIntegrationEventHandler eventHandler) {
BuilderFactory builderFactory, DepositConfigurationCacheService depositConfigurationCacheService, FileTransformerService fileTransformerService, StorageFileService storageFileService, UserScope userScope, ValidatorFactory validatorFactory, StorageFileProperties storageFileProperties, AuthorizationContentResolver authorizationContentResolver, ConventionService conventionService, JsonHandlingService jsonHandlingService, NotificationProperties notificationProperties, NotifyIntegrationEventHandler eventHandler, TenantScope tenantScope, EncryptionService encryptionService, TenantProperties tenantProperties, DepositSourcesCacheService depositSourcesCacheService) {
this.depositProperties = depositProperties;
this.tokenExchangeCacheService = tokenExchangeCacheService;
this.authorizationService = authorizationService;
@ -115,45 +132,122 @@ public class DepositServiceImpl implements DepositService {
this.jsonHandlingService = jsonHandlingService;
this.notificationProperties = notificationProperties;
this.eventHandler = eventHandler;
this.clients = new HashMap<>();
this.tenantScope = tenantScope;
this.encryptionService = encryptionService;
this.tenantProperties = tenantProperties;
this.depositSourcesCacheService = depositSourcesCacheService;
this.clients = new HashMap<>();
}
private DepositClient getDepositClient(String repositoryId) {
if (this.clients.containsKey(repositoryId)) return this.clients.get(repositoryId);
private DepositClient getDepositClient(String repositoryId) throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
String repositoryIdByTenant = this.getRepositoryIdByTenant(repositoryId);
if (this.clients.containsKey(repositoryIdByTenant)) return this.clients.get(repositoryIdByTenant);
//GK: It's register time
DepositSourceEntity source = depositProperties.getSources().stream().filter(depositSource -> depositSource.getRepositoryId().equals(repositoryId)).findFirst().orElse(null);
DepositSourceEntity source = this.getDepositSources().stream().filter(depositSource -> depositSource.getRepositoryId().equals(repositoryId)).findFirst().orElse(null);
if (source != null) {
String host = URI.create(source.getUrl()).getHost();
TokenExchangeModel tokenExchangeModel = new TokenExchangeModel("deposit:" + source.getRepositoryId(), source.getIssuerUrl(), source.getClientId(), source.getClientSecret(), source.getScope());
TokenExchangeModel tokenExchangeModel = new TokenExchangeModel("deposit:" + repositoryIdByTenant, source.getIssuerUrl(), source.getClientId(), source.getClientSecret(), source.getScope());
TokenExchangeFilterFunction apiKeyExchangeFilterFunction = new TokenExchangeFilterFunction(this.tokenExchangeCacheService, tokenExchangeModel);
WebClient webClient = WebClient.builder().baseUrl(source.getUrl() + "/api/deposit").filters(exchangeFilterFunctions -> exchangeFilterFunctions.add(apiKeyExchangeFilterFunction)).build();
DepositClientImpl repository = new DepositClientImpl(webClient);
this.clients.put(source.getRepositoryId(), repository);
this.clients.put(repositoryIdByTenant, repository);
return repository;
}
return null;
}
private List<DepositSourceEntity> getDepositSources() throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
String tenantCode = this.tenantScope.isSet() && this.tenantScope.isMultitenant() ? this.tenantScope.getTenantCode() : "";
DepositSourcesCacheService.DepositSourceCacheValue cacheValue = this.depositSourcesCacheService.lookup(this.depositSourcesCacheService.buildKey(tenantCode));
if (cacheValue == null) {
List<DepositSourceEntity> depositSourceEntities = new ArrayList<>(depositProperties.getSources());
if (this.tenantScope.isSet() && this.tenantScope.isMultitenant()) {
TenantConfigurationQuery tenantConfigurationQuery = this.queryFactory.query(TenantConfigurationQuery.class).isActive(IsActive.Active).types(TenantConfigurationType.DepositPlugins);
if (this.tenantScope.isDefaultTenant()) tenantConfigurationQuery.tenantIsSet(false);
else tenantConfigurationQuery.tenantIsSet(true).tenantIds(this.tenantScope.getTenant());
TenantConfigurationEntity tenantConfiguration = tenantConfigurationQuery.firstAs(new BaseFieldSet().ensure(TenantConfiguration._depositPlugins));
if (tenantConfiguration != null && !this.conventionService.isNullOrEmpty(tenantConfiguration.getValue())) {
DepositTenantConfigurationEntity depositTenantConfiguration = this.jsonHandlingService.fromJsonSafe(DepositTenantConfigurationEntity.class, tenantConfiguration.getValue());
if (depositTenantConfiguration != null) {
if (depositTenantConfiguration.getDisableSystemSources()) depositSourceEntities = new ArrayList<>();
depositSourceEntities.addAll(this.buildDepositSourceItems(depositTenantConfiguration.getSources()));
}
}
}
cacheValue = new DepositSourcesCacheService.DepositSourceCacheValue(tenantCode, depositSourceEntities);
this.depositSourcesCacheService.put(cacheValue);
}
return cacheValue.getSources();
}
@EventListener
public void handleTenantConfigurationTouchedEvent(TenantConfigurationTouchedEvent event) {
if (!event.getType().equals(TenantConfigurationType.DepositPlugins)) return;
DepositSourcesCacheService.DepositSourceCacheValue depositSourceCacheValue = this.depositSourcesCacheService.lookup(this.depositSourcesCacheService.buildKey(event.getTenantCode()));
if (depositSourceCacheValue != null && depositSourceCacheValue.getSources() != null){
for (DepositSourceEntity source : depositSourceCacheValue.getSources()){
String repositoryIdByTenant = source.getRepositoryId() + "_" + event.getTenantCode();
this.clients.remove(repositoryIdByTenant);
this.depositConfigurationCacheService.evict(this.depositConfigurationCacheService.buildKey(source.getRepositoryId(), event.getTenantCode()));
}
}
this.depositSourcesCacheService.evict(this.depositSourcesCacheService.buildKey(event.getTenantCode()));
}
private List<DepositSourceEntity> buildDepositSourceItems(List<DepositSourceEntity> sources) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
List<DepositSourceEntity> items = new ArrayList<>();
if (this.conventionService.isListNullOrEmpty(sources)) return items;
for (DepositSourceEntity source : sources){
DepositSourceEntity item = new DepositSourceEntity();
item.setRepositoryId(source.getRepositoryId());
item.setUrl(source.getUrl());
item.setIssuerUrl(source.getIssuerUrl());
item.setClientId(source.getClientId());
if (!this.conventionService.isNullOrEmpty(source.getClientSecret())) item.setClientSecret(this.encryptionService.decryptAES(source.getClientSecret(), tenantProperties.getConfigEncryptionAesKey(), tenantProperties.getConfigEncryptionAesIv()));
item.setScope(source.getScope());
item.setRdaTransformerId(source.getRdaTransformerId());
item.setPdfTransformerId(source.getPdfTransformerId());
items.add(item);
}
return items;
}
private String getRepositoryIdByTenant(String repositoryId) throws InvalidApplicationException {
if (this.tenantScope.isSet() && this.tenantScope.isMultitenant()) {
return repositoryId + "_" + this.tenantScope.getTenantCode();
} else {
return repositoryId;
}
}
@Override
public List<eu.eudat.model.deposit.DepositConfiguration> getAvailableConfigurations(FieldSet fieldSet) {
public List<eu.eudat.model.deposit.DepositConfiguration> getAvailableConfigurations(FieldSet fieldSet) throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
this.authorizationService.authorizeForce(Permission.BrowseDeposit, Permission.DeferredAffiliation);
List<eu.eudat.model.deposit.DepositConfiguration> configurations = new ArrayList<>();
for (DepositSourceEntity depositSource : depositProperties.getSources()) {
DepositConfigurationCacheService.DepositConfigurationCacheValue cacheValue = this.depositConfigurationCacheService.lookup(this.depositConfigurationCacheService.buildKey(depositSource.getRepositoryId()));
if (cacheValue == null){
DepositClient depositClient = getDepositClient(depositSource.getRepositoryId());
if (depositClient == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{depositSource.getRepositoryId(), DepositClient.class.getSimpleName()}, LocaleContextHolder.getLocale()));
for (DepositSourceEntity depositSource : this.getDepositSources()) {
DepositConfiguration configuration = depositClient.getConfiguration();
cacheValue = new DepositConfigurationCacheService.DepositConfigurationCacheValue(depositSource.getRepositoryId(), configuration);
this.depositConfigurationCacheService.put(cacheValue);
String tenantCode = this.tenantScope.isSet() && this.tenantScope.isMultitenant() ? this.tenantScope.getTenantCode() : "";
DepositConfigurationCacheService.DepositConfigurationCacheValue cacheValue = this.depositConfigurationCacheService.lookup(this.depositConfigurationCacheService.buildKey(depositSource.getRepositoryId(), tenantCode));
if (cacheValue == null){
try {
DepositClient depositClient = getDepositClient(depositSource.getRepositoryId());
if (depositClient == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{depositSource.getRepositoryId(), DepositClient.class.getSimpleName()}, LocaleContextHolder.getLocale()));
DepositConfiguration configuration = depositClient.getConfiguration();
cacheValue = new DepositConfigurationCacheService.DepositConfigurationCacheValue(depositSource.getRepositoryId(), tenantCode, configuration);
this.depositConfigurationCacheService.put(cacheValue);
}catch (Exception e){
logger.error(e.getMessage(), e);
}
}
if (cacheValue != null) {
eu.eudat.model.deposit.DepositConfiguration depositConfiguration = this.builderFactory.builder(DepositConfigurationBuilder.class).build(fieldSet, cacheValue.getConfiguration());
configurations.add(depositConfiguration);
}
eu.eudat.model.deposit.DepositConfiguration depositConfiguration = this.builderFactory.builder(DepositConfigurationBuilder.class).build(fieldSet, cacheValue.getConfiguration());
configurations.add(depositConfiguration);
}
return configurations;
@ -172,7 +266,7 @@ public class DepositServiceImpl implements DepositService {
//GK: Forth make the required files to be uploaded with the deposit
//TODO: Properly create required files
DepositSourceEntity source = depositProperties.getSources().stream().filter(depositSource -> depositSource.getRepositoryId().equals(dmpDepositModel.getRepositoryId())).findFirst().orElse(null);
DepositSourceEntity source = this.getDepositSources().stream().filter(depositSource -> depositSource.getRepositoryId().equals(dmpDepositModel.getRepositoryId())).findFirst().orElse(null);
if (source == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{dmpDepositModel.getRepositoryId(), DepositSourceEntity.class.getSimpleName()}, LocaleContextHolder.getLocale()));
eu.eudat.model.file.FileEnvelope pdfFile = this.fileTransformerService.exportDmp(dmpEntity.getId(), source.getPdfTransformerId(),"pdf");
@ -217,7 +311,7 @@ public class DepositServiceImpl implements DepositService {
throw new MyNotFoundException("Dmp does not have Users");
}
List<UserEntity> users = this.queryFactory.query(UserQuery.class).ids(dmpUsers.stream().map(x -> x.getUserId()).collect(Collectors.toList())).isActive(IsActive.Active).collect();
List<UserEntity> users = this.queryFactory.query(UserQuery.class).ids(dmpUsers.stream().map(DmpUserEntity::getUserId).collect(Collectors.toList())).isActive(IsActive.Active).collect();
for (UserEntity user: users) {
if (!user.getId().equals(this.userScope.getUserIdSafe()) && !this.conventionService.isListNullOrEmpty(dmpUsers.stream().filter(x -> x.getUserId().equals(user.getId())).collect(Collectors.toList()))){
@ -263,7 +357,7 @@ public class DepositServiceImpl implements DepositService {
}
@Override
public String getLogo(String repositoryId) {
public String getLogo(String repositoryId) throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
this.authorizationService.authorizeForce(Permission.BrowseDeposit, Permission.DeferredAffiliation);
DepositClient depositClient = getDepositClient(repositoryId);
@ -272,7 +366,7 @@ public class DepositServiceImpl implements DepositService {
}
@Override
public String authenticate(DepositAuthenticateRequest model) {
public String authenticate(DepositAuthenticateRequest model) throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
this.authorizationService.authorizeForce(Permission.BrowseDeposit, Permission.DeferredAffiliation);
DepositClient depositClient = getDepositClient(model.getRepositoryId());

View File

@ -4,6 +4,7 @@ import gr.cite.tools.cache.CacheOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@ConfigurationProperties(prefix = "cache.deposit")
public class DepositCacheOptions extends CacheOptions {
@Configuration
@ConfigurationProperties(prefix = "cache.deposit-sources-by-tenant")
public class DepositSourcesCacheOptions extends CacheOptions {
}

View File

@ -0,0 +1,66 @@
package eu.eudat.service.deposit;
import eu.eudat.commons.types.deposit.DepositSourceEntity;
import gr.cite.tools.cache.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
@Service
public class DepositSourcesCacheService extends CacheService<DepositSourcesCacheService.DepositSourceCacheValue> {
public static class DepositSourceCacheValue {
public DepositSourceCacheValue() {
}
public DepositSourceCacheValue(String tenantCode, List<DepositSourceEntity> sources) {
this.tenantCode = tenantCode;
this.sources = sources;
}
private String tenantCode;
private List<DepositSourceEntity> sources;
public List<DepositSourceEntity> getSources() {
return sources;
}
public void setSources(List<DepositSourceEntity> sources) {
this.sources = sources;
}
public String getTenantCode() {
return tenantCode;
}
public void setTenantCode(String tenantCode) {
this.tenantCode = tenantCode;
}
}
@Autowired
public DepositSourcesCacheService(DepositSourcesCacheOptions options) {
super(options);
}
@Override
protected Class<DepositSourceCacheValue> valueClass() {
return DepositSourceCacheValue.class;
}
@Override
public String keyOf(DepositSourceCacheValue value) {
return this.buildKey(value.getTenantCode());
}
public String buildKey(String tenantCod) {
HashMap<String, String> keyParts = new HashMap<>();
keyParts.put("$tenantCode$", tenantCod);
return this.generateKey(keyParts);
}
}

View File

@ -15,8 +15,14 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.multipart.MultipartFile;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@ -34,7 +40,7 @@ public interface DescriptionService {
void clone(UUID dmpId, UUID descriptionId) throws InvalidApplicationException, IOException;
ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException;
ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException;
StorageFile uploadFieldFile(DescriptionFieldFilePersist model, MultipartFile file, FieldSet fields) throws IOException;
StorageFileEntity getFieldFile(UUID descriptionId, UUID storageFileId);

View File

@ -67,9 +67,15 @@ import org.springframework.stereotype.Service;
import org.springframework.util.unit.DataSize;
import org.springframework.web.multipart.MultipartFile;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import java.io.IOException;
import java.net.URLConnection;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
@ -868,7 +874,7 @@ public class DescriptionServiceImpl implements DescriptionService {
//region file export
@Override
public ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException {
public ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
HttpHeaders headers = new HttpHeaders();
FileEnvelope fileEnvelope = this.fileTransformerService.exportDescription(id, null, exportType); //TODO get repo from config

View File

@ -12,10 +12,16 @@ import gr.cite.tools.fieldset.FieldSet;
import jakarta.xml.bind.JAXBException;
import org.springframework.http.ResponseEntity;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.UUID;
@ -38,7 +44,7 @@ public interface DmpService {
List<DmpUser> assignUsers(UUID dmp, List<DmpUserPersist> model, FieldSet fields, boolean disableDelete) throws InvalidApplicationException, IOException;
Dmp removeUser(DmpUserRemovePersist model, FieldSet fields) throws InvalidApplicationException, IOException;
ResponseEntity<byte[]> export(UUID id, String transformerId, String exportType) throws InvalidApplicationException, IOException;
ResponseEntity<byte[]> export(UUID id, String transformerId, String exportType) throws InvalidApplicationException, IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException;
void inviteUserOrAssignUsers(UUID id, List<DmpUserPersist> users) throws InvalidApplicationException, JAXBException, IOException;

View File

@ -76,8 +76,14 @@ import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
@ -650,7 +656,7 @@ public class DmpServiceImpl implements DmpService {
}
@Override
public ResponseEntity<byte[]> export(UUID id, String transformerId, String exportType) throws InvalidApplicationException, IOException {
public ResponseEntity<byte[]> export(UUID id, String transformerId, String exportType) throws InvalidApplicationException, IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
HttpHeaders headers = new HttpHeaders();
FileEnvelope fileEnvelope = this.fileTransformerService.exportDmp(id, transformerId, exportType);

View File

@ -1,8 +0,0 @@
package eu.eudat.service.filetransformer;
import gr.cite.tools.cache.CacheOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "cache.file-transformer")
public class FileTransformerCacheOptions extends CacheOptions {
}

View File

@ -4,6 +4,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties({FileTransformerProperties.class, FileTransformerCacheOptions.class})
@EnableConfigurationProperties({FileTransformerProperties.class})
public class FileTransformerConfiguration {
}

View File

@ -1,20 +0,0 @@
package eu.eudat.service.filetransformer;
import eu.eudat.model.file.TransformerCacheModel;
import gr.cite.tools.cache.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class FileTransformerConfigurationCache extends CacheService<TransformerCacheModel> {
@Autowired
public FileTransformerConfigurationCache(FileTransformerCacheOptions options) {
super(options);
}
@Override
protected Class<TransformerCacheModel> valueClass() {
return TransformerCacheModel.class;
}
}

View File

@ -0,0 +1,10 @@
package eu.eudat.service.filetransformer;
import gr.cite.tools.cache.CacheOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "cache.file-transformer-config-by-id")
public class FileTransformerConfigurationCacheOptions extends CacheOptions {
}

View File

@ -0,0 +1,77 @@
package eu.eudat.service.filetransformer;
import eu.eudat.file.transformer.interfaces.FileTransformerConfiguration;
import gr.cite.tools.cache.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
@Service
public class FileTransformerConfigurationCacheService extends CacheService<FileTransformerConfigurationCacheService.FileTransformerConfigurationCacheValue> {
public static class FileTransformerConfigurationCacheValue {
public FileTransformerConfigurationCacheValue() {
}
public FileTransformerConfigurationCacheValue(String repositoryId, String tenantCode, FileTransformerConfiguration configuration) {
this.transformerId = repositoryId;
this.configuration = configuration;
this.tenantCode = tenantCode == null ? "" : tenantCode;
}
private String transformerId;
private String tenantCode;
public String getTransformerId() {
return transformerId;
}
public void setTransformerId(String transformerId) {
this.transformerId = transformerId;
}
private FileTransformerConfiguration configuration;
public FileTransformerConfiguration getConfiguration() {
return configuration;
}
public void setConfiguration(FileTransformerConfiguration configuration) {
this.configuration = configuration;
}
public String getTenantCode() {
return tenantCode;
}
public void setTenantCode(String tenantCode) {
this.tenantCode = tenantCode;
}
}
@Autowired
public FileTransformerConfigurationCacheService(FileTransformerConfigurationCacheOptions options) {
super(options);
}
@Override
protected Class<FileTransformerConfigurationCacheService.FileTransformerConfigurationCacheValue> valueClass() {
return FileTransformerConfigurationCacheService.FileTransformerConfigurationCacheValue.class;
}
@Override
public String keyOf(FileTransformerConfigurationCacheService.FileTransformerConfigurationCacheValue value) {
return this.buildKey(value.getTransformerId(), value.getTenantCode());
}
public String buildKey(String transformerId, String tenantCod) {
HashMap<String, String> keyParts = new HashMap<>();
keyParts.put("$transformerId$", transformerId);
keyParts.put("$tenantCode$", tenantCod);
return this.generateKey(keyParts);
}
}

View File

@ -2,13 +2,20 @@ package eu.eudat.service.filetransformer;
import eu.eudat.model.file.RepositoryFileFormat;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.UUID;
public interface FileTransformerService {
List<RepositoryFileFormat> getAvailableExportFileFormats();
List<RepositoryFileFormat> getAvailableExportFileFormats() throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, InvalidApplicationException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException;
eu.eudat.model.file.FileEnvelope exportDmp(UUID dmpId, String repositoryId, String format);
eu.eudat.model.file.FileEnvelope exportDmp(UUID dmpId, String repositoryId, String format) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, InvalidApplicationException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException;
eu.eudat.model.file.FileEnvelope exportDescription(UUID descriptionId, String repositoryId, String format);
eu.eudat.model.file.FileEnvelope exportDescription(UUID descriptionId, String repositoryId, String format) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, InvalidApplicationException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException;
}

View File

@ -5,18 +5,29 @@ import eu.eudat.authorization.Permission;
import eu.eudat.commonmodels.models.FileEnvelopeModel;
import eu.eudat.commonmodels.models.description.DescriptionModel;
import eu.eudat.commonmodels.models.dmp.DmpModel;
import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.enums.StorageType;
import eu.eudat.commons.enums.TenantConfigurationType;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.commons.types.filetransformer.FileTransformerSourceEntity;
import eu.eudat.commons.types.tenantconfiguration.FileTransformerTenantConfigurationEntity;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.TenantConfigurationEntity;
import eu.eudat.event.TenantConfigurationTouchedEvent;
import eu.eudat.file.transformer.interfaces.FileTransformerConfiguration;
import eu.eudat.model.Description;
import eu.eudat.model.Dmp;
import eu.eudat.model.builder.commonmodels.description.DescriptionCommonModelBuilder;
import eu.eudat.model.builder.commonmodels.dmp.DmpCommonModelBuilder;
import eu.eudat.model.file.RepositoryFileFormat;
import eu.eudat.model.file.TransformerCacheModel;
import eu.eudat.model.tenantconfiguration.TenantConfiguration;
import eu.eudat.query.DescriptionQuery;
import eu.eudat.query.DmpQuery;
import eu.eudat.query.TenantConfigurationQuery;
import eu.eudat.service.encryption.EncryptionService;
import eu.eudat.service.storage.StorageFileService;
import eu.eudat.service.tenant.TenantProperties;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.commons.web.oidc.filter.webflux.TokenExchangeCacheService;
import gr.cite.commons.web.oidc.filter.webflux.TokenExchangeFilterFunction;
@ -24,17 +35,25 @@ import gr.cite.commons.web.oidc.filter.webflux.TokenExchangeModel;
import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyNotFoundException;
import gr.cite.tools.fieldset.BaseFieldSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.event.EventListener;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import java.net.URI;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
@Service
@ -44,88 +63,164 @@ public class FileTransformerServiceImpl implements FileTransformerService {
private final FileTransformerProperties fileTransformerProperties;
private final Map<String, FileTransformerRepository> clients;
private final TokenExchangeCacheService tokenExchangeCacheService;
private final FileTransformerConfigurationCache fileTransformerConfigurationCache;
private final FileTransformerConfigurationCacheService fileTransformerConfigurationCacheService;
private final AuthorizationService authorizationService;
private final QueryFactory queryFactory;
private final BuilderFactory builderFactory;
private final StorageFileService storageFileService;
private final MessageSource messageSource;
private final ConventionService conventionService;
private final TenantScope tenantScope;
private final EncryptionService encryptionService;
private final TenantProperties tenantProperties;
private final JsonHandlingService jsonHandlingService;
private final FileTransformerSourcesCacheService fileTransformerSourcesCacheService;
@Autowired
public FileTransformerServiceImpl(FileTransformerProperties fileTransformerProperties, TokenExchangeCacheService tokenExchangeCacheService, FileTransformerConfigurationCache fileTransformerConfigurationCache, AuthorizationService authorizationService,
QueryFactory queryFactory, BuilderFactory builderFactory, StorageFileService storageFileService, MessageSource messageSource) {
public FileTransformerServiceImpl(FileTransformerProperties fileTransformerProperties, TokenExchangeCacheService tokenExchangeCacheService, FileTransformerConfigurationCacheService fileTransformerConfigurationCacheService, AuthorizationService authorizationService,
QueryFactory queryFactory, BuilderFactory builderFactory, StorageFileService storageFileService, MessageSource messageSource, ConventionService conventionService, TenantScope tenantScope, EncryptionService encryptionService, TenantProperties tenantProperties, JsonHandlingService jsonHandlingService, FileTransformerSourcesCacheService fileTransformerSourcesCacheService) {
this.fileTransformerProperties = fileTransformerProperties;
this.tokenExchangeCacheService = tokenExchangeCacheService;
this.fileTransformerConfigurationCache = fileTransformerConfigurationCache;
this.authorizationService = authorizationService;
this.fileTransformerConfigurationCacheService = fileTransformerConfigurationCacheService;
this.authorizationService = authorizationService;
this.queryFactory = queryFactory;
this.builderFactory = builderFactory;
this.storageFileService = storageFileService;
this.messageSource = messageSource;
this.conventionService = conventionService;
this.tenantScope = tenantScope;
this.encryptionService = encryptionService;
this.tenantProperties = tenantProperties;
this.jsonHandlingService = jsonHandlingService;
this.fileTransformerSourcesCacheService = fileTransformerSourcesCacheService;
this.clients = new HashMap<>();
}
private FileTransformerRepository getRepository(String repoId) {
if (this.clients.containsKey(repoId)) return this.clients.get(repoId);
private FileTransformerRepository getRepository(String repoId) throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
String repositoryIdByTenant = this.getRepositoryIdByTenant(repoId);
if (this.clients.containsKey(repositoryIdByTenant)) return this.clients.get(repositoryIdByTenant);
//GK: It's register time
FileTransformerSourceEntity source = fileTransformerProperties.getSources().stream().filter(depositSource -> depositSource.getTransformerId().equals(repoId)).findFirst().orElse(null);
FileTransformerSourceEntity source = this.getFileTransformerSources().stream().filter(fileTransformerSourceEntity -> fileTransformerSourceEntity.getTransformerId().equals(repoId)).findFirst().orElse(null);
if (source != null) {
String host = URI.create(source.getUrl()).getHost();
TokenExchangeModel tokenExchangeModel = new TokenExchangeModel(host + "_" + source.getClientId(), source.getIssuerUrl(), source.getClientId(), source.getClientSecret(), source.getScope());
TokenExchangeModel tokenExchangeModel = new TokenExchangeModel("file_transformer:" + repositoryIdByTenant, source.getIssuerUrl(), source.getClientId(), source.getClientSecret(), source.getScope());
TokenExchangeFilterFunction tokenExchangeFilterFunction = new TokenExchangeFilterFunction(this.tokenExchangeCacheService, tokenExchangeModel);
FileTransformerRepository repository = new FileTransformerRepository(WebClient.builder().baseUrl(source.getUrl() + "/api/file-transformer").filters(exchangeFilterFunctions -> {
exchangeFilterFunctions.add(tokenExchangeFilterFunction);
exchangeFilterFunctions.add(logRequest());
}).build());
this.clients.put(source.getTransformerId(), repository);
this.clients.put(repositoryIdByTenant, repository);
return repository;
}
return null;
}
private List<FileTransformerSourceEntity> getFileTransformerSources() throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
String tenantCode = this.tenantScope.isSet() && this.tenantScope.isMultitenant() ? this.tenantScope.getTenantCode() : "";
FileTransformerSourcesCacheService.FileTransformerSourceCacheValue cacheValue = this.fileTransformerSourcesCacheService.lookup(this.fileTransformerSourcesCacheService.buildKey(tenantCode));
if (cacheValue == null) {
List<FileTransformerSourceEntity> fileTransformerSourceEntities = new ArrayList<>(fileTransformerProperties.getSources());
if (this.tenantScope.isSet() && this.tenantScope.isMultitenant()) {
TenantConfigurationQuery tenantConfigurationQuery = this.queryFactory.query(TenantConfigurationQuery.class).isActive(IsActive.Active).types(TenantConfigurationType.FileTransformerPlugins);
if (this.tenantScope.isDefaultTenant()) tenantConfigurationQuery.tenantIsSet(false);
else tenantConfigurationQuery.tenantIsSet(true).tenantIds(this.tenantScope.getTenant());
TenantConfigurationEntity tenantConfiguration = tenantConfigurationQuery.firstAs(new BaseFieldSet().ensure(TenantConfiguration._fileTransformerPlugins));
if (tenantConfiguration != null && !this.conventionService.isNullOrEmpty(tenantConfiguration.getValue())) {
FileTransformerTenantConfigurationEntity fileTransformerTenantConfigurationEntity = this.jsonHandlingService.fromJsonSafe(FileTransformerTenantConfigurationEntity.class, tenantConfiguration.getValue());
if (fileTransformerTenantConfigurationEntity != null) {
if (fileTransformerTenantConfigurationEntity.getDisableSystemSources()) fileTransformerSourceEntities = new ArrayList<>();
fileTransformerSourceEntities.addAll(this.buildFileTransformerSourceItems(fileTransformerTenantConfigurationEntity.getSources()));
}
}
}
cacheValue = new FileTransformerSourcesCacheService.FileTransformerSourceCacheValue(tenantCode, fileTransformerSourceEntities);
this.fileTransformerSourcesCacheService.put(cacheValue);
}
return cacheValue.getSources();
}
@EventListener
public void handleTenantConfigurationTouchedEvent(TenantConfigurationTouchedEvent event) {
if (!event.getType().equals(TenantConfigurationType.FileTransformerPlugins)) return;
FileTransformerSourcesCacheService.FileTransformerSourceCacheValue fileTransformerSourceCacheValue = this.fileTransformerSourcesCacheService.lookup(this.fileTransformerSourcesCacheService.buildKey(event.getTenantCode()));
if (fileTransformerSourceCacheValue != null && fileTransformerSourceCacheValue.getSources() != null){
for (FileTransformerSourceEntity source : fileTransformerSourceCacheValue.getSources()){
String repositoryIdByTenant = source.getTransformerId() + "_" + event.getTenantCode();
this.clients.remove(repositoryIdByTenant);
this.fileTransformerConfigurationCacheService.evict(this.fileTransformerConfigurationCacheService.buildKey(source.getTransformerId(), event.getTenantCode()));
}
}
this.fileTransformerSourcesCacheService.evict(this.fileTransformerSourcesCacheService.buildKey(event.getTenantCode()));
}
private List<FileTransformerSourceEntity> buildFileTransformerSourceItems(List<FileTransformerSourceEntity> sources) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
List<FileTransformerSourceEntity> items = new ArrayList<>();
if (this.conventionService.isListNullOrEmpty(sources)) return items;
for (FileTransformerSourceEntity source : sources){
FileTransformerSourceEntity item = new FileTransformerSourceEntity();
item.setTransformerId(source.getTransformerId());
item.setUrl(source.getUrl());
item.setIssuerUrl(source.getIssuerUrl());
item.setClientId(source.getClientId());
if (!this.conventionService.isNullOrEmpty(source.getClientSecret())) item.setClientSecret(this.encryptionService.decryptAES(source.getClientSecret(), tenantProperties.getConfigEncryptionAesKey(), tenantProperties.getConfigEncryptionAesIv()));
item.setScope(source.getScope());
items.add(item);
}
return items;
}
private String getRepositoryIdByTenant(String repositoryId) throws InvalidApplicationException {
if (this.tenantScope.isSet() && this.tenantScope.isMultitenant()) {
return repositoryId + "_" + this.tenantScope.getTenantCode();
} else {
return repositoryId;
}
}
@Override
public List<RepositoryFileFormat> getAvailableExportFileFormats() {
public List<RepositoryFileFormat> getAvailableExportFileFormats() throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, InvalidApplicationException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
List<RepositoryFileFormat> formats = new ArrayList<>();
List<FileTransformerConfiguration> configurations = this.getAvailableConfigurations();
if(configurations != null){
for (FileTransformerConfiguration configuration : configurations){
if (configuration != null && configuration.getExportVariants() != null) formats.addAll(configuration.getExportVariants().stream().map(x-> new RepositoryFileFormat(configuration.getFileTransformerId(), x, configuration.getExportEntityTypes())).toList());
}
for (FileTransformerConfiguration configuration : configurations){
if (configuration != null && configuration.getExportVariants() != null) formats.addAll(configuration.getExportVariants().stream().map(x-> new RepositoryFileFormat(configuration.getFileTransformerId(), x, configuration.getExportEntityTypes())).toList());
}
return formats;
}
private List<FileTransformerConfiguration> getAvailableConfigurations() {
TransformerCacheModel configs = fileTransformerConfigurationCache.lookup("base");
if (configs == null) {
List<FileTransformerConfiguration> configurations = new ArrayList<>();
//GK: So much for lazy loading
List<FileTransformerRepository> repositories = fileTransformerProperties.getSources().stream().map(depositSource -> getRepository(depositSource.getTransformerId())).toList();
private List<FileTransformerConfiguration> getAvailableConfigurations() throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, InvalidApplicationException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
List<FileTransformerConfiguration> configurations = new ArrayList<>();
repositories = new ArrayList<>(repositories);
repositories.forEach((client) -> {
for (FileTransformerSourceEntity transformerSource : this.getFileTransformerSources()) {
String tenantCode = this.tenantScope.isSet() && this.tenantScope.isMultitenant() ? this.tenantScope.getTenantCode() : "";
FileTransformerConfigurationCacheService.FileTransformerConfigurationCacheValue cacheValue = this.fileTransformerConfigurationCacheService.lookup(this.fileTransformerConfigurationCacheService.buildKey(transformerSource.getTransformerId(), tenantCode));
if (cacheValue == null){
try {
FileTransformerConfiguration repositoryConfig = client.getConfiguration();
if (repositoryConfig != null) {
configurations.add(repositoryConfig);
}
} catch (Exception e) {
logger.warn(e.getLocalizedMessage(), e);
}
});
FileTransformerRepository fileTransformerRepository = getRepository(transformerSource.getTransformerId());
if (fileTransformerRepository == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{transformerSource.getTransformerId(), FileTransformerRepository.class.getSimpleName()}, LocaleContextHolder.getLocale()));
configs = new TransformerCacheModel(configurations);
this.fileTransformerConfigurationCache.put("base", configs);
FileTransformerConfiguration configuration = fileTransformerRepository.getConfiguration();
cacheValue = new FileTransformerConfigurationCacheService.FileTransformerConfigurationCacheValue(transformerSource.getTransformerId(), tenantCode, configuration);
this.fileTransformerConfigurationCacheService.put(cacheValue);
}catch (Exception e){
logger.error(e.getMessage(), e);
}
}
if (cacheValue != null) {
configurations.add(cacheValue.getConfiguration());
}
}
return configs.getConfigurations();
return configurations;
}
@Override
public eu.eudat.model.file.FileEnvelope exportDmp(UUID dmpId, String repositoryId, String format) {
public eu.eudat.model.file.FileEnvelope exportDmp(UUID dmpId, String repositoryId, String format) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, InvalidApplicationException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
this.authorizationService.authorize(Permission.EditDmp);
//GK: First get the right client
FileTransformerRepository repository = getRepository(repositoryId);
@ -145,7 +240,7 @@ public class FileTransformerServiceImpl implements FileTransformerService {
}
@Override
public eu.eudat.model.file.FileEnvelope exportDescription(UUID descriptionId, String repositoryId, String format) {
public eu.eudat.model.file.FileEnvelope exportDescription(UUID descriptionId, String repositoryId, String format) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, InvalidApplicationException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
this.authorizationService.authorize(Permission.EditDmp);
//GK: First get the right client
FileTransformerRepository repository = getRepository(repositoryId);

View File

@ -0,0 +1,10 @@
package eu.eudat.service.filetransformer;
import gr.cite.tools.cache.CacheOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "cache.file-transformer-sources-by-tenant")
public class FileTransformerSourcesCacheOptions extends CacheOptions {
}

View File

@ -0,0 +1,67 @@
package eu.eudat.service.filetransformer;
import eu.eudat.commons.types.filetransformer.FileTransformerSourceEntity;
import gr.cite.tools.cache.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
@Service
public class FileTransformerSourcesCacheService extends CacheService<FileTransformerSourcesCacheService.FileTransformerSourceCacheValue> {
public static class FileTransformerSourceCacheValue {
public FileTransformerSourceCacheValue() {
}
public FileTransformerSourceCacheValue(String tenantCode, List<FileTransformerSourceEntity> sources) {
this.tenantCode = tenantCode;
this.sources = sources;
}
private String tenantCode;
private List<FileTransformerSourceEntity> sources;
public String getTenantCode() {
return tenantCode;
}
public void setTenantCode(String tenantCode) {
this.tenantCode = tenantCode;
}
public List<FileTransformerSourceEntity> getSources() {
return sources;
}
public void setSources(List<FileTransformerSourceEntity> sources) {
this.sources = sources;
}
}
@Autowired
public FileTransformerSourcesCacheService(FileTransformerSourcesCacheOptions options) {
super(options);
}
@Override
protected Class<FileTransformerSourceCacheValue> valueClass() {
return FileTransformerSourceCacheValue.class;
}
@Override
public String keyOf(FileTransformerSourceCacheValue value) {
return this.buildKey(value.getTenantCode());
}
public String buildKey(String tenantCod) {
HashMap<String, String> keyParts = new HashMap<>();
keyParts.put("$tenantCode$", tenantCod);
return this.generateKey(keyParts);
}
}

View File

@ -69,11 +69,7 @@ public class TenantServiceImpl implements TenantService {
private final ConventionService conventionService;
private final MessageSource messageSource;
private final XmlHandlingService xmlHandlingService;
private final ErrorThesaurusProperties errors;
private final EncryptionService encryptionService;
private final TenantProperties properties;
private final TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler;
private final TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler;
private final KeycloakService keycloakService;
@ -90,19 +86,14 @@ public class TenantServiceImpl implements TenantService {
BuilderFactory builderFactory,
ConventionService conventionService,
MessageSource messageSource,
XmlHandlingService xmlHandlingService,
ErrorThesaurusProperties errors,
EncryptionService encryptionService, TenantProperties properties, TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler, TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler, KeycloakService keycloakService, AuthorizationProperties authorizationProperties, TenantScope tenantScope, QueryFactory queryFactory) {
ErrorThesaurusProperties errors, TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler, TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler, KeycloakService keycloakService, AuthorizationProperties authorizationProperties, TenantScope tenantScope, QueryFactory queryFactory) {
this.entityManager = entityManager;
this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory;
this.builderFactory = builderFactory;
this.conventionService = conventionService;
this.messageSource = messageSource;
this.xmlHandlingService = xmlHandlingService;
this.errors = errors;
this.encryptionService = encryptionService;
this.properties = properties;
this.tenantTouchedIntegrationEventHandler = tenantTouchedIntegrationEventHandler;
this.tenantRemovalIntegrationEventHandler = tenantRemovalIntegrationEventHandler;
this.keycloakService = keycloakService;

View File

@ -7,13 +7,17 @@ import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.enums.StorageType;
import eu.eudat.commons.enums.TenantConfigurationType;
import eu.eudat.commons.scope.tenant.TenantScope;
import eu.eudat.commons.types.deposit.DepositSourceEntity;
import eu.eudat.commons.types.filetransformer.FileTransformerSourceEntity;
import eu.eudat.commons.types.tenantconfiguration.*;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.TenantConfigurationEntity;
import eu.eudat.data.TenantEntity;
import eu.eudat.data.TenantEntityManager;
import eu.eudat.errorcode.ErrorThesaurusProperties;
import eu.eudat.event.EventBroker;
import eu.eudat.event.TenantConfigurationTouchedEvent;
import eu.eudat.model.StorageFile;
import eu.eudat.model.builder.tenantconfiguration.TenantConfigurationBuilder;
import eu.eudat.model.deleter.TenantConfigurationDeleter;
@ -82,6 +86,8 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
private final TenantProperties tenantProperties;
private final StorageFileService storageFileService;
private final QueryFactory queryFactory;
private final EventBroker eventBroker;
private final TenantScope tenantScope;
@Autowired
public TenantConfigurationServiceImpl(
TenantEntityManager entityManager,
@ -90,7 +96,7 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
BuilderFactory builderFactory,
ConventionService conventionService,
ErrorThesaurusProperties errors,
MessageSource messageSource, JsonHandlingService jsonHandlingService, EncryptionService encryptionService, TenantProperties tenantProperties, StorageFileService storageFileService, QueryFactory queryFactory) {
MessageSource messageSource, JsonHandlingService jsonHandlingService, EncryptionService encryptionService, TenantProperties tenantProperties, StorageFileService storageFileService, QueryFactory queryFactory, EventBroker eventBroker, TenantScope tenantScope) {
this.entityManager = entityManager;
this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory;
@ -103,6 +109,8 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
this.tenantProperties = tenantProperties;
this.storageFileService = storageFileService;
this.queryFactory = queryFactory;
this.eventBroker = eventBroker;
this.tenantScope = tenantScope;
}
public TenantConfiguration persist(TenantConfigurationPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
@ -150,6 +158,14 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
this.entityManager.flush();
if (data.getTenantId() != null) {
TenantEntity tenant = this.entityManager.find(TenantEntity.class, data.getTenantId());
if (tenant == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{data.getTenantId(), TenantEntity.class.getSimpleName()}, LocaleContextHolder.getLocale()));
this.eventBroker.emit(new TenantConfigurationTouchedEvent(tenant.getId(), tenant.getCode(), data.getType()));
} else {
this.eventBroker.emit(new TenantConfigurationTouchedEvent(data.getId(), this.tenantScope.getDefaultTenantCode(), data.getType()));
}
return this.builderFactory.builder(TenantConfigurationBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, TenantConfiguration._id), data);
}
@ -253,6 +269,14 @@ public class TenantConfigurationServiceImpl implements TenantConfigurationServic
if (oldValue != null && oldValue.getStorageFileId() != null) this.storageFileService.updatePurgeAt(oldValue.getStorageFileId(), Instant.now().minusSeconds(60));
}
this.deleterFactory.deleter(TenantConfigurationDeleter.class).deleteAndSaveByIds(List.of(id));
if (data.getTenantId() != null) {
TenantEntity tenant = this.entityManager.find(TenantEntity.class, data.getTenantId());
if (tenant == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{data.getTenantId(), TenantEntity.class.getSimpleName()}, LocaleContextHolder.getLocale()));
this.eventBroker.emit(new TenantConfigurationTouchedEvent(tenant.getId(), tenant.getCode(), data.getType()));
} else {
this.eventBroker.emit(new TenantConfigurationTouchedEvent(data.getId(), this.tenantScope.getDefaultTenantCode(), data.getType()));
}
}
}

View File

@ -19,6 +19,13 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
@ -45,7 +52,7 @@ public class DepositController {
}
@GetMapping("/repositories/available")
public List<eu.eudat.model.deposit.DepositConfiguration> getAvailableRepos(FieldSet fieldSet) {
public List<eu.eudat.model.deposit.DepositConfiguration> getAvailableRepos(FieldSet fieldSet) throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
logger.debug(new MapLogEntry("retrieving" + DepositConfiguration.class.getSimpleName()).And("fields", fieldSet));
this.censorFactory.censor(DepositConfigurationCensor.class).censor(fieldSet, null);
@ -60,7 +67,7 @@ public class DepositController {
@PostMapping("/get-access-token")
@ValidationFilterAnnotation(validator = DepositAuthenticateRequest.DepositAuthenticateRequestValidator.ValidatorName, argumentName = "model")
public String getAccessToken(@RequestBody DepositAuthenticateRequest model) {
public String getAccessToken(@RequestBody DepositAuthenticateRequest model) throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
logger.debug(new MapLogEntry("get access token" + DepositAuthenticateRequest.class.getSimpleName()).And("model", model));
String accessToken = this.depositService.authenticate(model);
@ -87,7 +94,7 @@ public class DepositController {
}
@GetMapping("/repositories/{repositoryId}/logo")
public String getLogo(@PathVariable("repositoryId") String repositoryId) {
public String getLogo(@PathVariable("repositoryId") String repositoryId) throws InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
logger.debug(new MapLogEntry("get logo" + DepositConfiguration.class.getSimpleName()).And("repositoryId", repositoryId));
String logo = this.depositService.getLogo(repositoryId);

View File

@ -47,8 +47,14 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import static eu.eudat.authorization.AuthorizationFlags.Public;
@ -227,7 +233,7 @@ public class DescriptionController {
}
@GetMapping("{id}/export/{type}")
public ResponseEntity<byte[]> export(@PathVariable("id") UUID id, @PathVariable("type") String exportType) throws InvalidApplicationException, IOException {
public ResponseEntity<byte[]> export(@PathVariable("id") UUID id, @PathVariable("type") String exportType) throws InvalidApplicationException, IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
logger.debug(new MapLogEntry("exporting description"));
return this.descriptionService.export(id, exportType);

View File

@ -35,10 +35,16 @@ import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import static eu.eudat.authorization.AuthorizationFlags.Public;
@ -284,7 +290,7 @@ public class DmpController {
}
@GetMapping("{id}/export/{transformerId}/{type}")
public ResponseEntity<byte[]> export(@PathVariable("id") UUID id, @PathVariable("transformerId") String transformerId, @PathVariable("type") String exportType) throws InvalidApplicationException, IOException {
public ResponseEntity<byte[]> export(@PathVariable("id") UUID id, @PathVariable("transformerId") String transformerId, @PathVariable("type") String exportType) throws InvalidApplicationException, IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
logger.debug(new MapLogEntry("exporting dmp").And("id", id).And("transformerId", transformerId).And("exportType", exportType));
ResponseEntity<byte[]> bytes = this.dmpService.export(id, transformerId, exportType);

View File

@ -16,8 +16,14 @@ import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.management.InvalidApplicationException;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
@RestController
@ -37,7 +43,7 @@ public class FileTransformerController {
}
@GetMapping("/available")
public List<RepositoryFileFormat> getAvailableConfigurations() {
public List<RepositoryFileFormat> getAvailableConfigurations() throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, InvalidApplicationException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
logger.debug(new MapLogEntry("getAvailableConfigurations"));
List<RepositoryFileFormat> model = this.fileTransformerService.getAvailableExportFileFormats();
@ -48,7 +54,7 @@ public class FileTransformerController {
}
@PostMapping("/export-dmp")
public ResponseEntity<byte[]> export(@RequestBody ExportRequestModel requestModel) throws InvalidApplicationException, IOException {
public ResponseEntity<byte[]> export(@RequestBody ExportRequestModel requestModel) throws InvalidApplicationException, IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
logger.debug(new MapLogEntry("exporting dmp"));
HttpHeaders headers = new HttpHeaders();
@ -60,7 +66,7 @@ public class FileTransformerController {
}
@PostMapping("/export-description")
public ResponseEntity<byte[]> exportDescription(@RequestBody ExportRequestModel requestModel) {
public ResponseEntity<byte[]> exportDescription(@RequestBody ExportRequestModel requestModel) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, InvalidApplicationException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
logger.debug(new MapLogEntry("exporting dmp"));
HttpHeaders headers = new HttpHeaders();

View File

@ -26,6 +26,12 @@ cache:
maximumSize: 500
enableRecordStats: false
expireAfterWriteSeconds: 600
- names: [ "depositSourcesByTenant" ]
allowNullValues: true
initialCapacity: 100
maximumSize: 500
enableRecordStats: false
expireAfterWriteSeconds: 600
- names: [ "affiliation" ]
allowNullValues: true
initialCapacity: 100
@ -38,7 +44,13 @@ cache:
maximumSize: 500
enableRecordStats: false
expireAfterWriteSeconds: 30
- names: [ "fileTransformer" ]
- names: [ "fileTransformerConfigById" ]
allowNullValues: true
initialCapacity: 100
maximumSize: 500
enableRecordStats: false
expireAfterWriteSeconds: 600
- names: [ "fileTransformerSourcesByTenant" ]
allowNullValues: true
initialCapacity: 100
maximumSize: 500
@ -101,10 +113,16 @@ cache:
keyPattern: dashboard_stats_by_usr_$key$:v0
depositConfigById:
name: depositConfigById
keyPattern: deposit_config_by_id_$repositoryId$:v0
fileTransformer:
name: fileTransformer
keyPattern: base:v0
keyPattern: deposit_config_by_id_$repositoryId$_$tenantCode$:v0
depositSourcesByTenant:
name: depositSourcesByTenant
keyPattern: deposit_sources_by_tenant_$tenantCode$:v0
fileTransformerConfigById:
name: fileTransformerConfigById
keyPattern: file_transformer_config_by_id_$transformerId$_$tenantCode$:v0
fileTransformerSourcesByTenant:
name: fileTransformerSourcesByTenant
keyPattern: ile_transformer_sources_by_tenant_$tenantCode$:v0
token-exchange-key:
name: tokenExchangeKey
keyPattern: resolve_$keyhash$:v0

View File

@ -1,7 +1,7 @@
deposit:
sources:
- url: http://dev04.local.cite.gr:55330/zenodo
repositoryId: zenodo
repositoryId: Zenodo
pdfTransformerId: docx-file-transformer
rdaTransformerId: rda-file-transformer
issuer-url: ${IDP_ISSUER_URI_TOKEN}
@ -9,7 +9,7 @@ deposit:
client-secret: ${IDP_APIKEY_CLIENT_SECRET}
scope: ${IDP_APIKEY_SCOPE}
- url: http://dev04.local.cite.gr:55330/zenodo1
repositoryId: zenodo1
repositoryId: Zenodo1
pdfTransformerId: docx-file-transformer
rdaTransformerId: rda-file-transformer
issuer-url: ${IDP_ISSUER_URI_TOKEN}