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

knowledgepixels / nanodash / 17319343703

29 Aug 2025 08:53AM UTC coverage: 12.007% (-0.3%) from 12.355%
17319343703

push

github

tkuhn
Fix forcedGet(...) also catching RuntimeExceptions

330 of 3844 branches covered (8.58%)

Branch coverage included in aggregate %.

949 of 6808 relevant lines covered (13.94%)

0.61 hits per line

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

79.61
src/main/java/com/knowledgepixels/nanodash/QueryApiAccess.java
1
package com.knowledgepixels.nanodash;
2

3
import org.apache.commons.lang3.tuple.Pair;
4
import org.eclipse.rdf4j.model.IRI;
5
import org.nanopub.extra.services.ApiResponse;
6
import org.nanopub.extra.services.FailedApiCallException;
7
import org.nanopub.extra.services.QueryAccess;
8

9
import java.util.HashMap;
10
import java.util.Map;
11

12
/**
13
 * Utility class for accessing and managing API queries.
14
 * Provides methods to retrieve query results, manage query IDs, and fetch the latest versions of nanopublications.
15
 */
16
public class QueryApiAccess {
17

18
    private QueryApiAccess() {
19
    }  // no instances allowed
20

21
    private static Map<String, String> queryIds = new HashMap<>();
4✔
22

23
    private static Map<String, Pair<Long, String>> latestVersionMap = new HashMap<>();
4✔
24

25
    private static final String queryIriPattern = "^(.*[^A-Za-z0-9-_])(RA[A-Za-z0-9-_]{43})[/#]([^/#]+)$";
26

27
    static {
28
        // TODO Load this dynamically somehow at some point:
29
        load("RAe-oA5eSmkCXCALZ99-0k4imnlI74KPqURfhHOmnzo6A/get-latest-nanopubs-from-pubkeys");
2✔
30
        load("RAuy4N1h4vZ1wgBUMvTiWw2y_Y0_5oFYRTwdq-xj2qqNM/get-latest-nanopubs-from-userid");
2✔
31
        load("RAZbyFSenuKSRMLGlRfrbeu6vQ6g2IEECYZ2zSGcIBIhQ/get-accepted-nanopubs-by-author");
2✔
32
        load("RAiCBvPL2hRGzI8g5L68O-C9yEXryC_vG35GdEm5jtH_s/get-user-stats-from-pubkeys");  // Deactivated for now...
2✔
33
        load("RA3U23LL3xbNwsu92fAqsKb0kagOud4f9TlRQq3evNJck/get-user-stats-from-userid");  // Deactivated for now...
2✔
34
        load("RAcNvmEiUNUb2a7O4fwRvy2x2BCN640AC880fTzFworr8/get-top-creators-last30d");
2✔
35
        load("RAmhy4KQe6I80bA2Da4JziYyKBoXuXIzqo57GDSVgLfDg/get-top-authors");
2✔
36
        load("RA7oUCHG8TEjVQpGTUN5sfu3_IQmza3aSBSCxfJdBc3Rs/get-most-recent-nanopubs");
2✔
37
        load("RA52cg2OzJucmpCb7KSKTgfPV5HKIjsFcmww_rxb7v5zU/get-latest-accepted");
2✔
38
        load("RAPGhXDRzeGu-Qk0AkjleEtxMxqAvJ-dZn7985gzAbyhs/get-publisher-version");
2✔
39
        load("RAvL7pe2ppsfq4mVWTdJjssYGsjrmliNd_sZO2ytLvg1Y/get-most-used-templates-last30d");
2✔
40
        load("RANn4Mu8r8bqJA9KJMGXTQAEGAEvtNKGFsuhRIC6BRIOo/get-latest-nanopubs-by-type");
2✔
41
        load("RAiRsB2YywxjsBMkVRTREJBooXhf2ZOHoUs5lxciEl37I/get-latest-version-of-np");
2✔
42
        load("RA0aZxyh_I0rCJyBepXOWC2tGdI5YYHORFCC-qBR8xHZA/get-all-user-intros");
2✔
43
        load("RA-tlMmQA7iT2wR2aS3PlONrepX7vdXbkzeWluea7AECg/get-suggested-templates-to-get-started");
2✔
44
        load("RAtIndAeo8zYnEvTjFRaHD2AlenvkJHlw6P52JWR_l5dQ/get-type-overview-last-12-months");
2✔
45
        load("RAn3agwsH2yk-8132RJApGYxdPSHHCXDAIYiCaSBBo6tg/get-approved-nanopubs");
2✔
46
        load("RAz1ogtMxSTKSOYwHAfD5M3Y-vd1vd46OZta_vvbqh8kY/find-uri-references");
2✔
47
        load("RAE35dYJQlpnqim7VeKuu07E9I1LQUZpkdYQR4RvU3KMU/get-nanopubs-by-type");
2✔
48
        load("RALZXWg5lZoJoQ0VHL5mpDgNxYpqU6FoDLWGp4rs8A6b8/get-introducing-nanopub");
2✔
49
        load("RAWruhiSmyzgZhVRs8QY8YQPAgHzTfl7anxII1de-yaCs/fulltext-search-on-labels");
2✔
50
        load("RAVEmFh3d6qonTFQ5S9SVqXZh0prrH1YLhSSs0dJvyvpM/find-things");
2✔
51
        load("RAjt1H9rCSr6A9VGzlhye00zPdH69JdGc3kd_2VjDmzVg/get-instances");
2✔
52
        load("RAH06iUwnvj_pRARY15ayJAY5tuJau3rCvHhPPhe49fVI/get-classes-for-thing");
2✔
53
        load("RAJStXEm1wZcg34ZLPqe00VPSzIVCwC2rrxdj_JR8v5DY/find-referencing-nanopubs");  // not yet used...
2✔
54
        load("RAtftxAXJubB4rlm9fOvvHNVIkXvWQLC6Ag_MiV7HL0ow/get-labels-for-thing");  // not yet used...
2✔
55
        load("RARtWHRzNY5hh31X2VB5eOCJAdp9Cjv4CakA0Idqz69MI/get-templates-with-uri");
2✔
56
        load("RAfiHseHSs9ED7zbXD-OotwblOsT-AfgZ5_2RUeQkBdFc/get-introducing-np");
2✔
57
        load("RAWH0fe1RCpoOgaJE1B2qfTzzdTiBUUK7iIk6l7Zll9mg/get-newer-versions-of-np");
2✔
58
        load("RAQqjXQYlxYQeI4Y3UQy9OrD5Jx1E3PJ8KwKKQlWbiYSw/get-queries");
2✔
59
        load("RAzXDzCHoZmJITgYYquLwDDkSyNf3eKKQz9NfQPYB1cyE/get-latest-thing-nanopub");
2✔
60
        load("RAnpimW7SPwaum2fefdS6_jpzYxcTRGjE-pmgNTL_BBJU/get-projects");
2✔
61
        load("RAJmZoM0xCGE8OL6EgmQBOd1M58ggNkwZ0IUqHOAPRfvE/get-parts");
2✔
62
        load("RA6bgrU3Ezfg5VAiLru0BFYHaSj6vZU6jJTscxNl8Wqvc/get-assertion-templates");
2✔
63
        load("RA4bt3MQRnEPC2nSsdbCJc74wT-e1w68dSCpYVyvG0274/get-provenance-templates");
2✔
64
        load("RAMcdiJpvvk8424AJIH1jsDUQVcPYOLRw0DNnZt_ND_LQ/get-pubinfo-templates");
2✔
65
    }
1✔
66

67
    /**
68
     * Loads a query ID into the queryIds map.
69
     *
70
     * @param queryId The query ID to load.
71
     */
72
    static void load(String queryId) {
73
        queryIds.put(queryId.substring(46), queryId);
7✔
74
    }
1✔
75

76
    /**
77
     * Forces the retrieval of an API response for a given query name and parameters.
78
     * Retries until a valid response is received.
79
     *
80
     * @param queryName The name of the query.
81
     * @return The API response.
82
     */
83
    public static ApiResponse forcedGet(String queryName) {
84
        return forcedGet(queryName, new HashMap<>());
6✔
85
    }
86

87
    /**
88
     * Forces the retrieval of an API response for a given query name and parameters.
89
     * Retries until a valid response is received.
90
     *
91
     * @param queryName The name of the query.
92
     * @param params    The parameters for the query.
93
     * @return The API response.
94
     */
95
    public static ApiResponse forcedGet(String queryName, Map<String, String> params) {
96
        while (true) {
97
            ApiResponse resp = null;
2✔
98
            try {
99
                resp = QueryApiAccess.get(queryName, params);
4✔
100
            } catch (Exception ex) {
×
101
                // TODO We should be more specific about which exceptions we catch here
102
                //      and generally improve this, as this could hang forever.
103
                ex.printStackTrace();
×
104
            }
1✔
105
            if (resp != null) return resp;
4✔
106
            try {
107
                Thread.sleep(100);
2✔
108
            } catch (InterruptedException ex) {
×
109
                ex.printStackTrace();
×
110
            }
1✔
111
        }
1✔
112
    }
113

114
    /**
115
     * Retrieves an API response for a given query name.
116
     *
117
     * @param queryName The name of the query.
118
     * @return The API response.
119
     * @throws org.nanopub.extra.services.FailedApiCallException If the API call fails.
120
     */
121
    public static ApiResponse get(String queryName) throws FailedApiCallException {
122
        return get(queryName, new HashMap<>());
6✔
123
    }
124

125
    /**
126
     * Retrieves an API response for a given query name and a single parameter.
127
     *
128
     * @param queryName  The name of the query.
129
     * @param paramKey   The key of the parameter.
130
     * @param paramValue The value of the parameter.
131
     * @return The API response.
132
     * @throws org.nanopub.extra.services.FailedApiCallException If the API call fails.
133
     */
134
    public static ApiResponse get(String queryName, String paramKey, String paramValue) throws FailedApiCallException {
135
        Map<String, String> params = new HashMap<>();
×
136
        params.put(paramKey, paramValue);
×
137
        return get(queryName, params);
×
138
    }
139

140
    /**
141
     * Retrieves an API response for a given query name and parameters.
142
     *
143
     * @param queryName The name of the query.
144
     * @param params    The parameters for the query.
145
     * @return The API response.
146
     * @throws org.nanopub.extra.services.FailedApiCallException If the API call fails.
147
     */
148
    public static ApiResponse get(String queryName, Map<String, String> params) throws FailedApiCallException {
149
        String queryId;
150
        if (queryName.matches("^RA[A-Za-z0-9-_]{43}/.*$")) {
4✔
151
            queryId = queryName;
3✔
152
        } else if (queryIds.containsKey(queryName)) {
4✔
153
            queryId = queryIds.get(queryName);
6✔
154
        } else {
155
            throw new IllegalArgumentException("Query name not known: " + queryName);
6✔
156
        }
157
        return QueryAccess.get(queryId, params);
4✔
158
    }
159

160
    /**
161
     * Retrieves the latest version ID of a given nanopublication.
162
     *
163
     * @param nanopubId The ID of the nanopublication.
164
     * @return The latest version ID.
165
     */
166
    public static String getLatestVersionId(String nanopubId) {
167
        long currentTime = System.currentTimeMillis();
2✔
168
        if (!latestVersionMap.containsKey(nanopubId) || currentTime - latestVersionMap.get(nanopubId).getLeft() > 1000 * 60) {
4!
169
            // Re-fetch if existing value is older than 1 minute
170
            Map<String, String> params = new HashMap<>();
4✔
171
            params.put("np", nanopubId);
5✔
172
            try {
173
                ApiResponse r = get("get-latest-version-of-np", params);
4✔
174
                if (r.getData().size() != 1) return nanopubId;
5!
175
                String l = r.getData().get(0).get("latest");
8✔
176
                latestVersionMap.put(nanopubId, Pair.of(currentTime, l));
8✔
177
            } catch (Exception ex) {
×
178
                ex.printStackTrace();
×
179
                return nanopubId;
×
180
            }
1✔
181
        }
182
        return latestVersionMap.get(nanopubId).getRight();
7✔
183
    }
184

185
    /**
186
     * Extracts the query ID from a given query IRI.
187
     *
188
     * @param queryIri The query IRI.
189
     * @return The query ID, or null if the IRI is invalid.
190
     */
191
    public static String getQueryId(IRI queryIri) {
192
        if (queryIri == null) return null;
×
193
        if (!queryIri.stringValue().matches(queryIriPattern)) return null;
×
194
        return queryIri.stringValue().replaceFirst(queryIriPattern, "$2/$3");
×
195
    }
196

197
    /**
198
     * Retrieves the query ID for a given query name.
199
     *
200
     * @param queryName The name of the query.
201
     * @return The query ID, or null if the query name is unknown.
202
     */
203
    public static String getQueryId(String queryName) {
204
        return queryIds.get(queryName);
5✔
205
    }
206

207
    /**
208
     * Extracts the query name from a given query IRI.
209
     *
210
     * @param queryIri The query IRI.
211
     * @return The query name, or null if the IRI is invalid.
212
     */
213
    public static String getQueryName(IRI queryIri) {
214
        if (queryIri == null) return null;
4✔
215
        if (!queryIri.stringValue().matches(queryIriPattern)) return null;
7✔
216
        return queryIri.stringValue().replaceFirst(queryIriPattern, "$3");
6✔
217
    }
218

219
}
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