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

knowledgepixels / nanopub-registry / 21143551066

19 Jan 2026 03:44PM UTC coverage: 18.779% (+1.2%) from 17.551%
21143551066

push

github

ashleycaselli
docs(Utils): add missing Javadoc annotations

96 of 586 branches covered (16.38%)

Branch coverage included in aggregate %.

350 of 1789 relevant lines covered (19.56%)

3.59 hits per line

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

48.79
src/main/java/com/knowledgepixels/registry/RegistryDB.java
1
package com.knowledgepixels.registry;
2

3
import com.mongodb.MongoClient;
4
import com.mongodb.MongoNamespace;
5
import com.mongodb.MongoWriteException;
6
import com.mongodb.ServerAddress;
7
import com.mongodb.client.ClientSession;
8
import com.mongodb.client.MongoCollection;
9
import com.mongodb.client.MongoCursor;
10
import com.mongodb.client.MongoDatabase;
11
import com.mongodb.client.model.CountOptions;
12
import com.mongodb.client.model.IndexOptions;
13
import com.mongodb.client.model.Indexes;
14
import com.mongodb.client.model.UpdateOptions;
15
import net.trustyuri.TrustyUriUtils;
16
import org.bson.Document;
17
import org.bson.conversions.Bson;
18
import org.bson.types.Binary;
19
import org.eclipse.rdf4j.common.exception.RDF4JException;
20
import org.eclipse.rdf4j.model.IRI;
21
import org.eclipse.rdf4j.rio.RDFFormat;
22
import org.nanopub.MalformedNanopubException;
23
import org.nanopub.Nanopub;
24
import org.nanopub.NanopubUtils;
25
import org.nanopub.extra.security.MalformedCryptoElementException;
26
import org.nanopub.extra.security.NanopubSignatureElement;
27
import org.nanopub.extra.security.SignatureUtils;
28
import org.nanopub.jelly.JellyUtils;
29
import org.slf4j.Logger;
30
import org.slf4j.LoggerFactory;
31

32
import java.io.IOException;
33
import java.security.GeneralSecurityException;
34
import java.util.ArrayList;
35

36
import static com.mongodb.client.model.Indexes.*;
37

