• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

knowledgepixels / nanopub-query / 25736956287

12 May 2026 01:16PM UTC coverage: 58.609% (-0.2%) from 58.837%
25736956287

push

github

tkuhn
feat: expose Nanopub-Query-Version response header

Mirrors the Nanopub-Registry-Version header so clients can detect
which build of nanopub-query is serving them. Version is read at
runtime from a filtered version.properties resource.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

496 of 922 branches covered (53.8%)

Branch coverage included in aggregate %.

1308 of 2156 relevant lines covered (60.67%)

9.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.79
src/main/java/com/knowledgepixels/query/Utils.java
1
package com.knowledgepixels.query;
2

3
import java.io.IOException;
4
import java.io.InputStream;
5
import java.nio.charset.StandardCharsets;
6
import java.util.ArrayList;
7
import java.util.HashMap;
8
import java.util.List;
9
import java.util.Map;
10
import java.util.Properties;
11

12
import org.apache.commons.exec.environment.EnvironmentUtils;
13
import org.apache.commons.lang3.StringUtils;
14
import org.apache.http.client.config.CookieSpecs;
15
import org.apache.http.client.config.RequestConfig;
16
import org.eclipse.rdf4j.model.IRI;
17
import org.eclipse.rdf4j.model.Value;
18
import org.eclipse.rdf4j.model.ValueFactory;
19
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
20
import org.eclipse.rdf4j.query.BindingSet;
21
import org.eclipse.rdf4j.query.QueryLanguage;
22
import org.eclipse.rdf4j.query.TupleQuery;
23
import org.eclipse.rdf4j.query.TupleQueryResult;
24
import org.eclipse.rdf4j.repository.RepositoryConnection;
25
import org.nanopub.vocabulary.NPA;
26
import org.slf4j.Logger;
27
import org.slf4j.LoggerFactory;
28

29
import com.google.common.hash.Hashing;
30

31
/**
32
 * Utils class for Nanopub Registry.
33
 */
