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

knowledgepixels / nanodash / 21668389047

04 Feb 2026 10:44AM UTC coverage: 13.602% (-0.01%) from 13.615%
21668389047

push

github

tkuhn
chore(core-deps): Update nanopub dependency

551 of 5240 branches covered (10.52%)

Branch coverage included in aggregate %.

1457 of 9523 relevant lines covered (15.3%)

2.05 hits per line

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

60.78
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.*;
6
import org.slf4j.Logger;
7
import org.slf4j.LoggerFactory;
8

9
import java.util.concurrent.ConcurrentHashMap;
10
import java.util.concurrent.ConcurrentMap;
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
    // Query IDs (full id = RA.../query-name)
22
    public static final String GET_LATEST_NANOPUBS_FROM_PUBKEYS = "RAe-oA5eSmkCXCALZ99-0k4imnlI74KPqURfhHOmnzo6A/get-latest-nanopubs-from-pubkeys";
23
    public static final String GET_LATEST_NANOPUBS_FROM_USERID = "RAuy4N1h4vZ1wgBUMvTiWw2y_Y0_5oFYRTwdq-xj2qqNM/get-latest-nanopubs-from-userid";
24
    public static final String GET_USER_STATS_FROM_PUBKEYS = "RAiCBvPL2hRGzI8g5L68O-C9yEXryC_vG35GdEm5jtH_s/get-user-stats-from-pubkeys";
25
    public static final String GET_USER_STATS_FROM_USERID = "RA3U23LL3xbNwsu92fAqsKb0kagOud4f9TlRQq3evNJck/get-user-stats-from-userid";
26
    public static final String GET_TOP_CREATORS_LAST30D = "RAcNvmEiUNUb2a7O4fwRvy2x2BCN640AC880fTzFworr8/get-top-creators-last30d";
27
    public static final String GET_LATEST_USERS = "RAr27GmRUKQmvPbfmB34N9l9lX-xYK7nQhvOMbQCk3byI/get-latest-users";
28
    public static final String GET_MOST_RECENT_NANOPUBS = "RAYNg6rfvXIVvJY2u8oS0EEjxnVvimLLVZG1rOar_nWIY/get-most-recent-nanopubs";
29
    public static final String GET_PUBLISHER_VERSION = "RAPGhXDRzeGu-Qk0AkjleEtxMxqAvJ-dZn7985gzAbyhs/get-publisher-version";
30
    public static final String GET_MOST_USED_TEMPLATES_LAST30D = "RAvL7pe2ppsfq4mVWTdJjssYGsjrmliNd_sZO2ytLvg1Y/get-most-used-templates-last30d";
31
    public static final String GET_LATEST_NANOPUBS_BY_TYPE = "RANn4Mu8r8bqJA9KJMGXTQAEGAEvtNKGFsuhRIC6BRIOo/get-latest-nanopubs-by-type";
32
    public static final String GET_LATEST_VERSION_OF_NP = "RAiRsB2YywxjsBMkVRTREJBooXhf2ZOHoUs5lxciEl37I/get-latest-version-of-np";
33
    public static final String GET_ALL_USER_INTROS = "RAjHh6P11QFUaoPiMRBavdAnTq4YMJW4PB85oVFSBfYjU/get-all-user-intros";
34
    public static final String GET_SUGGESTED_TEMPLATES_TO_GET_STARTED = "RA-tlMmQA7iT2wR2aS3PlONrepX7vdXbkzeWluea7AECg/get-suggested-templates-to-get-started";
35
    public static final String GET_MONTHLY_TYPE_OVERVIEW_BY_PUBKEYS = "RAhI-C2KsqS_IvnxwyBrbMFsoj65dhLWE_CBo_KtcVEVA/get-monthly-type-overview-by-pubkeys";
36
    public static final String GET_APPROVED_NANOPUBS = "RAn3agwsH2yk-8132RJApGYxdPSHHCXDAIYiCaSBBo6tg/get-approved-nanopubs";
37
    public static final String FIND_URI_REFERENCES = "RAz1ogtMxSTKSOYwHAfD5M3Y-vd1vd46OZta_vvbqh8kY/find-uri-references";
38
    public static final String GET_NANOPUBS_BY_TYPE = "RAE35dYJQlpnqim7VeKuu07E9I1LQUZpkdYQR4RvU3KMU/get-nanopubs-by-type";
39
    public static final String GET_INTRODUCING_NANOPUB = "RALZXWg5lZoJoQ0VHL5mpDgNxYpqU6FoDLWGp4rs8A6b8/get-introducing-nanopub";
40
    public static final String FULLTEXT_SEARCH = "RAxdh5xkc6K6SMLY23yKu__zTWJPXeRFc0qgNNxkbOkpY/fulltext-search";
41
    public static final String FIND_THINGS = "RAyMrQ89RECTi9gZK5q7gjL1wKTiP8StkLy0NIkkCiyew/find-things";
42
    public static final String GET_INSTANCES = "RAjt1H9rCSr6A9VGzlhye00zPdH69JdGc3kd_2VjDmzVg/get-instances";
43
    public static final String GET_CLASSES_FOR_THING = "RAH06iUwnvj_pRARY15ayJAY5tuJau3rCvHhPPhe49fVI/get-classes-for-thing";
44
    public static final String FIND_REFERENCING_NANOPUBS = "RAJStXEm1wZcg34ZLPqe00VPSzIVCwC2rrxdj_JR8v5DY/find-referencing-nanopubs";
45
    public static final String GET_LABELS_FOR_THING = "RAtftxAXJubB4rlm9fOvvHNVIkXvWQLC6Ag_MiV7HL0ow/get-labels-for-thing";
46
    public static final String GET_TEMPLATES_WITH_URI = "RARtWHRzNY5hh31X2VB5eOCJAdp9Cjv4CakA0Idqz69MI/get-templates-with-uri";
47
    public static final String GET_NEWER_VERSIONS_OF_NP = "RAIn9NTsWE0qrpKiK3nOmZRXVzwv0qnfbm7dR_CUnp4aA/get-newer-versions-of-np";
48
    public static final String GET_QUERIES = "RAQqjXQYlxYQeI4Y3UQy9OrD5Jx1E3PJ8KwKKQlWbiYSw/get-queries";
49
    public static final String GET_LATEST_THING_NANOPUB = "RAzXDzCHoZmJITgYYquLwDDkSyNf3eKKQz9NfQPYB1cyE/get-latest-thing-nanopub";
50
    public static final String GET_PROJECTS = "RAnpimW7SPwaum2fefdS6_jpzYxcTRGjE-pmgNTL_BBJU/get-projects";
51
    public static final String GET_OWNERS = "RApiw7Z0NeP3RaLiqX6Q7Ml5CfEWbt-PysUbMNljuiLJw/get-owners";
52
    public static final String GET_MEMBERS = "RASyFJyADTtG-l_Qe3a5PE_e2yUJR-PydXfkZjjrBuV7U/get-members";
53
    public static final String GET_SPACES = "RAf0Apox1sbJRC0ZBrqS9wtYccLFJ_5VLq-u4rJy5WbnA/get-spaces";
54
    public static final String GET_PARTS = "RAJmZoM0xCGE8OL6EgmQBOd1M58ggNkwZ0IUqHOAPRfvE/get-parts";
55
    public static final String GET_ASSERTION_TEMPLATES = "RA6bgrU3Ezfg5VAiLru0BFYHaSj6vZU6jJTscxNl8Wqvc/get-assertion-templates";
56
    public static final String GET_PROVENANCE_TEMPLATES = "RA4bt3MQRnEPC2nSsdbCJc74wT-e1w68dSCpYVyvG0274/get-provenance-templates";
57
    public static final String GET_PUBINFO_TEMPLATES = "RAMcdiJpvvk8424AJIH1jsDUQVcPYOLRw0DNnZt_ND_LQ/get-pubinfo-templates";
