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

knowledgepixels / nanopub-registry / 20413250445

21 Dec 2025 05:19PM UTC coverage: 0.924% (-0.03%) from 0.954%
20413250445

push

github

ashleycaselli
chore: minor code cleanup

6 of 592 branches covered (1.01%)

Branch coverage included in aggregate %.

16 of 1789 relevant lines covered (0.89%)

0.11 hits per line

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

0.0
src/main/java/com/knowledgepixels/registry/NanopubLoader.java
1
package com.knowledgepixels.registry;
2

3
import com.mongodb.client.ClientSession;
4
import com.mongodb.client.MongoCursor;
5
import net.trustyuri.TrustyUriUtils;
6
import net.trustyuri.rdf.RdfModule;
7
import org.apache.http.Header;
8
import org.apache.http.HttpResponse;
9
import org.apache.http.client.HttpClient;
10
import org.apache.http.client.methods.CloseableHttpResponse;
11
import org.apache.http.client.methods.HttpGet;
12
import org.apache.http.util.EntityUtils;
13
import org.bson.Document;
14
import org.bson.types.Binary;
15
import org.eclipse.rdf4j.common.exception.RDF4JException;
16
import org.eclipse.rdf4j.rio.RDFFormat;
17
import org.nanopub.MalformedNanopubException;
18
import org.nanopub.Nanopub;
19
import org.nanopub.NanopubImpl;
20
import org.nanopub.NanopubUtils;
21
import org.nanopub.extra.server.GetNanopub;
22
import org.nanopub.jelly.JellyUtils;
23
import org.nanopub.jelly.MaybeNanopub;
24
import org.nanopub.jelly.NanopubStream;
25
import org.nanopub.trusty.TrustyNanopubUtils;
26
import org.nanopub.vocabulary.NPX;
27
import org.slf4j.Logger;
28
import org.slf4j.LoggerFactory;
29

30
import java.io.IOException;
31
import java.io.InputStream;
32
import java.util.ArrayList;
33
import java.util.Collections;
34
import java.util.List;
35
import java.util.stream.Stream;
36

37
import static com.knowledgepixels.registry.RegistryDB.has;
38

