Skip to content
This repository has been archived by the owner on Mar 7, 2024. It is now read-only.

Commit

Permalink
feat: use name spaces in knowledge graph (#32)
Browse files Browse the repository at this point in the history
* feat: small improvements

* feat: use name spaces in knowledge graph

* fix: broken test

* feat: blue bike popup improved

* feat: small improvements and fixes
  • Loading branch information
jobulcke authored Oct 20, 2023
1 parent 1c87bd2 commit bd47cca
Show file tree
Hide file tree
Showing 41 changed files with 746 additions and 416 deletions.
14 changes: 11 additions & 3 deletions backend/examples/example-application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,22 @@ ldes:
member-type: "https://data.vlaanderen.be/ns/mobiliteit#Mobiliteitshinder"
timestamp-path: "http://www.w3.org/ns/prov#generatedAtTime"
property-predicates:
startTime: "http://data.europa.eu/m8g/startTime"
endTime: "http://data.europa.eu/m8g/endTime"
starttime: "http://data.europa.eu/m8g/startTime"
endtime: "http://data.europa.eu/m8g/endTime"
verkeersmeting:
member-type: "https://data.vlaanderen.be/ns/verkeersmetingen#Verkeersmeting"
timestamp-path: "http://www.w3.org/ns/prov#generatedAtTime"
property-predicates:
fullName: "http://custom/meetpunt#VolledigeNaam"
fullname: "http://custom/meetpunt#VolledigeNaam"
countObservationResult: "http://def.isotc211.org/iso19156/2011/CountObservation#OM_CountObservation.result"
bluebikes:
member-type: "https://w3id.org/gbfs#Station"
timestamp-path: "http://www.w3.org/ns/prov#generatedAtTime"
property-predicates:
fullname: "http://schema.org/name"
capacity: "https://blue-bike.be/ns#capacity"
available: "https://w3id.org/gbfs#bikes_available"
used: "https://w3id.org/gbfs#bikes_in_use"
graphdb:
url: "http://localhost:8080/rdf4j-server/repositories/"
repositoryId: "test"
Expand Down
12 changes: 12 additions & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
<maven-failsafe-plugin.version>3.0.0-M7</maven-failsafe-plugin.version>
<jetbrains-annotations.version>24.0.1</jetbrains-annotations.version>

<!-- SPRING BOOT -->
<spring-boot.version>3.1.2</spring-boot.version>
Expand Down Expand Up @@ -132,6 +133,12 @@
<version>1.16.1</version>
</dependency>

<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>${jetbrains-annotations.version}</version>
</dependency>

<!-- TESTING -->
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down Expand Up @@ -178,6 +185,11 @@
<version>${wiremock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.2</version>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

@Repository
public class MemberRepositoryImpl implements MemberRepository {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.apache.jena.rdf.model.Model;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFParser;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
Expand Down Expand Up @@ -31,7 +32,7 @@ protected boolean supports(Class<?> clazz) {
}

@Override
protected Model readInternal(Class<? extends Model> clazz, HttpInputMessage inputMessage)
protected Model readInternal(@NotNull Class<? extends Model> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
MediaType contentType = Objects.requireNonNull(inputMessage.getHeaders().getContentType());
Lang lang =
Expand All @@ -42,7 +43,7 @@ protected Model readInternal(Class<? extends Model> clazz, HttpInputMessage inpu
}

@Override
protected void writeInternal(Model model, HttpOutputMessage outputMessage)
protected void writeInternal(@NotNull Model model, @NotNull HttpOutputMessage outputMessage)
throws UnsupportedOperationException, HttpMessageNotWritableException {
throw new UnsupportedOperationException();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package be.informatievlaanderen.vsds.demonstrator.triple.application.services;

import be.informatievlaanderen.vsds.demonstrator.triple.application.valueobjects.Triple;
import be.informatievlaanderen.vsds.demonstrator.triple.domain.valueobjects.Triple;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package be.informatievlaanderen.vsds.demonstrator.triple.application.services;

import be.informatievlaanderen.vsds.demonstrator.triple.application.valueobjects.Triple;
import be.informatievlaanderen.vsds.demonstrator.triple.domain.valueobjects.Triple;
import be.informatievlaanderen.vsds.demonstrator.triple.domain.repositories.TripleRepository;
import org.springframework.stereotype.Service;

Expand All @@ -16,9 +16,6 @@ public TripleServiceImpl(TripleRepository repository) {

@Override
public List<Triple> getTriplesById(String id) {
return repository.getById(id).getModel().stream()
.map(statement -> new Triple(statement.getSubject().stringValue(), statement.getPredicate().stringValue(), statement.getObject().stringValue()))
.toList();

return repository.getById(id);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package be.informatievlaanderen.vsds.demonstrator.triple.domain.repositories;

import be.informatievlaanderen.vsds.demonstrator.triple.domain.entities.MemberDescription;
import be.informatievlaanderen.vsds.demonstrator.triple.domain.valueobjects.Triple;

import java.util.List;

public interface TripleRepository {
MemberDescription getById(String id);
List<Triple> getById(String id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package be.informatievlaanderen.vsds.demonstrator.triple.domain.services;

import be.informatievlaanderen.vsds.demonstrator.triple.domain.valueobjects.Node;
import be.informatievlaanderen.vsds.demonstrator.triple.domain.valueobjects.Triple;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.Value;
import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

public class TriplesFactory {
private static final Map<String, String> COMMON_NAMESPACES = Map.ofEntries(
Map.entry("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"),
Map.entry("rdfs", "http://www.w3.org/2000/01/rdf-schema#"),
Map.entry("owl", "http://www.w3.org/2002/07/owl#"),
Map.entry("xsd", "http://www.w3.org/2001/XMLSchema#"),
Map.entry("dct", "http://purl.org/dc/terms/"),
Map.entry("adms", "http://www.w3.org/ns/adms#"),
Map.entry("prov", "http://www.w3.org/ns/prov#"),
Map.entry("purl", "http://purl.org/dc/elements/1.1/"),
Map.entry("foaf", "http://xmlns.com/foaf/0.1/"),
Map.entry("org", "http://www.w3.org/ns/org#"),
Map.entry("legal", "http://www.w3.org/ns/legal#"),
Map.entry("m8g", "http://data.europa.eu/m8g/"),
Map.entry("locn", "http://www.w3.org/ns/locn#"),
Map.entry("ldes", "http://w3id.org/ldes#"),
Map.entry("tree", "https://w3id.org/tree#"),
Map.entry("sh", "http://www.w3.org/ns/shacl#"),
Map.entry("skos", "http://www.w3.org/2004/02/skos/core#"),
Map.entry("schema", "http://schema.org/")
);
private static final String VALID_PREFIX_REGEX = "^[a-zA-Z_][\\w.-]*$"; // NCName regex
private final Stream<Statement> statementStream;
private final Map<String, String> namespaces;

private TriplesFactory(@NotNull Model model) {
this.statementStream = model.stream();
namespaces = new HashMap<>(COMMON_NAMESPACES);

}

/**
* Assigns the namespaces to this factory
*
* @param namespaces Map with namespace prefix as key and the according name as value
* @return the factory whereon this method is called
*/
public TriplesFactory withNamespaces(@NotNull Map<String, String> namespaces) {
this.namespaces.putAll(namespaces);

return this;
}

/**
* Initialize an instance of TriplesFactory with the specified Model
*
* @param model Model with which the initialization needs to be done
* @return new instance of TriplesFactory
*/
public static TriplesFactory fromModel(@NotNull Model model) {
return new TriplesFactory(model);
}

/**
* Converts all the statements of the model in this factory to a list of triples
*
* @return the list of triples
*/
public List<Triple> getTriples() {
return statementStream
.map(statement -> new Triple(valueToNode(statement.getSubject()), valueToNode(statement.getPredicate()), valueToNode(statement.getObject())))
.toList();
}

private Node valueToNode(@NotNull Value value) {
if (value.isIRI()) {
String name = ((IRI) value).getNamespace();
return getNamespace(name).or(() -> createNamespace(name))
.map(namespace -> new Node(value.stringValue(), namespace))
.orElseGet(() -> new Node(value.stringValue()));
}
return new Node(value.stringValue());
}

private Optional<Map.Entry<String, String>> getNamespace(@NotNull String name) {
return namespaces.entrySet().stream().filter(entry -> entry.getValue().equals(name)).findFirst();
}

private Optional<Map.Entry<String, String>> createNamespace(@NotNull String name) {
Optional<String> prefixOptional = name.contains("#")
? createNamespacePrefix(name)
: createNonNamespacePrefix(name);

return prefixOptional
.filter(prefix -> prefix.matches(VALID_PREFIX_REGEX))
.map(prefix -> Map.entry(prefix, name));
}

private Optional<String> createNamespacePrefix(@NotNull String name) {
int lastIndexOfHashtag = name.lastIndexOf('#');
int lastIndexOfSlash = name.lastIndexOf('/');
return Optional.of(name.substring(lastIndexOfSlash + 1, lastIndexOfHashtag));

}

private Optional<String> createNonNamespacePrefix(@NotNull String name) {
String[] nameSplit = name.split("/");
int index = nameSplit.length - 1;
return Optional.ofNullable(nameSplit[index]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package be.informatievlaanderen.vsds.demonstrator.triple.domain.valueobjects;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Map;
import java.util.Objects;

public class Node {
private final String value;
private Map.Entry<String, String> namespace;

public Node(@NotNull String value) {
this.value = value;
}

public Node(@NotNull String value, @Nullable Map.Entry<String, String> namespace) {
this.value = value;
this.namespace = namespace;
}

public String getValue() {
return value;
}

public String getPrefixedValue() {
if (namespace != null) {
return value.replace(namespace.getValue(), "%s:".formatted(namespace.getKey()));
}
return value;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Node node = (Node) o;

if (!value.equals(node.value)) return false;
return Objects.equals(namespace, node.namespace);
}

@Override
public int hashCode() {
int result = value.hashCode();
result = 31 * result + (namespace != null ? namespace.hashCode() : 0);
return result;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package be.informatievlaanderen.vsds.demonstrator.triple.application.valueobjects;
package be.informatievlaanderen.vsds.demonstrator.triple.domain.valueobjects;

import org.jetbrains.annotations.NotNull;

public class Triple {
private final String subject;
private final String predicate;
private final String object;
private final Node subject;
private final Node predicate;
private final Node object;

public Triple(String subject, String predicate, String object) {
public Triple(@NotNull Node subject, @NotNull Node predicate, @NotNull Node object) {
this.subject = subject;
this.predicate = predicate;
this.object = object;
Expand All @@ -31,15 +33,24 @@ public int hashCode() {
return result;
}

public String getSubject() {
@Override
public String toString() {
return "Triple{" +
"subject=" + subject.getValue() +
", predicate=" + predicate.getValue() +
", object=" + object.getValue() +
'}';
}

public Node getSubject() {
return subject;
}

public String getPredicate() {
public Node getPredicate() {
return predicate;
}

public String getObject() {
public Node getObject() {
return object;
}
}
Loading

0 comments on commit bd47cca

Please sign in to comment.