58
    public static final String GET_ADMINS = "RAOpebLWcp0G6D9U8ZhfYGOkz-kObkytDsM6rCQlIi_j0/get-admins";
59
    public static final String GET_SPACE_MEMBERS = "RA_Xf7mfC2PAohGYktJEXjkbzxPhkfX4DE1bQKFqkxrRg/get-space-members";
60
    public static final String GET_FILTERED_NANOPUB_LIST = "RAhbj9bJBxRYbGPbluKkf4yDMKM5nZ29w0dMjaGq7XfNU/get-filtered-nanopub-list";
61
    public static final String GET_PINNED_TEMPLATES = "RA_F6C2DtlL4EXSF2vzU1KLVUiRLjPAM-r1Wy32JIeSYI/get-pinned-templates";
62
    public static final String GET_PINNED_QUERIES = "RAH5jJUo8ukFkPP1xghveSNPze3pmSK69zri5PPM6HEbg/get-pinned-queries";
63
    public static final String GET_SPACE_MEMBER_ROLES = "RAF-LNZPrT11euM9NQGOLRrJg1pD02oXM5Cxb9XP7tBkU/get-space-member-roles";
64
    public static final String GET_LATEST_ACCEPTED_BDJ = "RAkoDiXZG_CYt978-dZ_vffK-UTbN6e1bmtFy6qdmFzC4/get-latest-accepted-bdj";
65
    public static final String GET_LATEST_BIODIV_CANDIDATES = "RAgnLJH8kcI_e488VdoyQ0g3-wcumj4mSiusxPmeAYsSI/get-latest-biodiv-candidates";
66
    public static final String GET_LATEST_ACCEPTED_DS = "RATpsBysLf8yXeMpY7PHKj-aKNCa4-4Okg1hi97OLDXIo/get-latest-accepted-ds";
67
    public static final String GET_LATEST_DS_CANDIDATES = "RAFNTW3jhWKnNvhMSOfYvG53ZAurxrFv_-vnIJkZyfAuo/get-latest-ds-candidates";
68
    public static final String GET_DS_REACTIONS = "RA0FiH8gukovvEHPBMn72zUDdMQylQmUwtIGNLYBZXGfk/get-ds-reactions";
69
    public static final String GET_LATEST_ACCEPTED_RIO = "RAAXmnJdXHO86GqJs8VTdqapUWqCrHKRgRT2b4NfjAfgk/get-latest-accepted-rio";
70
    public static final String GET_LATEST_RIO_CANDIDATES = "RAehKOCOnZ3uDBmI0kkCNTh5k9Nl6YYNj7tyc20tVymxY/get-latest-rio-candidates";
71
    public static final String GET_REACTIONS = "RAe7k3L0oElPOrFoUMkUhqU9dGUqfBaUSw3cVplOUn3Fk/get-reactions";
72
    public static final String GET_TERM_DEFINITIONS = "RAZUsK7jU85oUYEVKvMPFlqbwn19oR55IQuFkXuiS_Tkg/get-term-definitions";
73
    public static final String GET_MAINTAINED_RESOURCES = "RA8RsuKt6HzCXGmw9wMeN4rwSm456bohOuJ0h-jEgXKmM/get-maintained-resources";
74
    public static final String GET_VIEW_DISPLAYS = "RAapc3jbJ3GkDy0ncKx3pok_zEKqwrT6-Z5TkCP1k96II/get-view-displays";
75

76
    private static final Logger logger = LoggerFactory.getLogger(QueryApiAccess.class);
9✔
77

78
    private static ConcurrentMap<String, Pair<Long, String>> latestVersionMap = new ConcurrentHashMap<>();
15✔
79

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

82
    /**
83
     * Forces the retrieval of an API response for a given query name and parameters.
84
     * Retries until a valid response is received.
85
     *
86
     * @param queryRef The query reference
87
     * @return The API response.
88
     */
89
    public static ApiResponse forcedGet(QueryRef queryRef) {
90
        while (true) {
91
            ApiResponse resp = null;
6✔
92
            try {
93
                resp = QueryApiAccess.get(queryRef);
9✔
94
            } catch (Exception ex) {
×
95
                // TODO We should be more specific about which exceptions we catch here
96
                //      and generally improve this, as this could hang forever.
97
                logger.error("Error while forcing API get for query {}", queryRef, ex);
×
98
            }
3✔
99
            if (resp != null) return resp;
12✔
100
            try {
101
                Thread.sleep(5000);
6✔
102
            } catch (InterruptedException ex) {
×
103
                logger.error("Interrupted while forcing API get for query {}", queryRef, ex);
×
104
            }
3✔
105
        }
3✔
106
    }
107

108
    /**
109
     * Retrieves an API response for a given query reference.
110
     *
111
     * @param queryRef The query reference
112
     * @return The API response.
113
     * @throws org.nanopub.extra.services.FailedApiCallException         If the API call fails.
114
     * @throws org.nanopub.extra.services.APINotReachableException       If the API is not reachable.
115
     * @throws org.nanopub.extra.services.NotEnoughAPIInstancesException If there are not enough API instances.
116
     */
117
    public static ApiResponse get(QueryRef queryRef) throws FailedApiCallException, APINotReachableException, NotEnoughAPIInstancesException {
118
        if (!queryRef.getQueryId().matches("^RA[A-Za-z0-9-_]{43}/.*$")) {
15!
119
            throw new IllegalArgumentException("QueryRef name must be full query ID: " + queryRef.getQueryId());
×
120
        }
121
        return QueryAccess.get(queryRef);
9✔
122
    }
123

124
    /**
125
     * Retrieves the latest version ID of a given nanopublication.
126
     *
127
     * @param nanopubId The ID of the nanopublication.
128
     * @return The latest version ID.
129
     */
130
    public static String getLatestVersionId(String nanopubId) {
131
        long currentTime = System.currentTimeMillis();
6✔
132
        if (!latestVersionMap.containsKey(nanopubId) || currentTime - latestVersionMap.get(nanopubId).getLeft() > 1000 * 60) {
12!
133
            // Re-fetch if existing value is older than 1 minute
134
            try {
135
                ApiResponse r = ApiCache.retrieveResponseSync(new QueryRef(GET_LATEST_VERSION_OF_NP, "np", nanopubId), false);
27✔
136
                if (r.getData().size() != 1) return nanopubId;
15!
137
                String l = r.getData().get(0).get("latest");
24✔
138
                latestVersionMap.put(nanopubId, Pair.of(currentTime, l));
24✔
139
            } catch (Exception ex) {
×
140
                logger.error("Error while getting latest version of nanopub '{}'", nanopubId, ex);
×
141
                return nanopubId;
×
142
            }
3✔
143
        }
144
        return latestVersionMap.get(nanopubId).getRight();
21✔
145
    }
146

147
    /**
148
     * Extracts the query ID from a given query IRI.
149
     *
150
     * @param queryIri The query IRI.
151
     * @return The query ID, or null if the IRI is invalid.
152
     */
153
    public static String getQueryId(IRI queryIri) {
154
        if (queryIri == null) return null;
×
155
        if (!queryIri.stringValue().matches(queryIriPattern)) return null;
×
156
        return queryIri.stringValue().replaceFirst(queryIriPattern, "$2/$3");
×
157
    }
158

159
    /**
160
     * Extracts the query name from a given query IRI.
161
     *
162
     * @param queryIri The query IRI.
163
     * @return The query name, or null if the IRI is invalid.
164
     */
165
    public static String getQueryName(IRI queryIri) {
166
        if (queryIri == null) return null;
12✔
167
        if (!queryIri.stringValue().matches(queryIriPattern)) return null;
21✔
168
        return queryIri.stringValue().replaceFirst(queryIriPattern, "$3");
18✔
169
    }
170

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