34
public class Utils {
35

36
    private Utils() {
37
    }  // no instances allowed
38

39
    private static final ValueFactory vf = SimpleValueFactory.getInstance();
6✔
40

41
    private static final Logger log = LoggerFactory.getLogger(Utils.class);
12✔
42

43
    private static Map<String, Value> hashToObjMap;
44

45
    /**
46
     * Returns reverse hashing map.
47
     *
48
     * @return Map from hashes to their original objects
49
     */
50
    static Map<String, Value> getHashToObjectMap() {
51
        if (hashToObjMap == null) {
6✔
52
            hashToObjMap = new HashMap<>();
12✔
53
            try (RepositoryConnection conn = TripleStore.get().getAdminRepoConnection()) {
9✔
54
                TupleQuery query = conn.prepareTupleQuery(QueryLanguage.SPARQL, "SELECT * { graph ?g { ?s ?p ?o } }");
15✔
55
                query.setBinding("g", NPA.GRAPH);
12✔
56
                query.setBinding("p", NPA.IS_HASH_OF);
12✔
57
                try (TupleQueryResult r = query.evaluate()) {
9✔
58
                    while (r.hasNext()) {
9✔
59
                        BindingSet b = r.next();
12✔
60
                        String hash = b.getBinding("s").getValue().stringValue();
18✔
61
                        hash = StringUtils.replace(hash, NPA.HASH.toString(), "");
18✔
62
                        hashToObjMap.put(hash, b.getBinding("o").getValue());
24✔
63
                    }
3✔
64
                }
65
            }
66
        }
67
        return hashToObjMap;
6✔
68
    }
69

70
    /**
71
     * Returns the original object for the given hash value.
72
     *
73
     * @param hash The hash value
74
     * @return The original object
75
     */
76
    public static Value getObjectForHash(String hash) {
77
        return getHashToObjectMap().get(hash);
15✔
78
    }
79

80
    /**
81
     * Creates a hash value for the object and remembers it.
82
     *
83
     * @param obj Object to be hashed
84
     * @return hash value
85
     */
86
    public static String createHash(Object obj) {
87
        String hash = Hashing.sha256().hashString(obj.toString(), StandardCharsets.UTF_8).toString();
21✔
88

89
        if (!getHashToObjectMap().containsKey(hash)) {
12✔
90
            Value objV = getValue(obj);
9✔
91
            try (RepositoryConnection conn = TripleStore.get().getAdminRepoConnection()) {
9✔
92
                conn.add(vf.createStatement(vf.createIRI(NPA.HASH + hash), NPA.IS_HASH_OF, objV, NPA.GRAPH));
45✔
93
            }
94
            getHashToObjectMap().put(hash, objV);
15✔
95
        }
96
        return hash;
6✔
97
    }
98

99
    /**
100
     * Returns the object as a Value object.
101
     *
102
     * @param obj Input object
103
     * @return A Value object with the string content of the input object
104
     */
105
    static Value getValue(Object obj) {
106
        if (obj instanceof Value) {
9✔
107
            return (Value) obj;
9✔
108
        } else {
109
            return vf.createLiteral(obj.toString());
15✔
110
        }
111
    }
112

113
    /**
114
     * Returns a short "name" for the given public key
115
     *
116
     * @param pubkey Public key string
117
     * @return Short "name"
118
     */
119
    public static String getShortPubkeyName(String pubkey) {
120
        return pubkey.replaceFirst("^(.).{39}(.{5}).*$", "$1..$2..");
15✔
121
    }
122

123
    /**
124
     * Executes a query on the given connection to return the first objects matching the input.
125
     *
126
     * @param conn  The repository connection
127
     * @param graph Graph (=context) IRI
128
     * @param subj  Subject IRI
129
     * @param pred  Predicate IRI
130
     * @return the first object to match the pattern
131
     */
132
    public static Value getObjectForPattern(RepositoryConnection conn, IRI graph, IRI subj, IRI pred) {
133
        TupleQueryResult r = conn.prepareTupleQuery(QueryLanguage.SPARQL, "SELECT * { graph <" + graph.stringValue() + "> { <" + subj.stringValue() + "> <" + pred.stringValue() + "> ?o } }").evaluate();
36✔
134
        try (r) {
6✔
135
            if (!r.hasNext()) return null;
21✔
136
            return r.next().getBinding("o").getValue();
27✔
137
        }
12!
138
    }
139

140
    /**
141
     * Executes a query on the given connection to return all objects matching the input.
142
     *
143
     * @param conn  The repository connection
144
     * @param graph Graph (=context) IRI
145
     * @param subj  Subject IRI
146
     * @param pred  Predicate IRI
147
     * @return a list of all objects matching the pattern
148
     */
149
    public static List<Value> getObjectsForPattern(RepositoryConnection conn, IRI graph, IRI subj, IRI pred) {
150
        List<Value> values = new ArrayList<>();
12✔
151
        TupleQueryResult r = conn.prepareTupleQuery(QueryLanguage.SPARQL, "SELECT * { graph <" + graph.stringValue() + "> { <" + subj.stringValue() + "> <" + pred.stringValue() + "> ?o } }").evaluate();
36✔
152
        try (r) {
6✔
153
            while (r.hasNext()) {
9✔
154
                values.add(r.next().getBinding("o").getValue());
30✔
155
            }
156
            return values;
12✔
157
        }
158
    }
159

160
    /**
161
     * Returns the system environment variable content for the given environment variable name.
162
     *
163
     * @param envVarName   environment variable name
164
     * @param defaultValue default value if not found
165
     * @return environment variable value
166
     */
167
    public static String getEnvString(String envVarName, String defaultValue) {
168
        try {
169
            String s = EnvironmentUtils.getProcEnvironment().get(envVarName);
15✔
170
            if (s != null && !s.isEmpty()) {
15✔
171
                return s;
6✔
172
            }
173
        } catch (Exception ex) {
3✔
174
            log.info("Could not get environment variable", ex);
12✔
175
        }
3✔
176
        return defaultValue;
6✔
177
    }
178

179
    /**
180
     * Returns the system environment variable content as an integer for the given environment variable name.
181
     *
182
     * @param envVarName   environment variable name
183
     * @param defaultValue default value if not found
184
     * @return environment variable value interpreted as an integer
185
     */
186
    public static int getEnvInt(String envVarName, int defaultValue) {
187
        try {
188
            String s = getEnvString(envVarName, null);
12✔
189
            if (s != null) {
6✔
190
                return Integer.parseInt(s);
9✔
191
            }
192
        } catch (Exception ex) {
3✔
193
            log.info("Could not get environment variable", ex);
12✔
194
        }
3✔
195
        return defaultValue;
6✔
196
    }
197

198
    private static String version;
199

200
    /**
201
     * Returns the application version, read from the filtered version.properties resource.
202
     *
203
     * @return the project version, or "unknown" if it cannot be read
204
     */
205
    public static String getVersion() {
206
        String v = version;
6✔
207
        if (v != null) {
6✔
208
            return v;
6✔
209
        }
210
        Properties p = new Properties();
12✔
211
        try (InputStream in = Utils.class.getResourceAsStream("/version.properties")) {
12✔
212
            if (in != null) {
6!
213
                p.load(in);
9✔
214
            }
215
        } catch (IOException ex) {
×
216
            log.warn("Could not read version.properties", ex);
×
217
        }
3✔
218
        v = p.getProperty("version", "unknown");
15✔
219
        version = v;
6✔
220
        return v;
6✔
221
    }
222

223
    /**
224
     * Default query to be shown in YASGUI client.
225
     */
226
    public static final String defaultQuery = """
227
            prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
228
            prefix dct: <http://purl.org/dc/terms/>
229
            prefix np: <http://www.nanopub.org/nschema#>
230
            prefix npa: <http://purl.org/nanopub/admin/>
231
            prefix npx: <http://purl.org/nanopub/x/>
232
            
233
            select * where {
234
            ## Info about this repo:
235
              npa:thisRepo ?pred ?obj .
236
            ## Search for nanopublications:
237
            # graph npa:graph {
238
            #   ?np npa:hasValidSignatureForPublicKey ?pubkey .
239
            #   filter not exists { ?npx npx:invalidates ?np ; npa:hasValidSignatureForPublicKey ?pubkey . }
240
            #   ?np dct:created ?date .
241
            #   ?np np:hasAssertion ?a .
242
            #   optional { ?np rdfs:label ?label }
243
            # }
244
            } limit 10""";
245

246
    /**
247
     * Get the HTTP request config for fetching nanopublications.
248
     *
249
     * @return the HTTP client
250
     */
251
    static RequestConfig getHttpRequestConfig() {
252
        return RequestConfig.custom()
12✔
253
                .setConnectTimeout(getEnvInt("NANOPUB_QUERY_FETCHING_CONNECT_TIMEOUT", 10000))
12✔
254
                .setConnectionRequestTimeout(getEnvInt("NANOPUB_QUERY_FETCHING_CONNECTION_REQUEST_TIMEOUT", 1000))
12✔
255
                .setSocketTimeout(getEnvInt("NANOPUB_QUERY_FETCHING_SOCKET_TIMEOUT", 10000))
9✔
256
                .setCookieSpec(CookieSpecs.IGNORE_COOKIES).build();
6✔
257
    }
258

259
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc