Rdf4JRepositoryManagerWrapper.java

package org.linkedopenactors.rdfpub.store.rdf4j;

import java.io.File;
import java.util.Optional;

import org.apache.commons.rdf.api.Dataset;
import org.apache.commons.rdfrdf4j.RDF4J;
import org.eclipse.rdf4j.common.transaction.QueryEvaluationMode;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.config.RepositoryConfig;
import org.eclipse.rdf4j.repository.config.RepositoryConfigException;
import org.eclipse.rdf4j.repository.manager.RepositoryManager;
import org.eclipse.rdf4j.repository.manager.RepositoryProvider;
import org.eclipse.rdf4j.repository.sail.config.SailRepositoryConfig;
import org.eclipse.rdf4j.sail.inferencer.fc.config.SchemaCachingRDFSInferencerConfig;
import org.eclipse.rdf4j.sail.memory.config.MemoryStoreConfig;
import org.linkedopenactors.rdfpub.store.DatasetRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * Wrapper for {@link RepositoryManager} that is managing {@link Dataset}s based on the underlaying {@link Repository}s.
 */
@Component
class Rdf4JRepositoryManagerWrapper implements DatasetRepository {

	private RDF4J rdf4j;
	private RepositoryManager repositoryManager;

	public Rdf4JRepositoryManagerWrapper(RDF4J rdf4j, @Value("${app.rdfRepositoryHome}") File baseDir) {
		this.rdf4j = rdf4j;
		repositoryManager = RepositoryProvider.getRepositoryManager(baseDir);
		repositoryManager.init();
	}
	
	/**
	 * Gets the repository that is known by the specified ID from the underlaying
	 * {@link RepositoryManager} and convert it to a {@link Dataset} using
	 * {@link RDF4J#asDataset(Repository, org.apache.commons.rdfrdf4j.RDF4J.Option...)}.
	 * 
	 * @param id
	 * @return A {@link Dataset} backed by an initialized {@link Repository} object, or {@link Optional#empty()} if no {@link Repository} was known for the specified ID.
	 * @throws RepositoryConfigException If no repository could be created due to invalid or incomplete configuration
	 *                                   data.
	 */
	public Optional<Dataset> findDataset(String id) {
		return Optional.ofNullable(repositoryManager.getRepository(id))
				.map(rdf4j::asDataset);
	}

	public Optional<Repository> findRepository(String id) {
		return Optional.ofNullable(repositoryManager.getRepository(id));
	}
	
	/**
	 * Gets or create a repository that is/will be known by the specified ID from the underlaying
	 * {@link RepositoryManager} and convert it to a {@link Dataset} using
	 * {@link RDF4J#asDataset(Repository, org.apache.commons.rdfrdf4j.RDF4J.Option...)}.
	 * 
	 * @param id
	 * @return A {@link Dataset} backed by an initialized {@link Repository} object, or {@link Optional#empty()} if no {@link Repository} was known for the specified ID.
	 */
	public Dataset createDataset(String id) {
		if(!repositoryManager.hasRepositoryConfig(id)) {
			createAndAddRdf4jRepositoryConfig(id);
		}
		return findDataset(id).orElseThrow();		
	}

	public Repository createRepository(String id) {
		if(!repositoryManager.hasRepositoryConfig(id)) {
			createAndAddRdf4jRepositoryConfig(id);
		}
		return findRepository(id).orElseThrow();		
	}

	/**
	 * Creates a new {@link RepositoryConfig} and adds it to the {@link RepositoryManager}.
	 * @param id
	 */
	private void createAndAddRdf4jRepositoryConfig(String id) {
		boolean persist = true;
		var storeConfig = new MemoryStoreConfig(persist);
		storeConfig.setDefaultQueryEvaluationMode(QueryEvaluationMode.STANDARD);
		
		var stackConfig = new SchemaCachingRDFSInferencerConfig(storeConfig);
		SailRepositoryConfig repositoryTypeSpec = new SailRepositoryConfig(stackConfig);
		
		repositoryManager.addRepositoryConfig(new RepositoryConfig(id, repositoryTypeSpec));
	}

	/**
	 * Delegate the shutdown comman to the underlaying {@link RepositoryManager}. 
	 */
	public void shutdown() {
		repositoryManager.shutDown();
	}
}