39
public class NanopubLoader {
40

41
    private NanopubLoader() {
42
    }
43

44
    public final static String INTRO_TYPE = NPX.DECLARED_BY.stringValue();
×
45
    public final static String INTRO_TYPE_HASH = Utils.getHash(INTRO_TYPE);
×
46
    public final static String ENDORSE_TYPE = Utils.APPROVES_OF.stringValue();
×
47
    public final static String ENDORSE_TYPE_HASH = Utils.getHash(ENDORSE_TYPE);
×
48
    private static final Logger log = LoggerFactory.getLogger(NanopubLoader.class);
×
49

50
    // TODO Distinguish and support these cases:
51
    //      1. Simple load: load to all core lists if pubkey is "core-loaded", or load to all lists if pubkey is "full-loaded"
52
    //      2. Core load: load to all core lists (initialize if needed), or load to all lists if pubkey is "full-loaded"
53
    //      3. Full load: load to all lists (initialize if needed)
54

55
    public static void simpleLoad(ClientSession mongoSession, String nanopubId) {
56
        simpleLoad(mongoSession, retrieveNanopub(mongoSession, nanopubId));
×
57
    }
×
58

59
    public static void simpleLoad(ClientSession mongoSession, Nanopub np) {
60
        String pubkey = RegistryDB.getPubkey(np);
×
61
        if (pubkey == null) {
×
62
            log.info("Ignore (not signed): {}", np.getUri());
×
63
            return;
×
64
        }
65
        String pubkeyHash = Utils.getHash(pubkey);
×
66
        // TODO Do we need to load anything else here, into the other DB collections?
67
        if (has(mongoSession, "lists", new Document("pubkey", pubkeyHash).append("type", "$").append("status", "loaded"))) {
×
68
            RegistryDB.loadNanopub(mongoSession, np, pubkeyHash, "$");
×
69
        } else if (has(mongoSession, "lists", new Document("pubkey", pubkeyHash).append("type", INTRO_TYPE_HASH).append("status", "loaded"))) {
×
70
            RegistryDB.loadNanopub(mongoSession, np, pubkeyHash, INTRO_TYPE, ENDORSE_TYPE);
×
71
        }
72
    }
×
73

74
    /**
75
     * Retrieve Nanopubs from the peers of this Nanopub Registry.
76
     *
77
     * @param typeHash   The hash of the type of the Nanopub to retrieve.
78
     * @param pubkeyHash The hash of the pubkey of the Nanopub to retrieve.
79
     * @return A stream of MaybeNanopub objects, or an empty stream if no peer is available.
80
     */
81
    public static Stream<MaybeNanopub> retrieveNanopubsFromPeers(String typeHash, String pubkeyHash) {
82
        // TODO Move the code of this method to nanopub-java library.
83

84
        List<String> peerUrlsToTry = new ArrayList<>(Utils.getPeerUrls());
×
85
        Collections.shuffle(peerUrlsToTry);
×
86
        while (!peerUrlsToTry.isEmpty()) {
×
87
            String peerUrl = peerUrlsToTry.removeFirst();
×
88

89
            String requestUrl = peerUrl + "list/" + pubkeyHash + "/" + typeHash + ".jelly";
×
90
            log.info("Request: {}", requestUrl);
×
91
            try {
92
                CloseableHttpResponse resp = NanopubUtils.getHttpClient().execute(new HttpGet(requestUrl));
×
93
                int httpStatus = resp.getStatusLine().getStatusCode();
×
94
                if (httpStatus < 200 || httpStatus >= 300) {
×
95
                    log.info("Request failed: {} {}", peerUrl, httpStatus);
×
96
                    EntityUtils.consumeQuietly(resp.getEntity());
×
97
                    continue;
×
98
                }
99
                Header nrStatus = resp.getFirstHeader("Nanopub-Registry-Status");
×
100
                if (nrStatus == null) {
×
101
                    log.info("Nanopub-Registry-Status header not found at: {}", peerUrl);
×
102
                    EntityUtils.consumeQuietly(resp.getEntity());
×
103
                    continue;
×
104
                } else if (!nrStatus.getValue().equals("ready") && !nrStatus.getValue().equals("updating")) {
×
105
                    log.info("Peer in non-ready state: {} {}", peerUrl, nrStatus.getValue());
×
106
                    EntityUtils.consumeQuietly(resp.getEntity());
×
107
                    continue;
×
108
                }
109
                InputStream is = resp.getEntity().getContent();
×
110
                return NanopubStream.fromByteStream(is).getAsNanopubs();
×
111
            } catch (UnsupportedOperationException | IOException ex) {
×
112
                log.info("Request failed: ", ex);
×
113
            }
114
        }
×
115
        return Stream.empty();
×
116
    }
117

118
    public static Nanopub retrieveNanopub(ClientSession mongoSession, String nanopubId) {
119
        Nanopub np = retrieveLocalNanopub(mongoSession, nanopubId);
×
120
        int tryCount = 0;
×
121
        while (np == null) {
×
122
            if (tryCount > 10) {
×
123
                throw new RuntimeException("Could not load nanopub: " + nanopubId);
×
124
            } else if (tryCount > 0) {
×
125
                try {
126
                    Thread.sleep(100);
×
127
                } catch (InterruptedException ex) {
×
128
                    log.info("Thread was interrupted", ex);
×
129
                }
×
130
            }
131
            log.info("Loading {}", nanopubId);
×
132

133
            // TODO Reach out to other Nanopub Registries here:
134
            np = getNanopub(nanopubId);
×
135
            if (np != null) {
×
136
                RegistryDB.loadNanopub(mongoSession, np);
×
137
            } else {
138
                tryCount = tryCount + 1;
×
139
            }
140
        }
141
        return np;
×
142
    }
143

144
    public static Nanopub retrieveLocalNanopub(ClientSession mongoSession, String nanopubId) {
145
        String ac = TrustyUriUtils.getArtifactCode(nanopubId);
×
146
        MongoCursor<Document> cursor = RegistryDB.get(mongoSession, "nanopubs", new Document("_id", ac));
×
147
        if (!cursor.hasNext()) return null;
×
148
        try {
149
            // Parse from Jelly, not TriG (it's faster)
150
            return JellyUtils.readFromDB(((Binary) cursor.next().get("jelly")).getData());
×
151
        } catch (RDF4JException | MalformedNanopubException ex) {
×
152
            log.info("Exception reading Jelly", ex);
×
153
            return null;
×
154
        }
155
    }
156

157
    // TODO Provide this method in nanopub-java (GetNanopub)
158
    private static Nanopub getNanopub(String uriOrArtifactCode) {
159
        List<String> peerUrls = new ArrayList<>(Utils.getPeerUrls());
×
160
        Collections.shuffle(peerUrls);
×
161
        String ac = GetNanopub.getArtifactCode(uriOrArtifactCode);
×
162
        if (!ac.startsWith(RdfModule.MODULE_ID)) {
×
163
            throw new IllegalArgumentException("Not a trusty URI of type RA");
×
164
        }
165
        while (!peerUrls.isEmpty()) {
×
166
            String peerUrl = peerUrls.removeFirst();
×
167
            try {
168
                Nanopub np = get(ac, peerUrl, NanopubUtils.getHttpClient());
×
169
                if (np != null) {
×
170
                    return np;
×
171
                }
172
            } catch (IOException | RDF4JException | MalformedNanopubException ex) {
×
173
                // ignore
174
            }
×
175
        }
×
176
        return null;
×
177
    }
178

179
    // TODO Provide this method in nanopub-java (GetNanopub)
180
    private static Nanopub get(String artifactCode, String registryUrl, HttpClient httpClient)
181
            throws IOException, RDF4JException, MalformedNanopubException {
182
        HttpGet get = null;
×
183
        // TODO Get in Jelly format:
184
        String getUrl = registryUrl + "np/" + artifactCode;
×
185
        try {
186
            get = new HttpGet(getUrl);
×
187
        } catch (IllegalArgumentException ex) {
×
188
            throw new IOException("invalid URL: " + getUrl);
×
189
        }
×
190
        get.setHeader("Accept", "application/trig");
×
191
        InputStream in = null;
×
192
        try {
193
            HttpResponse resp = httpClient.execute(get);
×
194
            if (!wasSuccessful(resp)) {
×
195
                EntityUtils.consumeQuietly(resp.getEntity());
×
196
                throw new IOException(resp.getStatusLine().toString());
×
197
            }
198
            in = resp.getEntity().getContent();
×
199
            Nanopub nanopub = new NanopubImpl(in, RDFFormat.TRIG);
×
200
            if (!TrustyNanopubUtils.isValidTrustyNanopub(nanopub)) {
×
201
                throw new MalformedNanopubException("Nanopub is not trusty");
×
202
            }
203
            return nanopub;
×
204
        } finally {
205
            if (in != null) in.close();
×
206
        }
207
    }
208

209
    private static boolean wasSuccessful(HttpResponse resp) {
210
        int c = resp.getStatusLine().getStatusCode();
×
211
        return c >= 200 && c < 300;
×
212
    }
213

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