argos/dmp-backend/core/src/main/java/eu/eudat/service/transformer/FileTransformerService.java

180 lines
10 KiB
Java

package eu.eudat.service.transformer;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.Permission;
import eu.eudat.cache.transformer.FileTransformerConfigurationCache;
import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.enums.StorageType;
import eu.eudat.configurations.transformer.TransformerProperties;
import eu.eudat.convention.ConventionService;
import eu.eudat.file.transformer.interfaces.FileTransformerConfiguration;
import eu.eudat.file.transformer.models.description.DescriptionFileTransformerModel;
import eu.eudat.file.transformer.models.dmp.DmpFileTransformerModel;
import eu.eudat.file.transformer.models.misc.FileEnvelope;
import eu.eudat.file.transformer.models.misc.FileFormat;
import eu.eudat.model.builder.filetransformer.DescriptionFileTransformerBuilder;
import eu.eudat.model.builder.filetransformer.DmpFileTransformerBuilder;
import eu.eudat.model.file.TransformerCacheModel;
import eu.eudat.query.DescriptionQuery;
import eu.eudat.query.DmpQuery;
import eu.eudat.query.EntityDoiQuery;
import eu.eudat.repository.TransformerRepository;
import eu.eudat.service.entitydoi.EntityDoiService;
import eu.eudat.service.storage.StorageFileService;
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;
import gr.cite.commons.web.oidc.filter.webflux.TokenExchangeModel;
import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.query.QueryFactory;
import jakarta.persistence.EntityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
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 javax.management.InvalidApplicationException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.util.*;
@Service
public class FileTransformerService {
private static final Logger logger = LoggerFactory.getLogger(FileTransformerService.class);
private final TransformerProperties transformerProperties;
private final Map<String, TransformerRepository> clients;
private final TokenExchangeCacheService tokenExchangeCacheService;
private final FileTransformerConfigurationCache fileTransformerConfigurationCache;
private final AuthorizationService authorizationService;
private final ConventionService conventionService;
private final Environment environment;
private final WebClient.Builder webClientBuilder;
private final EntityDoiService doiService;
private final ApplicationContext applicationContext;
private final JsonHandlingService jsonHandlingService;
private final QueryFactory queryFactory;
private final BuilderFactory builderFactory;
private final StorageFileService storageFileService;
@Autowired
public FileTransformerService(TransformerProperties transformerProperties, TokenExchangeCacheService tokenExchangeCacheService, FileTransformerConfigurationCache fileTransformerConfigurationCache, WebClient.Builder builder, EntityManager entityManager, AuthorizationService authorizationService, ConventionService conventionService, Environment environment, DmpQuery dmpQuery, EntityDoiQuery doiQuery, EntityDoiService doiService, ApplicationContext applicationContext, JsonHandlingService jsonHandlingService, QueryFactory queryFactory, BuilderFactory builderFactory, StorageFileService storageFileService) {
this.transformerProperties = transformerProperties;
this.tokenExchangeCacheService = tokenExchangeCacheService;
this.fileTransformerConfigurationCache = fileTransformerConfigurationCache;
this.authorizationService = authorizationService;
this.conventionService = conventionService;
this.environment = environment;
this.webClientBuilder = builder;
this.doiService = doiService;
this.applicationContext = applicationContext;
this.jsonHandlingService = jsonHandlingService;
this.queryFactory = queryFactory;
this.builderFactory = builderFactory;
this.storageFileService = storageFileService;
this.clients = new HashMap<>();
}
private TransformerRepository getRepository(String repoId) {
if (this.clients.containsKey(repoId)) return this.clients.get(repoId);
//GK: It's register time
TransformerProperties.TransformerSource source = transformerProperties.getSources().stream().filter(depositSource -> depositSource.getCodes().contains(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());
TokenExchangeFilterFunction tokenExchangeFilterFunction = new TokenExchangeFilterFunction(this.tokenExchangeCacheService, tokenExchangeModel);
TransformerRepository repository = new TransformerRepository(webClientBuilder.baseUrl(source.getUrl() + "/api/file").filters(exchangeFilterFunctions -> {
exchangeFilterFunctions.add(tokenExchangeFilterFunction);
exchangeFilterFunctions.add(logRequest());
}).build());
source.getCodes().forEach(code -> this.clients.put(code, repository));
return repository;
}
return null;
}
public List<FileFormat> getAvailableConfigurations() {
TransformerCacheModel configs = fileTransformerConfigurationCache.lookup("base");
if (configs == null) {
List<FileFormat> configurations = new ArrayList<>();
//GK: So much for lazy loading
List<TransformerRepository> repositories = transformerProperties.getSources().stream().map(depositSource -> getRepository(depositSource.getCodes().get(0))).toList();
repositories.forEach((client) -> {
FileTransformerConfiguration repositoryConfigs = client.getConfiguration();
if (repositoryConfigs != null && !repositoryConfigs.getExportVariants().isEmpty()) {
configurations.addAll(repositoryConfigs.getExportVariants());
}
});
configs = new TransformerCacheModel(configurations);
this.fileTransformerConfigurationCache.put("base", configs);
}
return configs.getFormats();
}
public eu.eudat.model.file.FileEnvelope exportDmp(UUID dmpId, String format) throws InvalidApplicationException, IOException {
this.authorizationService.authorize(Permission.EditDmp);
//GK: Why it is in that service, and why it's not static?
this.conventionService.isValidGuid(dmpId);
//GK: First get the right client
TransformerRepository repository = getRepository(format);
//GK: Second get the Target Data Management Plan
DmpQuery query = this.queryFactory.query(DmpQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).ids(dmpId);
DmpFileTransformerModel dmpFileTransformerModel = this.builderFactory.builder(DmpFileTransformerBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(query.first());
dmpFileTransformerModel.setVariant(format);
FileEnvelope fileEnvelope = repository.exportDmp(dmpFileTransformerModel);
eu.eudat.model.file.FileEnvelope result = new eu.eudat.model.file.FileEnvelope();
byte[] data = storageFileService.readByFileRefAsBytesSafe(fileEnvelope.getFile(), StorageType.Transformer);
File temp = new File(environment.getProperty("path.path") + UUID.randomUUID());
try (FileOutputStream fos = new FileOutputStream(temp)) {
fos.write(data);
}
result.setFile(temp);
result.setFilename(fileEnvelope.getFilename());
return result;
}
public eu.eudat.model.file.FileEnvelope exportDescription(UUID descriptionId, String format) throws InvalidApplicationException, IOException {
this.authorizationService.authorize(Permission.EditDmp);
//GK: Why it is in that service, and why it's not static?
this.conventionService.isValidGuid(descriptionId);
//GK: First get the right client
TransformerRepository repository = getRepository(format);
//GK: Second get the Target Data Management Plan
DescriptionQuery query = this.queryFactory.query(DescriptionQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).ids(descriptionId);
DescriptionFileTransformerModel descriptionFileTransformerModel = this.builderFactory.builder(DescriptionFileTransformerBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(query.first());
descriptionFileTransformerModel.setCreatedBy(descriptionFileTransformerModel.getDmp().getCreator());
FileEnvelope fileEnvelope = repository.exportDescription(descriptionFileTransformerModel, format);
eu.eudat.model.file.FileEnvelope result = new eu.eudat.model.file.FileEnvelope();
byte[] data = this.storageFileService.readByFileRefAsBytesSafe(fileEnvelope.getFile(), StorageType.Transformer);
File temp = new File(environment.getProperty("path.path") + UUID.randomUUID());
try (FileOutputStream fos = new FileOutputStream(temp)) {
fos.write(data);
}
result.setFile(temp);
result.setFilename(fileEnvelope.getFilename());
return result;
}
// This method returns filter function which will log request data
private static ExchangeFilterFunction logRequest() {
return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
logger.info("Request: {} {}", clientRequest.method(), clientRequest.url());
clientRequest.headers().forEach((name, values) -> values.forEach(value -> logger.info("{}={}", name, value)));
return Mono.just(clientRequest);
});
}
}