Skip to content

Commit

Permalink
Merge pull request #1568 from thehyve/refactoring/FAIRSPC-79
Browse files Browse the repository at this point in the history
Refactoring/fairspc 79
  • Loading branch information
tgreenwood authored Oct 24, 2024
2 parents 59e870e + 56e4d30 commit 19e7e18
Show file tree
Hide file tree
Showing 90 changed files with 1,277 additions and 1,066 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.fairspace.saturn.config;

import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.resource.UsersResource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import io.fairspace.saturn.config.properties.KeycloakClientProperties;

@Configuration
public class KeycloakConfig {

@Bean
public UsersResource usersResource(Keycloak keycloak, KeycloakClientProperties keycloakClientProperties) {
return keycloak.realm(keycloakClientProperties.getRealm()).users();
}

@Bean
public Keycloak keycloak(KeycloakClientProperties keycloakClientProperties) {
return KeycloakBuilder.builder()
.serverUrl(keycloakClientProperties.getAuthServerUrl())
.realm(keycloakClientProperties.getRealm())
.grantType(OAuth2Constants.CLIENT_CREDENTIALS)
.clientId(keycloakClientProperties.getClientId())
.clientSecret(keycloakClientProperties.getClientSecret())
.username(keycloakClientProperties.getClientId())
.password(keycloakClientProperties.getClientSecret())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.fairspace.saturn.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import io.fairspace.saturn.services.IRIModule;

import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;

@Configuration
public class MappingConfig {

/**
* The maapper is used to read views.yaml configuration file
*/
@Bean
public ObjectMapper yamlObjectMapper() {
return new ObjectMapper(new YAMLFactory());
}

@Bean
@Primary // to be used by default, including serialization of JSON responses to HTTP requests
public ObjectMapper jsonObjectMapper() {
return new ObjectMapper()
.registerModule(new IRIModule())
.registerModule(new JavaTimeModule())
.configure(WRITE_DATES_AS_TIMESTAMPS, false)
.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.fairspace.saturn.config;

import org.apache.jena.query.Dataset;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.sparql.util.Symbol;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import io.fairspace.saturn.rdf.transactions.Transactions;
import io.fairspace.saturn.services.metadata.MetadataPermissions;
import io.fairspace.saturn.services.metadata.MetadataService;
import io.fairspace.saturn.services.metadata.validation.ComposedValidator;

@Configuration
public class MetadataConfig {

public static final Symbol METADATA_SERVICE = Symbol.create("metadata_service");

@Bean
public MetadataService metadataService(
Transactions transactions,
MetadataPermissions metadataPermissions,
@Qualifier("dataset") Dataset dataset,
@Qualifier("vocabulary") Model vocabulary,
@Qualifier("systemVocabulary") Model systemVocabulary,
@Qualifier("composedValidator") ComposedValidator composedValidator) {
var metadataService =
new MetadataService(transactions, vocabulary, systemVocabulary, composedValidator, metadataPermissions);
// This is a workaround (old, not a new one) to resolve circular dependency:
// MetadataService --> ComposedValidator --> URIPrefixValidator --> DavFactory --> DirectoryResource -->
// MetadataService
// TODO: refactor to avoid circular dependency and !!!USE!!! injection using Spring (at least in DavFactory)
// this to-do supposes getting rid of the following line and using dataset context for storing metadataService
dataset.getContext().set(METADATA_SERVICE, metadataService);
return metadataService;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.fairspace.saturn.config;

import org.apache.jena.rdf.model.Model;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static org.apache.jena.riot.RDFDataMgr.loadModel;

@Configuration
public class RdfModelConfig {

@Bean
public Model systemVocabulary() {
return loadModel("system-vocabulary.ttl");
}

@Bean
public Model userVocabulary() {
return loadModel("vocabulary.ttl");
}

@Bean
public Model vocabulary(
@Qualifier("systemVocabulary") Model systemVocabulary, @Qualifier("userVocabulary") Model userVocabulary) {
return systemVocabulary.union(userVocabulary);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.fairspace.saturn.config;

import org.apache.jena.query.Dataset;
import org.apache.jena.sparql.core.DatasetImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;

import io.fairspace.saturn.config.properties.JenaProperties;
import io.fairspace.saturn.config.properties.ViewsProperties;
import io.fairspace.saturn.rdf.SaturnDatasetFactory;
import io.fairspace.saturn.rdf.search.FilteredDatasetGraph;
import io.fairspace.saturn.services.metadata.MetadataPermissions;
import io.fairspace.saturn.services.views.ViewStoreClientFactory;

@Configuration
public class RdfStorageConfig {

@Value("${application.publicUrl}")
private String publicUrl;

@Bean
public Dataset dataset(
ViewsProperties viewsProperties,
JenaProperties jenaProperties,
@Nullable ViewStoreClientFactory viewStoreClientFactory) {
return SaturnDatasetFactory.connect(viewsProperties, jenaProperties, viewStoreClientFactory, publicUrl);
}

@Bean
public Dataset filteredDataset(Dataset dataset, MetadataPermissions metadataPermissions) {
var filteredDatasetGraph = new FilteredDatasetGraph(dataset.asDatasetGraph(), metadataPermissions);
return DatasetImpl.wrap(filteredDatasetGraph);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.fairspace.saturn.config;

import javax.sql.DataSource;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import io.fairspace.saturn.config.properties.ViewDatabaseProperties;

@Configuration
@ConditionalOnProperty(value = "application.view-database.enabled", havingValue = "true")
public class SecondaryStorageConfig {

@Bean
public DataSource dataSource(ViewDatabaseProperties viewDatabaseProperties) {
var databaseConfig = getHikariConfig(viewDatabaseProperties);
return new HikariDataSource(databaseConfig);
}

private HikariConfig getHikariConfig(ViewDatabaseProperties viewDatabaseProperties) {
var databaseConfig = new HikariConfig();
databaseConfig.setJdbcUrl(viewDatabaseProperties.getUrl());
databaseConfig.setUsername(viewDatabaseProperties.getUsername());
databaseConfig.setPassword(viewDatabaseProperties.getPassword());
databaseConfig.setAutoCommit(viewDatabaseProperties.isAutoCommitEnabled());
databaseConfig.setConnectionTimeout(viewDatabaseProperties.getConnectionTimeout());
databaseConfig.setMaximumPoolSize(viewDatabaseProperties.getMaxPoolSize());
return databaseConfig;
}
}
Original file line number Diff line number Diff line change
@@ -1,111 +1,56 @@
package io.fairspace.saturn.config;

import java.sql.SQLException;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.RequiredArgsConstructor;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.apache.jena.query.Dataset;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;

import io.fairspace.saturn.config.properties.CacheProperties;
import io.fairspace.saturn.config.properties.FeatureProperties;
import io.fairspace.saturn.config.properties.JenaProperties;
import io.fairspace.saturn.config.properties.KeycloakClientProperties;
import io.fairspace.saturn.config.properties.SearchProperties;
import io.fairspace.saturn.config.properties.ViewDatabaseProperties;
import io.fairspace.saturn.config.properties.WebDavProperties;
import io.fairspace.saturn.rdf.SaturnDatasetFactory;
import io.fairspace.saturn.services.IRIModule;
import io.fairspace.saturn.services.users.UserService;
import io.fairspace.saturn.config.properties.ViewsProperties;
import io.fairspace.saturn.rdf.transactions.Transactions;
import io.fairspace.saturn.services.search.FileSearchService;
import io.fairspace.saturn.services.search.JdbcFileSearchService;
import io.fairspace.saturn.services.search.SparqlFileSearchService;
import io.fairspace.saturn.services.views.JdbcQueryService;
import io.fairspace.saturn.services.views.QueryService;
import io.fairspace.saturn.services.views.SparqlQueryService;
import io.fairspace.saturn.services.views.ViewStoreClientFactory;
import io.fairspace.saturn.services.views.ViewStoreReader;
import io.fairspace.saturn.webdav.DavFactory;

import static io.fairspace.saturn.config.ConfigLoader.VIEWS_CONFIG;

import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;
import static io.fairspace.saturn.services.views.ViewStoreClientFactory.protectedResources;

/**
* Configuration for the Spark filter to enable the Saturn API.
*/
@Configuration
@RequiredArgsConstructor
public class ServiceConfig {

// todo: make the init done by Spring
@Bean
public Services getService(
Keycloak keycloak,
public QueryService queryService(
SparqlQueryService sparqlQueryService,
@Nullable ViewStoreClientFactory viewStoreClientFactory,
FeatureProperties featureProperties,
JenaProperties jenaProperties,
CacheProperties cacheProperties,
SearchProperties searchProperties,
WebDavProperties webDavProperties,
KeycloakClientProperties keycloakClientProperties,
@Value("${application.publicUrl}") String publicUrl) {
var ds = SaturnDatasetFactory.connect(jenaProperties, viewStoreClientFactory, publicUrl);
return new Services(
VIEWS_CONFIG,
ds,
featureProperties,
viewStoreClientFactory,
keycloak.realm(keycloakClientProperties.getRealm()).users(),
jenaProperties,
cacheProperties,
searchProperties,
webDavProperties,
keycloakClientProperties,
publicUrl);
}

@Bean
@ConditionalOnProperty(value = "application.view-database.enabled", havingValue = "true")
public ViewStoreClientFactory getViewStoreClientFactory(
ViewDatabaseProperties viewDatabaseProperties, SearchProperties searchProperties) {
try {
return new ViewStoreClientFactory(VIEWS_CONFIG, viewDatabaseProperties, searchProperties);
} catch (SQLException e) {
throw new RuntimeException("Error connecting to the view database", e);
}
}

@Bean
public SparqlQueryService getSparqlQueryService(Services services) {
return services.getSparqlQueryService();
Transactions transactions,
@Qualifier("davFactory") DavFactory davFactory,
ViewStoreReader viewStoreReader) {
return viewStoreClientFactory == null
? sparqlQueryService
: new JdbcQueryService(transactions, davFactory.root, viewStoreReader);
}

@Bean
public UserService getUserService(Services services) {
return services.getUserService();
}

@Bean
public Keycloak getKeycloak(KeycloakClientProperties keycloakClientProperties) {
return KeycloakBuilder.builder()
.serverUrl(keycloakClientProperties.getAuthServerUrl())
.realm(keycloakClientProperties.getRealm())
.grantType(OAuth2Constants.CLIENT_CREDENTIALS)
.clientId(keycloakClientProperties.getClientId())
.clientSecret(keycloakClientProperties.getClientSecret())
.username(keycloakClientProperties.getClientId())
.password(keycloakClientProperties.getClientSecret())
.build();
}

@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper()
.registerModule(new IRIModule())
.registerModule(new JavaTimeModule())
.configure(WRITE_DATES_AS_TIMESTAMPS, false)
.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
public FileSearchService fileSearchService(
@Qualifier("filteredDataset") Dataset filteredDataset,
@Nullable ViewStoreClientFactory viewStoreClientFactory,
ViewsProperties viewsProperties,
Transactions transactions,
@Qualifier("davFactory") DavFactory davFactory,
ViewStoreReader viewStoreReader) {
// File search should be done using JDBC for performance reasons. However, if the view store is not available,
// or collections and files view is not configured, we fall back to using SPARQL queries on the RDF database
// directly.
boolean useSparqlFileSearchService = viewStoreClientFactory == null
|| viewsProperties.views.stream().noneMatch(view -> protectedResources.containsAll(view.types));

return useSparqlFileSearchService
? new SparqlFileSearchService(filteredDataset)
: new JdbcFileSearchService(transactions, davFactory.root, viewStoreReader);
}
}
Loading

0 comments on commit 19e7e18

Please sign in to comment.