diff --git a/backend/src/main/java/be/informatievlaanderen/vsds/demonstrator/triple/infra/TripleRepositoryImpl.java b/backend/src/main/java/be/informatievlaanderen/vsds/demonstrator/triple/infra/TripleRepositoryImpl.java index 55cf72e..3ff4ea2 100644 --- a/backend/src/main/java/be/informatievlaanderen/vsds/demonstrator/triple/infra/TripleRepositoryImpl.java +++ b/backend/src/main/java/be/informatievlaanderen/vsds/demonstrator/triple/infra/TripleRepositoryImpl.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.Objects; -@Repository +//@Repository public class TripleRepositoryImpl implements TripleRepository { private final GraphDBConfig graphDBConfig; diff --git a/backend/src/main/java/be/informatievlaanderen/vsds/demonstrator/triple/infra/TripleRepositoryRDF4JImpl.java b/backend/src/main/java/be/informatievlaanderen/vsds/demonstrator/triple/infra/TripleRepositoryRDF4JImpl.java new file mode 100644 index 0000000..da29a19 --- /dev/null +++ b/backend/src/main/java/be/informatievlaanderen/vsds/demonstrator/triple/infra/TripleRepositoryRDF4JImpl.java @@ -0,0 +1,70 @@ +package be.informatievlaanderen.vsds.demonstrator.triple.infra; + +import be.informatievlaanderen.vsds.demonstrator.triple.domain.entities.MemberDescription; +import be.informatievlaanderen.vsds.demonstrator.triple.domain.repositories.TripleRepository; +import be.informatievlaanderen.vsds.demonstrator.triple.infra.exceptions.TripleFetchFailedException; +import org.eclipse.rdf4j.common.transaction.IsolationLevels; +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.impl.DynamicModel; +import org.eclipse.rdf4j.model.impl.DynamicModelFactory; +import org.eclipse.rdf4j.query.GraphQueryResult; +import org.eclipse.rdf4j.repository.Repository; +import org.eclipse.rdf4j.repository.RepositoryConnection; +import org.eclipse.rdf4j.repository.config.RepositoryConfig; +import org.eclipse.rdf4j.repository.config.RepositoryImplConfig; +import org.eclipse.rdf4j.repository.manager.RemoteRepositoryManager; +import org.eclipse.rdf4j.repository.manager.RepositoryManager; +import org.eclipse.rdf4j.repository.sail.config.SailRepositoryConfig; +import org.eclipse.rdf4j.sail.memory.config.MemoryStoreConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@org.springframework.stereotype.Repository +public class TripleRepositoryRDF4JImpl implements TripleRepository { + private final GraphDBConfig graphDBConfig; + private RepositoryManager repositoryManager; + private Repository repository; + private static final Logger log = LoggerFactory.getLogger(TripleRepositoryRDF4JImpl.class); + + public TripleRepositoryRDF4JImpl(GraphDBConfig graphDBConfig) { + this.graphDBConfig = graphDBConfig; + String url = graphDBConfig.getUrl().substring(0, graphDBConfig.getUrl().length() - 13); + initRepo(new RemoteRepositoryManager(url)); + } + + protected void initRepo(RepositoryManager manager) { + repositoryManager = manager; + repositoryManager.init(); + try { + if(!repositoryManager.hasRepositoryConfig(graphDBConfig.getRepositoryId())) { + MemoryStoreConfig storeConfig = new MemoryStoreConfig(true); + RepositoryImplConfig repositoryImplConfig = new SailRepositoryConfig(storeConfig); + RepositoryConfig config = new RepositoryConfig(graphDBConfig.getRepositoryId(), repositoryImplConfig); + repositoryManager.addRepositoryConfig(config); + log.info("Created repository with id: " + graphDBConfig.getRepositoryId()); + } + repository = repositoryManager.getRepository(graphDBConfig.getRepositoryId()); + + } catch (Exception e) { + log.error("Could not create repository. Reason: " + e.getMessage()); + } + } + + @Override + public MemberDescription getById(String id) { + try (RepositoryConnection dbConnection = repository.getConnection()) { + dbConnection.setIsolationLevel(IsolationLevels.NONE); + dbConnection.begin(); + + String queryString = "Describe<" + id + ">"; + GraphQueryResult result = dbConnection.prepareGraphQuery(queryString).evaluate(); + Model model = new DynamicModel(new DynamicModelFactory()); + result.forEach(model::add); + dbConnection.commit(); + + return new MemberDescription(id, model); + } catch (Exception e) { + throw new TripleFetchFailedException(id, e); + } + } +} diff --git a/backend/src/test/java/be/informatievlaanderen/vsds/demonstrator/triple/infra/TripleRepositoryRDF4JImplTest.java b/backend/src/test/java/be/informatievlaanderen/vsds/demonstrator/triple/infra/TripleRepositoryRDF4JImplTest.java new file mode 100644 index 0000000..c05ca13 --- /dev/null +++ b/backend/src/test/java/be/informatievlaanderen/vsds/demonstrator/triple/infra/TripleRepositoryRDF4JImplTest.java @@ -0,0 +1,91 @@ +package be.informatievlaanderen.vsds.demonstrator.triple.infra; + +import be.informatievlaanderen.vsds.demonstrator.triple.domain.entities.MemberDescription; +import org.eclipse.rdf4j.repository.RepositoryConnection; +import org.eclipse.rdf4j.repository.config.RepositoryConfig; +import org.eclipse.rdf4j.repository.manager.LocalRepositoryManager; +import org.eclipse.rdf4j.repository.manager.RepositoryManager; +import org.eclipse.rdf4j.repository.sail.config.SailRepositoryConfig; +import org.eclipse.rdf4j.rio.RDFFormat; +import org.eclipse.rdf4j.rio.Rio; +import org.eclipse.rdf4j.sail.memory.config.MemoryStoreConfig; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.springframework.util.ResourceUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.*; + +class TripleRepositoryRDF4JImplTest { + + private static final String MEMBER_ID = "https://private-api.gipod.beta-vlaanderen.be/api/v1/mobility-hindrances/10810464/#ID"; + private static final GraphDBConfig graphDbConfig = new GraphDBConfig(); + private static final String LOCAL_SERVER_URL = "http://localhost:8080/rdf4j-server"; + private static final String LOCAL_REPOSITORY_ID = "test"; + private TripleRepositoryRDF4JImpl repo; + private static RepositoryManager manager; + private static RepositoryConnection connection; + + @TempDir + File dataDir; + + @BeforeEach + public void setUp() { + manager = new LocalRepositoryManager(dataDir); + manager.init(); + manager.addRepositoryConfig( + new RepositoryConfig(LOCAL_REPOSITORY_ID, new SailRepositoryConfig(new MemoryStoreConfig(true)))); + connection = manager.getRepository(LOCAL_REPOSITORY_ID).getConnection(); + + graphDbConfig.setRepositoryId(LOCAL_REPOSITORY_ID); + graphDbConfig.setUrl(LOCAL_SERVER_URL + "/repositories/"); + + repo = new TripleRepositoryRDF4JImpl(graphDbConfig); + repo.initRepo(manager); + } + + @AfterEach + public void tearDown() { + connection.close(); + manager.shutDown(); + } + + @Test + void when_ExistingTriplesAreRequested_then_MemberDescriptionIsExpected() throws IOException { + populateRepository(); + + MemberDescription memberDescription = repo.getById(MEMBER_ID); + + assertEquals(MEMBER_ID, memberDescription.getMemberId()); + assertFalse(memberDescription.getModel().isEmpty()); + } + + @Test + void when_MemberNotPresent_then_EmptyModelIsExpected() { + MemberDescription memberDescription = repo.getById(MEMBER_ID); + + assertEquals(MEMBER_ID, memberDescription.getMemberId()); + assertTrue(memberDescription.getModel().isEmpty()); + } + + void populateRepository() throws IOException { + var model = Rio.parse(readDataFromFile(), "", RDFFormat.NQUADS); + connection.begin(); + connection.add(model); + connection.commit(); + connection.close(); + } + + private InputStream readDataFromFile() throws IOException { + Path path = ResourceUtils.getFile("classpath:members/mobility-hindrance.nq").toPath(); + return Files.newInputStream(path); + } + +} \ No newline at end of file