View Javadoc
1   package de.dlr.shepard.context.semantic;
2   
3   import com.fasterxml.jackson.core.JsonProcessingException;
4   import com.fasterxml.jackson.databind.JsonNode;
5   import com.fasterxml.jackson.databind.ObjectMapper;
6   import io.quarkus.logging.Log;
7   import jakarta.ws.rs.ProcessingException;
8   import jakarta.ws.rs.client.Client;
9   import jakarta.ws.rs.client.ClientBuilder;
10  import jakarta.ws.rs.client.Invocation;
11  import jakarta.ws.rs.core.MediaType;
12  import java.util.Collections;
13  import java.util.HashMap;
14  import java.util.Map;
15  import java.util.Optional;
16  
17  public class SparqlConnector implements ISemanticRepositoryConnector {
18  
19    private static final String SELECT_TEMPLATE =
20      """
21      PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
22  
23      SELECT DISTINCT ?o WHERE {
24          ?s rdfs:label ?o .
25          FILTER ( ?s = <%s> )
26      }""";
27  
28    private static final String ASK_TEMPLATE = "ASK { ?x ?y ?z }";
29  
30    private final String endpoint;
31    private final ObjectMapper mapper = new ObjectMapper();
32    private Client client = ClientBuilder.newClient();
33  
34    public SparqlConnector(String endpoint) {
35      this.endpoint = endpoint;
36    }
37  
38    @Override
39    public boolean healthCheck() {
40      var invocation = client
41        .target(endpoint)
42        .queryParam("query", ASK_TEMPLATE)
43        .request(MediaType.APPLICATION_JSON)
44        .buildGet();
45      String requestResult = request(invocation);
46      client.close();
47      return parseJson(requestResult).map(t -> t.get("boolean")).map(JsonNode::asBoolean).orElse(false);
48    }
49  
50    @Override
51    public Map<String, String> getTerm(String termIri) {
52      var requestResult = requestTerm(termIri);
53      if (requestResult == null || requestResult.isBlank()) {
54        Log.error("Could not retrieve request result");
55        return Collections.emptyMap();
56      }
57  
58      return parseResult(requestResult);
59    }
60  
61    private String requestTerm(String termIri) {
62      var query = String.format(SELECT_TEMPLATE, termIri);
63      var invocation = client.target(endpoint).queryParam("query", query).request(MediaType.APPLICATION_JSON).buildGet();
64      String responseEntity = request(invocation);
65      client.close();
66      return responseEntity;
67    }
68  
69    private Map<String, String> parseResult(String requestResult) {
70      var bindings = parseJson(requestResult).map(t -> t.get("results")).map(r -> r.get("bindings"));
71  
72      if (bindings.isEmpty()) return Collections.emptyMap();
73  
74      var result = new HashMap<String, String>();
75      for (var binding : bindings.get()) {
76        var oBinding = Optional.of(binding);
77        var object = oBinding.map(b -> b.get("o")).map(p -> p.get("value")).map(JsonNode::asText).orElse("");
78        var language = oBinding.map(b -> b.get("o")).map(p -> p.get("xml:lang")).map(JsonNode::asText).orElse("");
79        if (!object.isBlank()) result.put(language, object);
80      }
81      return result;
82    }
83  
84    private Optional<JsonNode> parseJson(String string) {
85      JsonNode tree;
86      try {
87        tree = mapper.readTree(string);
88      } catch (JsonProcessingException e) {
89        return Optional.empty();
90      }
91      return Optional.of(tree);
92    }
93  
94    /**
95     * You have to close the client yourself afterwards
96     *
97     * @param invocation
98     * @return Response as String or null
99     */
100   private String request(Invocation invocation) {
101     String responseEntity;
102     try {
103       var response = invocation.invoke();
104       responseEntity = response.readEntity(String.class);
105     } catch (ProcessingException e) {
106       Log.error("Could not execute request");
107       return null;
108     }
109     return responseEntity;
110   }
111 }