38
public class RegistryDB {
39

40
    private RegistryDB() {
41
    }
42

43
    private static final String REGISTRY_DB_NAME = Utils.getEnv("REGISTRY_DB_NAME", "nanopubRegistry");
16✔
44

45
    private static final Logger logger = LoggerFactory.getLogger(RegistryDB.class);
12✔
46

47
    private static MongoClient mongoClient;
48
    private static MongoDatabase mongoDB;
49

50
    /**
51
     * Returns the MongoDB database instance.
52
     *
53
     * @return the MongoDatabase instance
54
     */
55
    public static MongoDatabase getDB() {
56
        return mongoDB;
8✔
57
    }
58

59
    /**
60
     * Returns the MongoDB client instance.
61
     *
62
     * @return the MongoClient instance
63
     */
64
    public static MongoClient getClient() {
65
        return mongoClient;
8✔
66
    }
67

68
    public static MongoCollection<Document> collection(String name) {
69
        return mongoDB.getCollection(name);
16✔
70
    }
71

72
    private final static IndexOptions unique = new IndexOptions().unique(true);
24✔
73

74
    /**
75
     * Initializes the MongoDB connection and sets up collections and indexes if not already initialized.
76
     */
77
    public static void init() {
78
        if (mongoClient != null) {
8✔
79
            logger.info("RegistryDB already initialized");
12✔
80
            return;
4✔
81
        }
82
        final String REGISTRY_DB_HOST = Utils.getEnv("REGISTRY_DB_HOST", "mongodb");
16✔
83
        final int REGISTRY_DB_PORT = Integer.parseInt(Utils.getEnv("REGISTRY_DB_PORT", String.valueOf(ServerAddress.defaultPort())));
24✔
84
        logger.info("Initializing RegistryDB connection to database '{}' at {}:{}", REGISTRY_DB_NAME, REGISTRY_DB_HOST, REGISTRY_DB_PORT);
72✔
85
        mongoClient = new MongoClient(REGISTRY_DB_HOST, REGISTRY_DB_PORT);
24✔
86
        mongoDB = mongoClient.getDatabase(REGISTRY_DB_NAME);
16✔
87

88
        try (ClientSession mongoSession = mongoClient.startSession()) {
12✔
89
            if (isInitialized(mongoSession)) {
12!
90
                return;
×
91
            }
92

93
            final IndexOptions unique = new IndexOptions().unique(true);
24✔
94

95
            collection("tasks").createIndex(mongoSession, Indexes.descending("not-before"));
48✔
96

97
            collection(Collection.NANOPUBS.toString()).createIndex(mongoSession, ascending("fullId"), unique);
56✔
98
            collection(Collection.NANOPUBS.toString()).createIndex(mongoSession, descending("counter"), unique);
56✔
99
            collection(Collection.NANOPUBS.toString()).createIndex(mongoSession, ascending("pubkey"));
52✔
100

101
            collection("lists").createIndex(mongoSession, ascending("pubkey", "type"), unique);
68✔
102
            collection("lists").createIndex(mongoSession, ascending("status"));
48✔
103

104
            collection("listEntries").createIndex(mongoSession, ascending("np"));
48✔
105
            collection("listEntries").createIndex(mongoSession, ascending("pubkey", "type", "np"), unique);
84✔
106
            collection("listEntries").createIndex(mongoSession, compoundIndex(ascending("pubkey"), ascending("type"), descending("position")), unique);
156✔
107
            collection("listEntries").createIndex(mongoSession, ascending("pubkey", "type", "checksum"), unique);
84✔
108
            collection("listEntries").createIndex(mongoSession, ascending("invalidated"));
48✔
109

110
            collection("invalidations").createIndex(mongoSession, ascending("invalidatingNp"));
48✔
111
            collection("invalidations").createIndex(mongoSession, ascending("invalidatingPubkey"));
48✔
112
            collection("invalidations").createIndex(mongoSession, ascending("invalidatedNp"));
48✔
113
            collection("invalidations").createIndex(mongoSession, ascending("invalidatingPubkey", "invalidatedNp"));
64✔
114

115
            collection("trustEdges").createIndex(mongoSession, ascending("fromAgent"));
48✔
116
            collection("trustEdges").createIndex(mongoSession, ascending("fromPubkey"));
48✔
117
            collection("trustEdges").createIndex(mongoSession, ascending("toAgent"));
48✔
118
            collection("trustEdges").createIndex(mongoSession, ascending("toPubkey"));
48✔
119
            collection("trustEdges").createIndex(mongoSession, ascending("source"));
48✔
120
            collection("trustEdges").createIndex(mongoSession, ascending("fromAgent", "fromPubkey", "toAgent", "toPubkey", "source"), unique);
116✔
121
            collection("trustEdges").createIndex(mongoSession, ascending("invalidated"));
48✔
122

123
            collection("hashes").createIndex(mongoSession, ascending("hash"), unique);
52✔
124
            collection("hashes").createIndex(mongoSession, ascending("value"), unique);
52✔
125
        }
×
126
    }
4✔
127

128
    /**
129
     * Initializes the loading collections with appropriate indexes.
130
     *
131
     * @param mongoSession the MongoDB client session
132
     */
133
    public static void initLoadingCollections(ClientSession mongoSession) {
134
        collection("endorsements_loading").createIndex(mongoSession, ascending("agent"));
48✔
135
        collection("endorsements_loading").createIndex(mongoSession, ascending("pubkey"));
48✔
136
        collection("endorsements_loading").createIndex(mongoSession, ascending("endorsedNanopub"));
48✔
137
        collection("endorsements_loading").createIndex(mongoSession, ascending("source"));
48✔
138
        collection("endorsements_loading").createIndex(mongoSession, ascending("status"));
48✔
139
        // zip: Hmm, not possible to set com.mongodb.client.model.WriteModel<T> here
140
        // I'd currently recommend to have a package with the DB related stuff
141
        // and therein a Custom Extension T of <Document>, where we could put that WriteModel<T>.
142

143
        collection("agents_loading").createIndex(mongoSession, ascending("agent"), unique);
52✔
144
        collection("agents_loading").createIndex(mongoSession, descending("accountCount"));
48✔
145
        collection("agents_loading").createIndex(mongoSession, descending("avgPathCount"));
48✔
146
        collection("agents_loading").createIndex(mongoSession, descending("totalRatio"));
48✔
147

148
        collection("accounts_loading").createIndex(mongoSession, ascending("agent"));
48✔
149
        collection("accounts_loading").createIndex(mongoSession, ascending("pubkey"));
48✔
150
        collection("accounts_loading").createIndex(mongoSession, ascending("agent", "pubkey"), unique);
68✔
151
        collection("accounts_loading").createIndex(mongoSession, ascending("type"));
48✔
152
        collection("accounts_loading").createIndex(mongoSession, ascending("status"));
48✔
153
        collection("accounts_loading").createIndex(mongoSession, descending("ratio"));
48✔
154
        collection("accounts_loading").createIndex(mongoSession, descending("pathCount"));
48✔
155

156
        collection("trustPaths_loading").createIndex(mongoSession, ascending("agent", "pubkey", "depth", "sorthash"), unique);
100✔
157
        collection("trustPaths_loading").createIndex(mongoSession, ascending("depth"));
48✔
158
        collection("trustPaths_loading").createIndex(mongoSession, descending("ratio"));
48✔
159
    }
4✔
160

161
    /**
162
     * Checks if the database has been initialized.
163
     *
164
     * @param mongoSession the MongoDB client session
165
     * @return true if initialized, false otherwise
166
     */
167
    public static boolean isInitialized(ClientSession mongoSession) {
168
        return getValue(mongoSession, Collection.SERVER_INFO.toString(), "setupId") != null;
32!
169
    }
170

171
    /**
172
     * Renames a collection in the database. If the new collection name already exists, it will be dropped first.
173
     *
174
     * @param oldCollectionName the current name of the collection
175
     * @param newCollectionName the new name for the collection
176
     */
177
    public static void rename(String oldCollectionName, String newCollectionName) {
178
        // Designed as idempotent operation: calling multiple times has same effect as calling once
179
        if (hasCollection(oldCollectionName)) {
12✔
180
            if (hasCollection(newCollectionName)) {
12✔
181
                collection(newCollectionName).drop();
12✔
182
            }
183
            collection(oldCollectionName).renameCollection(new MongoNamespace(REGISTRY_DB_NAME, newCollectionName));
32✔
184
        }
185
    }
4✔
186

187
    /**
188
     * Checks if a collection with the given name exists in the database.
189
     *
190
     * @param collectionName the name of the collection to check
191
     * @return true if the collection exists, false otherwise
192
     */
193
    public static boolean hasCollection(String collectionName) {
194
        return mongoDB.listCollectionNames().into(new ArrayList<>()).contains(collectionName);
40✔
195
    }
196

197
    /**
198
     * Increases the trust state counter in the server info collection.
199
     *
200
     * @param mongoSession the MongoDB client session
201
     */
202
    public static void increaseStateCounter(ClientSession mongoSession) {
203
        MongoCursor<Document> cursor = collection(Collection.SERVER_INFO.toString()).find(mongoSession, new Document("_id", "trustStateCounter")).cursor();
48✔
204
        if (cursor.hasNext()) {
12✔
205
            long counter = cursor.next().getLong("value");
28✔
206
            collection(Collection.SERVER_INFO.toString()).updateOne(mongoSession, new Document("_id", "trustStateCounter"), new Document("$set", new Document("value", counter + 1)));
92✔
207
        } else {
4✔
208
            collection(Collection.SERVER_INFO.toString()).insertOne(mongoSession, new Document("_id", "trustStateCounter").append("value", 0L));
56✔
209
        }
210
    }
4✔
211

212
    /**
213
     * Checks if an element with the given name exists in the specified collection.
214
     *
215
     * @param mongoSession the MongoDB client session
216
     * @param collection   the name of the collection
217
     * @param elementName  the name of the element used as the _id field
218
     * @return true if the element exists, false otherwise
219
     */
220
    public static boolean has(ClientSession mongoSession, String collection, String elementName) {
221
        return has(mongoSession, collection, new Document("_id", elementName));
36✔
222
    }
223

224
    private static final CountOptions hasCountOptions = new CountOptions().limit(1);
28✔
225

226
    /**
227
     * Checks if any document matching the given filter exists in the specified collection.
228
     *
229
     * @param mongoSession the MongoDB client session
230
     * @param collection   the name of the collection
231
     * @param find         the filter to match documents
232
     * @return true if at least one matching document exists, false otherwise
233
     */
234
    public static boolean has(ClientSession mongoSession, String collection, Bson find) {
235
        return collection(collection).countDocuments(mongoSession, find, hasCountOptions) > 0;
52✔
236
    }
237

238
    /**
239
     * Retrieves a cursor for documents matching the given filter in the specified collection.
240
     *
241
     * @param mongoSession the MongoDB client session
242
     * @param collection   the name of the collection
243
     * @param find         the filter to match documents
244
     * @return a MongoCursor for the matching documents
245
     */
246
    public static MongoCursor<Document> get(ClientSession mongoSession, String collection, Bson find) {
247
        return collection(collection).find(mongoSession, find).cursor();
28✔
248
    }
249

250
    /**
251
     * Retrieves the value of an element with the given name from the specified collection.
252
     *
253
     * @param mongoSession the MongoDB client session
254
     * @param collection   the name of the collection
255
     * @param elementName  the name of the element used as the _id field
256
     * @return the value of the element, or null if not found
257
     */
258
    public static Object getValue(ClientSession mongoSession, String collection, String elementName) {
259
        Document d = collection(collection).find(mongoSession, new Document("_id", elementName)).first();
48✔
260
        if (d == null) {
8✔
261
            return null;
8✔
262
        }
263
        return d.get("value");
16✔
264
    }
265

266
    /**
267
     * Retrieves the boolean value of an element with the given name from the specified collection.
268
     *
269
     * @param mongoSession the MongoDB client session
270
     * @param collection   the name of the collection
271
     * @param elementName  the name of the element used as the _id field
272
     * @return the value of the element, or null if not found
273
     */
274
    public static boolean isSet(ClientSession mongoSession, String collection, String elementName) {
275
        Document d = collection(collection).find(mongoSession, new Document("_id", elementName)).first();
48✔
276
        if (d == null) {
8✔
277
            return false;
8✔
278
        }
279
        return d.getBoolean("value");
20✔
280
    }
281

282
    /**
283
     * Retrieves a single document matching the given filter from the specified collection.
284
     *
285
     * @param mongoSession the MongoDB client session
286
     * @param collection   the name of the collection
287
     * @param find         the filter to match the document
288
     * @return the matching document, or null if not found
289
     */
290
    public static Document getOne(ClientSession mongoSession, String collection, Bson find) {
291
        return collection(collection).find(mongoSession, find).first();
32✔
292
    }
293

294
    /**
295
     * Retrieves the maximum value of a specified field from the documents in the given collection.
296
     *
297
     * @param mongoSession the MongoDB client session
298
     * @param collection   the name of the collection
299
     * @param fieldName    the field for which to find the maximum value
300
     * @return the maximum value of the specified field, or null if no documents exist
301
     */
302
    public static Object getMaxValue(ClientSession mongoSession, String collection, String fieldName) {
303
        Document doc = collection(collection).find(mongoSession).projection(new Document(fieldName, 1)).sort(new Document(fieldName, -1)).first();
84✔
304
        if (doc == null) {
8!
305
            return null;
×
306
        }
307
        return doc.get(fieldName);
16✔
308
    }
309

310
    /**
311
     * Retrieves the document with the maximum value of a specified field from the documents matching the given filter in the specified collection.
312
     *
313
     * @param mongoSession the MongoDB client session
314
     * @param collection   the name of the collection
315
     * @param find         the filter to match documents
316
     * @param fieldName    the field for which to find the maximum value
317
     * @return the document with the maximum value of the specified field, or null if no matching documents exist
318
     */
319
    public static Document getMaxValueDocument(ClientSession mongoSession, String collection, Bson find, String fieldName) {
320
        return collection(collection).find(mongoSession, find).sort(new Document(fieldName, -1)).first();
60✔
321
    }
322

323
    /**
324
     * Sets or updates a document in the specified collection.
325
     *
326
     * @param mongoSession the MongoDB client session
327
     * @param collection   the name of the collection
328
     * @param update       the document to set or update (must contain an _id field)
329
     */
330
    public static void set(ClientSession mongoSession, String collection, Document update) {
331
        Bson find = new Document("_id", update.get("_id"));
32✔
332
        MongoCursor<Document> cursor = collection(collection).find(mongoSession, find).cursor();
28✔
333
        if (cursor.hasNext()) {
12✔
334
            collection(collection).updateOne(mongoSession, find, new Document("$set", update));
44✔
335
        }
336
    }
4✔
337

338
    /**
339
     * Inserts a document into the specified collection.
340
     *
341
     * @param mongoSession the MongoDB client session
342
     * @param collection   the name of the collection
343
     * @param doc          the document to insert
344
     */
345
    public static void insert(ClientSession mongoSession, String collection, Document doc) {
346
        collection(collection).insertOne(mongoSession, doc);
20✔
347
    }
4✔
348

349
    /**
350
     * Sets the value of an element with the given name in the specified collection.
351
     * If the element does not exist, it will be created.
352
     *
353
     * @param mongoSession the MongoDB client session
354
     * @param collection   the name of the collection
355
     * @param elementId    the name of the element used as the _id field
356
     * @param value        the value to set
357
     */
358
    public static void setValue(ClientSession mongoSession, String collection, String elementId, Object value) {
359
        collection(collection).updateOne(mongoSession, new Document("_id", elementId), new Document("$set", new Document("value", value)), new UpdateOptions().upsert(true));
96✔
360
    }
4✔
361

362
    /**
363
     * Records the hash of a given value in the "hashes" collection.
364
     * If the hash already exists, it will be ignored.
365
     *
366
     * @param mongoSession the MongoDB client session
367
     * @param value        the value to hash and record
368
     */
369
    public static void recordHash(ClientSession mongoSession, String value) {
370
        try {
371
            insert(mongoSession, "hashes", new Document("value", value).append("hash", Utils.getHash(value)));
48✔
372
        } catch (MongoWriteException e) {
×
373
            // Duplicate key error -- ignore it
374
            if (e.getError().getCode() != 11000) throw e;
×
375
        }
4✔
376
    }
4✔
377

378
    /**
379
     * Retrieves the original value corresponding to a given hash from the "hashes" collection.
380
     *
381
     * @param hash the hash to look up
382
     * @return the original value, or null if not found
383
     */
384
    public static String unhash(String hash) {
385
        try (var c = collection("hashes").find(new Document("hash", hash)).cursor()) {
40✔
386
            if (c.hasNext()) {
12✔
387
                return c.next().getString("value");
32✔
388
            }
389
            return null;
16✔
390
        }
16!
391
    }
392

393
    /**
394
     * Loads a nanopublication into the database.
395
     *
396
     * @param mongoSession the MongoDB client session
397
     * @param nanopub      the nanopublication to load
398
     */
399
    public static boolean loadNanopub(ClientSession mongoSession, Nanopub nanopub) {
400
        return loadNanopub(mongoSession, nanopub, null);
×
401
    }
402

403
    /**
404
     * Loads a nanopublication into the database, optionally filtering by public key hash and types.
405
     *
406
     * @param mongoSession the MongoDB client session
407
     * @param nanopub      the nanopublication to load
408
     * @param pubkeyHash   the public key hash to filter by (can be null)
409
     * @param types        the types to filter by (can be empty)
410
     * @return true if the nanopublication was loaded, false otherwise
411
     */
412
    public static boolean loadNanopub(ClientSession mongoSession, Nanopub nanopub, String pubkeyHash, String... types) {
413
        if (nanopub.getTripleCount() > 1200) {
×
414
            logger.info("Nanopub has too many triples ({}): {}", nanopub.getTripleCount(), nanopub.getUri());
×
415
            return false;
×
416
        }
417
        if (nanopub.getByteCount() > 1000000) {
×
418
            logger.info("Nanopub is too large ({}): {}", nanopub.getByteCount(), nanopub.getUri());
×
419
            return false;
×
420
        }
421
        String pubkey = getPubkey(nanopub);
×
422
        if (pubkey == null) {
×
423
            logger.info("Ignoring invalid nanopub: {}", nanopub.getUri());
×
424
            return false;
×
425
        }
426
        String ph = Utils.getHash(pubkey);
×
427
        if (pubkeyHash != null && !pubkeyHash.equals(ph)) {
×
428
            logger.info("Ignoring nanopub with non-matching pubkey: {}", nanopub.getUri());
×
429
            return false;
×
430
        }
431
        recordHash(mongoSession, pubkey);
×
432

433
        String ac = TrustyUriUtils.getArtifactCode(nanopub.getUri().stringValue());
×
434
        if (ac == null) {
×
435
            // I don't think this ever happens, but checking here to be sure
436
            logger.info("ERROR. Unexpected Trusty URI: {}", nanopub.getUri());
×
437
            return false;
×
438
        }
439
        if (has(mongoSession, Collection.NANOPUBS.toString(), ac)) {
×
440
            logger.info("Already loaded: {}", nanopub.getUri());
×
441
        } else {
442
            Long counter = (Long) getMaxValue(mongoSession, Collection.NANOPUBS.toString(), "counter");
×
443
            if (counter == null) counter = 0l;
×
444
            String nanopubString;
445
            byte[] jellyContent;
446
            try {
447
                nanopubString = NanopubUtils.writeToString(nanopub, RDFFormat.TRIG);
×
448
                // Save the same thing in the Jelly format for faster loading
449
                jellyContent = JellyUtils.writeNanopubForDB(nanopub);
×
450
            } catch (IOException ex) {
×
451
                throw new RuntimeException(ex);
×
452
            }
×
453
            collection(Collection.NANOPUBS.toString()).insertOne(mongoSession, new Document("_id", ac).append("fullId", nanopub.getUri().stringValue()).append("counter", counter + 1).append("pubkey", ph).append("content", nanopubString).append("jelly", new Binary(jellyContent)));
×
454

455
            for (IRI invalidatedId : Utils.getInvalidatedNanopubIds(nanopub)) {
×
456
                String invalidatedAc = TrustyUriUtils.getArtifactCode(invalidatedId.stringValue());
×
457
                if (invalidatedAc == null) continue;  // This should never happen; checking here just to be sure
×
458

459
                // Add this nanopub also to all lists of invalidated nanopubs:
460
                collection("invalidations").insertOne(mongoSession, new Document("invalidatingNp", ac).append("invalidatingPubkey", ph).append("invalidatedNp", invalidatedAc));
×
461
                MongoCursor<Document> invalidatedEntries = collection("listEntries").find(mongoSession, new Document("np", invalidatedAc).append("pubkey", ph)).cursor();
×
462
                while (invalidatedEntries.hasNext()) {
×
463
                    Document invalidatedEntry = invalidatedEntries.next();
×
464
                    addToList(mongoSession, nanopub, ph, invalidatedEntry.getString("type"));
×
465
                }
×
466

467
                collection("listEntries").updateMany(mongoSession, new Document("np", invalidatedAc).append("pubkey", ph), new Document("$set", new Document("invalidated", true)));
×
468
                collection("trustEdges").updateMany(mongoSession, new Document("source", invalidatedAc), new Document("$set", new Document("invalidated", true)));
×
469
            }
×
470
        }
471

472
        if (pubkeyHash != null) {
×
473
            for (String type : types) {
×
474
                // TODO Check if nanopub really has the type?
475
                addToList(mongoSession, nanopub, pubkeyHash, Utils.getTypeHash(mongoSession, type));
×
476
                if (type.equals("$")) {
×
477
                    for (IRI t : NanopubUtils.getTypes(nanopub)) {
×
478
                        addToList(mongoSession, nanopub, pubkeyHash, Utils.getTypeHash(mongoSession, t));
×
479
                    }
×
480
                }
481
            }
482
        }
483

484
        // Add the invalidating nanopubs also to the lists of this nanopub:
485
        try (MongoCursor<Document> invalidations = collection("invalidations").find(mongoSession, new Document("invalidatedNp", ac).append("invalidatingPubkey", ph)).cursor()) {
×
486
            if (invalidations.hasNext()) {
×
487
                collection("listEntries").updateMany(mongoSession, new Document("np", ac).append("pubkey", ph), new Document("$set", new Document("invalidated", true)));
×
488
                collection("trustEdges").updateMany(mongoSession, new Document("source", ac), new Document("$set", new Document("invalidated", true)));
×
489
            }
490
            while (invalidations.hasNext()) {
×
491
                String iac = invalidations.next().getString("invalidatingNp");
×
492
                try {
493
                    Document npDoc = collection(Collection.NANOPUBS.toString()).find(mongoSession, new Document("_id", iac)).projection(new Document("jelly", 1)).first();
×
494
                    Nanopub inp = JellyUtils.readFromDB(npDoc.get("jelly", Binary.class).getData());
×
495
                    for (IRI type : NanopubUtils.getTypes(inp)) {
×
496
                        addToList(mongoSession, inp, ph, Utils.getTypeHash(mongoSession, type));
×
497
                    }
×
498
                } catch (RDF4JException | MalformedNanopubException ex) {
×
499
                    ex.printStackTrace();
×
500
                }
×
501
            }
×
502

503
        }
504

505
        return true;
×
506
    }
507

508
    private static void addToList(ClientSession mongoSession, Nanopub nanopub, String pubkeyHash, String typeHash) {
509
        String ac = TrustyUriUtils.getArtifactCode(nanopub.getUri().stringValue());
×
510
        try {
511
            insert(mongoSession, "lists", new Document("pubkey", pubkeyHash).append("type", typeHash));
×
512
        } catch (MongoWriteException e) {
×
513
            // Duplicate key error -- ignore it
514
            if (e.getError().getCode() != 11000) throw e;
×
515
        }
×
516

517
        if (has(mongoSession, "listEntries", new Document("pubkey", pubkeyHash).append("type", typeHash).append("np", ac))) {
×
518
            logger.info("Already listed: {}", nanopub.getUri());
×
519
        } else {
520

521
            Document doc = getMaxValueDocument(mongoSession, "listEntries", new Document("pubkey", pubkeyHash).append("type", typeHash), "position");
×
522
            long position;
523
            String checksum;
524
            if (doc == null) {
×
525
                position = 0l;
×
526
                checksum = NanopubUtils.updateXorChecksum(nanopub.getUri(), NanopubUtils.INIT_CHECKSUM);
×
527
            } else {
528
                position = doc.getLong("position") + 1;
×
529
                checksum = NanopubUtils.updateXorChecksum(nanopub.getUri(), doc.getString("checksum"));
×
530
            }
531
            collection("listEntries").insertOne(mongoSession, new Document("pubkey", pubkeyHash).append("type", typeHash).append("position", position).append("np", ac).append("checksum", checksum).append("invalidated", false));
×
532
        }
533
    }
×
534

535
    /**
536
     * Returns the public key string of the Nanopub's signature, or null if not available or invalid.
537
     *
538
     * @param nanopub the nanopub to extract the public key from
539
     * @return The public key string, or null if not available or invalid.
540
     */
541
    public static String getPubkey(Nanopub nanopub) {
542
        // TODO shouldn't this be moved to a utility class in nanopub-java? there is a similar method in NanopubElement class of nanodash
543
        NanopubSignatureElement el;
544
        try {
545
            el = SignatureUtils.getSignatureElement(nanopub);
12✔
546
            if (el != null && SignatureUtils.hasValidSignature(el) && el.getPublicKeyString() != null) {
32!
547
                return el.getPublicKeyString();
12✔
548
            }
549
        } catch (MalformedCryptoElementException | GeneralSecurityException ex) {
×
550
            logger.error("Error in checking the signature of the nanopub {}", nanopub.getUri());
×
551
        }
4✔
552
        return null;
8✔
553
    }
554

555
    /**
556
     * Calculates a hash representing the current state of the trust paths in the loading collection.
557
     *
558
     * @param mongoSession the MongoDB client session
559
     * @return the calculated trust state hash
560
     */
561
    public static String calculateTrustStateHash(ClientSession mongoSession) {
562
        MongoCursor<Document> tp = collection("trustPaths_loading").find(mongoSession).sort(ascending("_id")).cursor();
×
563
        // TODO Improve this so we don't create the full string just for calculating its hash:
564
        String s = "";
×
565
        while (tp.hasNext()) {
×
566
            Document d = tp.next();
×
567
            s += d.getString("_id") + " (" + d.getString("type") + ")\n";
×
568
        }
×
569
        return Utils.getHash(s);
×
570
    }
571

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