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

knowledgepixels / nanodash / 20332936699

18 Dec 2025 09:53AM UTC coverage: 15.293% (+0.9%) from 14.405%
20332936699

push

github

tkuhn
fix(Space): Leaking Space objects fixed

592 of 5002 branches covered (11.84%)

Branch coverage included in aggregate %.

1577 of 9181 relevant lines covered (17.18%)

2.23 hits per line

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

31.9
src/main/java/com/knowledgepixels/nanodash/Space.java
1
package com.knowledgepixels.nanodash;
2

3
import java.io.Serializable;
4
import java.util.ArrayList;
5
import java.util.Calendar;
6
import java.util.Collections;
7
import java.util.HashMap;
8
import java.util.HashSet;
9
import java.util.List;
10
import java.util.Map;
11
import java.util.Set;
12

13
import org.eclipse.rdf4j.model.IRI;
14
import org.eclipse.rdf4j.model.Literal;
15
import org.eclipse.rdf4j.model.Statement;
16
import org.eclipse.rdf4j.model.vocabulary.DCTERMS;
17
import org.eclipse.rdf4j.model.vocabulary.OWL;
18
import org.nanopub.Nanopub;
19
import org.nanopub.extra.services.ApiResponse;
20
import org.nanopub.extra.services.ApiResponseEntry;
21
import org.nanopub.extra.services.QueryRef;
22
import org.nanopub.vocabulary.NTEMPLATE;
23
import org.slf4j.Logger;
24
import org.slf4j.LoggerFactory;
25

26
import com.github.jsonldjava.shaded.com.google.common.collect.Ordering;
27
import com.google.common.collect.ArrayListMultimap;
28
import com.google.common.collect.Multimap;
29
import com.knowledgepixels.nanodash.template.Template;
30
import com.knowledgepixels.nanodash.template.TemplateData;
31
import com.knowledgepixels.nanodash.vocabulary.KPXL_TERMS;
32

33
import jakarta.xml.bind.DatatypeConverter;
34

35
/**
36
 * Class representing a "Space", which can be any kind of collaborative unit, like a project, group, or event.
37
 */
38
public class Space extends ProfiledResource {
39

40
    private static final Logger logger = LoggerFactory.getLogger(Space.class);
9✔
41

42
    private static List<Space> spaceList;
43
    private static Map<String, List<Space>> spaceListByType;
44
    private static Map<String, Space> spacesByCoreInfo = new HashMap<>();
12✔
45
    private static Map<String, Space> spacesById;
46
    private static Map<Space, Set<Space>> subspaceMap;
47
    private static Map<Space, Set<Space>> superspaceMap;
48
    private static boolean loaded = false;
6✔
49
    private static Long runRootUpdateAfter = null;
9✔
50

51
    /**
52
     * Refresh the list of spaces from the API response.
53
     *
54
     * @param resp The API response containing space data.
55
     */
56
    public static synchronized void refresh(ApiResponse resp) {
57
        spaceList = new ArrayList<>();
12✔
58
        spaceListByType = new HashMap<>();
12✔
59
        Map<String, Space> prevSpacesByCoreInfoPrev = spacesByCoreInfo;
6✔
60
        spacesByCoreInfo = new HashMap<>();
12✔
61
        spacesById = new HashMap<>();
12✔
62
        subspaceMap = new HashMap<>();
12✔
63
        superspaceMap = new HashMap<>();
12✔
64
        for (ApiResponseEntry entry : resp.getData()) {
33✔
65
            String id = getCoreInfoString(entry);
9✔
66
            Space space;
67
            if (prevSpacesByCoreInfoPrev.containsKey(id)) {
12!
68
                space = prevSpacesByCoreInfoPrev.get(id);
×
69
            } else {
70
                space = new Space(entry);
15✔
71
            }
72
            spaceList.add(space);
12✔
73
            spaceListByType.computeIfAbsent(space.getType(), k -> new ArrayList<>()).add(space);
39✔
74
            spacesByCoreInfo.put(space.getCoreInfoString(), space);
18✔
75
            spacesById.put(space.getId(), space);
18✔
76
        }
3✔
77
        for (Space space : spaceList) {
30✔
78
            Space superSpace = space.getIdSuperspace();
9✔
79
            if (superSpace == null) continue;
9✔
80
            subspaceMap.computeIfAbsent(superSpace, k -> new HashSet<>()).add(space);
36✔
81
            superspaceMap.computeIfAbsent(space, k -> new HashSet<>()).add(superSpace);
36✔
82
            space.setDataNeedsUpdate();
6✔
83
        }
3✔
84
        loaded = true;
6✔
85
    }
3✔
86

87
    /**
88
     * Check if the spaces have been loaded.
89
     *
90
     * @return true if loaded, false otherwise.
91
     */
92
    public static boolean isLoaded() {
93
        return loaded;
×
94
    }
95

96
    public static boolean areAllSpacesInitialized() {
97
        for (Space space : spaceList) {
×
98
            if (!space.isDataInitialized()) return false;
×
99
        }
×
100
        return true;
×
101
    }
102

103
    @Override
104
    public boolean isDataInitialized() {
105
        triggerDataUpdate();
×
106
        return dataInitialized && super.isDataInitialized();
×
107
    }
108

109
    public static void triggerAllDataUpdates() {
110
        for (Space space : spaceList) {
×
111
            space.triggerDataUpdate();
×
112
        }
×
113
    }
×
114

115
    private static final String ensureLoadedLock = "";
116

117
    /**
118
     * Ensure that the spaces are loaded, fetching them from the API if necessary.
119
     */
120
    public static void ensureLoaded() {
121
        if (spaceList == null) {
6!
122
            try {
123
                synchronized (ensureLoadedLock) {
×
124
                    if (runRootUpdateAfter != null) {
×
125
                        while (System.currentTimeMillis() < runRootUpdateAfter) {
×
126
                            Thread.sleep(100);
×
127
                        }
128
                        runRootUpdateAfter = null;
×
129
                    }
130
                }
×
131
            } catch (InterruptedException ex) {
×
132
                logger.error("Interrupted", ex);
×
133
            }
×
134
            refresh(ApiCache.retrieveResponseSync(new QueryRef("get-spaces"), true));
×
135
        }
136
    }
3✔
137

138
    public static void forceRootRefresh(long waitMillis) {
139
        spaceList = null;
×
140
        runRootUpdateAfter = System.currentTimeMillis() + waitMillis;
×
141
    }
×
142

143
    /**
144
     * Get the list of all spaces.
145
     *
146
     * @return List of spaces.
147
     */
148
    public static List<Space> getSpaceList() {
149
        ensureLoaded();
×
150
        return spaceList;
×
151
    }
152

153
    /**
154
     * Get the list of spaces of a specific type.
155
     *
156
     * @param type The type of spaces to retrieve.
157
     *             System.err.println("REFRESH...");
158
     * @return List of spaces of the specified type.
159
     */
160
    public static List<Space> getSpaceList(String type) {
161
        ensureLoaded();
×
162
        return spaceListByType.computeIfAbsent(type, k -> new ArrayList<>());
×
163
    }
164

165
    /**
166
     * Get a space by its id.
167
     *
168
     * @param id The id of the space.
169
     * @return The corresponding Space object, or null if not found.
170
     */
171
    public static Space get(String id) {
172
        ensureLoaded();
3✔
173
        return spacesById.get(id);
15✔
174
    }
175

176
    /**
177
     * Mark all spaces as needing a data update.
178
     */
179
    public static void refresh() {
180
        refresh(ApiCache.retrieveResponseSync(new QueryRef("get-spaces"), true));
21✔
181
        for (Space space : spaceList) {
30✔
182
            space.dataNeedsUpdate = true;
9✔
183
        }
3✔
184
    }
3✔
185

186
    public void forceRefresh(long waitMillis) {
187
        super.forceRefresh(waitMillis);
×
188
        dataNeedsUpdate = true;
×
189
        dataInitialized = false;
×
190
    }
×
191

192
    private String label, rootNanopubId, type;
193
    private Nanopub rootNanopub = null;
9✔
194
    private SpaceData data = new SpaceData();
15✔
195

196
    private static class SpaceData implements Serializable {
6✔
197

198
        List<String> altIds = new ArrayList<>();
15✔
199

200
        String description = null;
9✔
201
        Calendar startDate, endDate;
202
        IRI defaultProvenance = null;
9✔
203

204
        List<IRI> admins = new ArrayList<>();
15✔
205
        Map<IRI, Set<SpaceMemberRoleRef>> users = new HashMap<>();
15✔
206
        List<SpaceMemberRoleRef> roles = new ArrayList<>();
15✔
207
        Map<IRI, SpaceMemberRole> roleMap = new HashMap<>();
15✔
208

209
        Map<String, IRI> adminPubkeyMap = new HashMap<>();
15✔
210
        Set<Serializable> pinnedResources = new HashSet<>();
15✔
211
        Set<String> pinGroupTags = new HashSet<>();
15✔
212
        Map<String, Set<Serializable>> pinnedResourceMap = new HashMap<>();
18✔
213

214
        void addAdmin(IRI admin, String npId) {
215
            // TODO This isn't efficient for long owner lists:
216
            if (admins.contains(admin)) return;
15!
217
            admins.add(admin);
15✔
218
            UserData ud = User.getUserData();
6✔
219
            for (String pubkeyhash : ud.getPubkeyhashes(admin, true)) {
42✔
220
                adminPubkeyMap.put(pubkeyhash, admin);
18✔
221
            }
3✔
222
            users.computeIfAbsent(admin, (k) -> new HashSet<>()).add(new SpaceMemberRoleRef(SpaceMemberRole.ADMIN_ROLE, npId));
51✔
223
        }
3✔
224

225
    }
226

227
    private static String getCoreInfoString(ApiResponseEntry resp) {
228
        String id = resp.get("space");
12✔
229
        String rootNanopubId = resp.get("np");
12✔
230
        return id + " " + rootNanopubId;
12✔
231
    }
232

233
    private boolean dataInitialized = false;
9✔
234
    private boolean dataNeedsUpdate = true;
9✔
235

236
    private Space(ApiResponseEntry resp) {
237
        super(resp.get("space"));
15✔
238
        initSpace(this);
9✔
239
        this.label = resp.get("label");
15✔
240
        this.type = resp.get("type");
15✔
241
        this.rootNanopubId = resp.get("np");
15✔
242
        this.rootNanopub = Utils.getAsNanopub(rootNanopubId);
15✔
243
        setCoreData(data);
12✔
244
    }
3✔
245

246
    /**
247
     * Get the root nanopublication ID of the space.
248
     *
249
     * @return The root nanopub ID.
250
     */
251
    @Override
252
    public String getNanopubId() {
253
        return rootNanopubId;
×
254
    }
255

256
    /**
257
     * Get a string combining the space ID and root nanopub ID for core identification.
258
     *
259
     * @return The core info string.
260
     */
261
    public String getCoreInfoString() {
262
        return getId() + " " + rootNanopubId;
18✔
263
    }
264

265
    /**
266
     * Get the root nanopublication of the space.
267
     *
268
     * @return The root Nanopub object.
269
     */
270
    @Override
271
    public Nanopub getNanopub() {
272
        return rootNanopub;
×
273
    }
274

275
    /**
276
     * Get the label of the space.
277
     *
278
     * @return The space label.
279
     */
280
    public String getLabel() {
281
        return label;
×
282
    }
283

284
    /**
285
     * Get the type of the space.
286
     *
287
     * @return The space type.
288
     */
289
    public String getType() {
290
        return type;
9✔
291
    }
292

293
    /**
294
     * Get the start date of the space.
295
     *
296
     * @return The start date as a Calendar object, or null if not set.
297
     */
298
    public Calendar getStartDate() {
299
        return data.startDate;
×
300
    }
301

302
    /**
303
     * Get the end date of the space.
304
     *
305
     * @return The end date as a Calendar object, or null if not set.
306
     */
307
    public Calendar getEndDate() {
308
        return data.endDate;
×
309
    }
310

311
    /**
312
     * Get a simplified label for the type of space by removing any namespace prefix.
313
     *
314
     * @return The simplified type label.
315
     */
316
    public String getTypeLabel() {
317
        return type.replaceFirst("^.*/", "");
×
318
    }
319

320
    /**
321
     * Get the description of the space.
322
     *
323
     * @return The description string.
324
     */
325
    public String getDescription() {
326
        return data.description;
×
327
    }
328

329

330
    /**
331
     * Get the list of admins in this space.
332
     *
333
     * @return List of admin IRIs.
334
     */
335
    public List<IRI> getAdmins() {
336
        ensureInitialized();
×
337
        return data.admins;
×
338
    }
339

340
    /**
341
     * Get the list of members in this space.
342
     *
343
     * @return List of member IRIs.
344
     */
345
    public List<IRI> getUsers() {
346
        ensureInitialized();
×
347
        List<IRI> users = new ArrayList<IRI>(data.users.keySet());
×
348
        users.sort(User.getUserData().userComparator);
×
349
        return users;
×
350
    }
351

352
    /**
353
     * Get the roles of a specific member in this space.
354
     *
355
     * @param userId The IRI of the member.
356
     * @return Set of roles assigned to the member, or null if the member is not part of this space.
357
     */
358
    public Set<SpaceMemberRoleRef> getMemberRoles(IRI userId) {
359
        ensureInitialized();
×
360
        return data.users.get(userId);
×
361
    }
362

363
    /**
364
     * Check if a user is a member of this space.
365
     *
366
     * @param userId The IRI of the user to check.
367
     * @return true if the user is a member, false otherwise.
368
     */
369
    public boolean isMember(IRI userId) {
370
        ensureInitialized();
×
371
        return data.users.containsKey(userId);
×
372
    }
373

374
    public boolean isAdminPubkey(String pubkey) {
375
        ensureInitialized();
×
376
        return data.adminPubkeyMap.containsKey(pubkey);
×
377
    }
378

379
    /**
380
     * Get the list of pinned resources in this space.
381
     *
382
     * @return List of pinned resources.
383
     */
384
    public Set<Serializable> getPinnedResources() {
385
        ensureInitialized();
×
386
        return data.pinnedResources;
×
387
    }
388

389
    /**
390
     * Get the set of tags used for grouping pinned resources.
391
     *
392
     * @return Set of tags.
393
     */
394
    public Set<String> getPinGroupTags() {
395
        ensureInitialized();
×
396
        return data.pinGroupTags;
×
397
    }
398

399
    /**
400
     * Get a map of pinned resources grouped by their tags.
401
     *
402
     * @return Map where keys are tags and values are lists of pinned resources (Templates or GrlcQueries).
403
     */
404
    public Map<String, Set<Serializable>> getPinnedResourceMap() {
405
        ensureInitialized();
×
406
        return data.pinnedResourceMap;
×
407
    }
408

409
    public boolean appliesTo(String elementId, Set<IRI> classes) {
410
        triggerDataUpdate();
×
411
        for (ViewDisplay v : getViewDisplays()) {
×
412
            if (v.appliesTo(elementId, classes)) return true;
×
413
        }
×
414
        return false;
×
415
    }
416

417
    /**
418
     * Get the default provenance IRI for this space.
419
     *
420
     * @return The default provenance IRI, or null if not set.
421
     */
422
    public IRI getDefaultProvenance() {
423
        return data.defaultProvenance;
×
424
    }
425

426
    /**
427
     * Get the roles defined in this space.
428
     *
429
     * @return List of roles.
430
     */
431
    public List<SpaceMemberRoleRef> getRoles() {
432
        return data.roles;
×
433
    }
434

435
    /**
436
     * Get the super ID of the space.
437
     *
438
     * @return Always returns null. Use getIdSuperspace() instead.
439
     */
440
    public String getSuperId() {
441
        return null;
×
442
    }
443

444
    /**
445
     * Get the superspace ID.
446
     *
447
     * @return The superspace, or null if not applicable.
448
     */
449
    public Space getIdSuperspace() {
450
        if (!getId().matches("https?://[^/]+/.*/[^/]*/?")) return null;
15!
451
        String superId = getId().replaceFirst("(https?://[^/]+/.*)/[^/]*/?", "$1");
18✔
452
        if (spacesById.containsKey(superId)) {
12✔
453
            return spacesById.get(superId);
15✔
454
        }
455
        return null;
6✔
456
    }
457

458
    /**
459
     * Get superspaces of this space.
460
     *
461
     * @return List of superspaces.
462
     */
463
    public List<Space> getSuperspaces() {
464
        if (superspaceMap.containsKey(this)) {
×
465
            List<Space> superspaces = new ArrayList<>(superspaceMap.get(this));
×
466
            Collections.sort(superspaces, Ordering.usingToString());
×
467
            return superspaces;
×
468
        }
469
        return new ArrayList<>();
×
470
    }
471

472
    /**
473
     * Get subspaces of this space.
474
     *
475
     * @return List of subspaces.
476
     */
477
    public List<Space> getSubspaces() {
478
        if (subspaceMap.containsKey(this)) {
×
479
            List<Space> subspaces = new ArrayList<>(subspaceMap.get(this));
×
480
            Collections.sort(subspaces, Ordering.usingToString());
×
481
            return subspaces;
×
482
        }
483
        return new ArrayList<>();
×
484
    }
485

486
    /**
487
     * Get subspaces of a specific type.
488
     *
489
     * @param type The type of subspaces to retrieve.
490
     * @return List of subspaces of the specified type.
491
     */
492
    public List<Space> getSubspaces(String type) {
493
        List<Space> l = new ArrayList<>();
×
494
        for (Space s : getSubspaces()) {
×
495
            if (s.getType().equals(type)) l.add(s);
×
496
        }
×
497
        return l;
×
498
    }
499

500
    /**
501
     * Get alternative IDs for the space.
502
     *
503
     * @return List of alternative IDs.
504
     */
505
    public List<String> getAltIDs() {
506
        return data.altIds;
×
507
    }
508

509
    private synchronized void ensureInitialized() {
510
        Thread thread = triggerSpaceDataUpdate();
×
511
        if (!dataInitialized && thread != null) {
×
512
            try {
513
                thread.join();
×
514
            } catch (InterruptedException ex) {
×
515
                logger.error("failed to join thread", ex);
×
516
            }
×
517
        }
518
        thread = super.triggerDataUpdate();
×
519
        if (!dataInitialized && thread != null) {
×
520
            try {
521
                thread.join();
×
522
            } catch (InterruptedException ex) {
×
523
                logger.error("failed to join thread", ex);
×
524
            }
×
525
        }
526
    }
×
527

528
    @Override
529
    public synchronized Thread triggerDataUpdate() {
530
        triggerSpaceDataUpdate();
×
531
        return super.triggerDataUpdate();
×
532
    }
533

534
    private synchronized Thread triggerSpaceDataUpdate() {
535
        if (dataNeedsUpdate) {
×
536
            Thread thread = new Thread(() -> {
×
537
                try {
538
                    if (getRunUpdateAfter() != null) {
×
539
                        while (System.currentTimeMillis() < getRunUpdateAfter()) {
×
540
                            Thread.sleep(100);
×
541
                        }
542
                    }
543
                    SpaceData newData = new SpaceData();
×
544
                    setCoreData(newData);
×
545

546
                    newData.roles.add(new SpaceMemberRoleRef(SpaceMemberRole.ADMIN_ROLE, null));
×
547
                    newData.roleMap.put(KPXL_TERMS.HAS_ADMIN_PREDICATE, SpaceMemberRole.ADMIN_ROLE);
×
548

549
                    // TODO Improve this:
550
                    Multimap<String, String> spaceIds = ArrayListMultimap.create();
×
551
                    Multimap<String, String> resourceIds = ArrayListMultimap.create();
×
552
                    spaceIds.put("space", getId());
×
553
                    resourceIds.put("resource", getId());
×
554
                    for (String id : newData.altIds) {
×
555
                        spaceIds.put("space", id);
×
556
                        resourceIds.put("resource", id);
×
557
                    }
×
558

559
                    ApiResponse getAdminsResponse = ApiCache.retrieveResponseSync(new QueryRef("get-admins", spaceIds), false);
×
560
                    boolean continueAddingAdmins = true;
×
561
                    while (continueAddingAdmins) {
×
562
                        continueAddingAdmins = false;
×
563
                        for (ApiResponseEntry r : getAdminsResponse.getData()) {
×
564
                            String pubkeyhash = r.get("pubkey");
×
565
                            if (newData.adminPubkeyMap.containsKey(pubkeyhash)) {
×
566
                                IRI adminId = Utils.vf.createIRI(r.get("admin"));
×
567
                                if (!newData.admins.contains(adminId)) {
×
568
                                    continueAddingAdmins = true;
×
569
                                    newData.addAdmin(adminId, r.get("np"));
×
570
                                }
571
                            }
572
                        }
×
573
                    }
574
                    newData.admins.sort(User.getUserData().userComparator);
×
575

576
                    Multimap<String, String> getSpaceMemberParams = ArrayListMultimap.create(spaceIds);
×
577

578
                    for (ApiResponseEntry r : ApiCache.retrieveResponseSync(new QueryRef("get-space-member-roles", spaceIds), false).getData()) {
×
579
                        if (!newData.adminPubkeyMap.containsKey(r.get("pubkey"))) continue;
×
580
                        SpaceMemberRole role = new SpaceMemberRole(r);
×
581
                        newData.roles.add(new SpaceMemberRoleRef(role, r.get("np")));
×
582

583
                        // TODO Handle cases of overlapping properties:
584
                        for (IRI p : role.getRegularProperties()) newData.roleMap.put(p, role);
×
585
                        for (IRI p : role.getInverseProperties()) newData.roleMap.put(p, role);
×
586

587
                        role.addRoleParams(getSpaceMemberParams);
×
588
                    }
×
589

590
                    for (ApiResponseEntry r : ApiCache.retrieveResponseSync(new QueryRef("get-space-members", getSpaceMemberParams), false).getData()) {
×
591
                        IRI memberId = Utils.vf.createIRI(r.get("member"));
×
592
                        SpaceMemberRole role = newData.roleMap.get(Utils.vf.createIRI(r.get("role")));
×
593
                        newData.users.computeIfAbsent(memberId, (k) -> new HashSet<>()).add(new SpaceMemberRoleRef(role, r.get("np")));
×
594
                    }
×
595

596
                    for (ApiResponseEntry r : ApiCache.retrieveResponseSync(new QueryRef("get-pinned-templates", spaceIds), false).getData()) {
×
597
                        if (!newData.adminPubkeyMap.containsKey(r.get("pubkey"))) continue;
×
598
                        Template t = TemplateData.get().getTemplate(r.get("template"));
×
599
                        if (t == null) continue;
×
600
                        newData.pinnedResources.add(t);
×
601
                        String tag = r.get("tag");
×
602
                        if (tag != null && !tag.isEmpty()) {
×
603
                            newData.pinGroupTags.add(r.get("tag"));
×
604
                            newData.pinnedResourceMap.computeIfAbsent(tag, k -> new HashSet<>()).add(TemplateData.get().getTemplate(r.get("template")));
×
605
                        }
606
                    }
×
607
                    for (ApiResponseEntry r : ApiCache.retrieveResponseSync(new QueryRef("get-pinned-queries", spaceIds), false).getData()) {
×
608
                        if (!newData.adminPubkeyMap.containsKey(r.get("pubkey"))) continue;
×
609
                        GrlcQuery query = GrlcQuery.get(r.get("query"));
×
610
                        if (query == null) continue;
×
611
                        newData.pinnedResources.add(query);
×
612
                        String tag = r.get("tag");
×
613
                        if (tag != null && !tag.isEmpty()) {
×
614
                            newData.pinGroupTags.add(r.get("tag"));
×
615
                            newData.pinnedResourceMap.computeIfAbsent(tag, k -> new HashSet<>()).add(query);
×
616
                        }
617
                    }
×
618
                    data = newData;
×
619
                    dataInitialized = true;
×
620
                } catch (Exception ex) {
×
621
                    logger.error("Error while trying to update space data: {}", ex);
×
622
                }
×
623
            });
×
624
            thread.start();
×
625
            dataNeedsUpdate = false;
×
626
            return thread;
×
627
        }
628
        return null;
×
629
    }
630

631
    private void setCoreData(SpaceData data) {
632
        for (Statement st : rootNanopub.getAssertion()) {
36✔
633
            if (st.getSubject().stringValue().equals(getId())) {
21!
634
                if (st.getPredicate().equals(OWL.SAMEAS) && st.getObject() instanceof IRI objIri) {
42!
635
                    data.altIds.add(objIri.stringValue());
21✔
636
                } else if (st.getPredicate().equals(DCTERMS.DESCRIPTION)) {
15✔
637
                    data.description = st.getObject().stringValue();
18✔
638
                } else if (st.getPredicate().stringValue().equals("http://schema.org/startDate")) {
18✔
639
                    try {
640
                        data.startDate = DatatypeConverter.parseDateTime(st.getObject().stringValue());
18✔
641
                    } catch (IllegalArgumentException ex) {
×
642
                        logger.error("Failed to parse date {}", st.getObject().stringValue());
×
643
                    }
3✔
644
                } else if (st.getPredicate().stringValue().equals("http://schema.org/endDate")) {
18✔
645
                    try {
646
                        data.endDate = DatatypeConverter.parseDateTime(st.getObject().stringValue());
18✔
647
                    } catch (IllegalArgumentException ex) {
×
648
                        logger.error("Failed to parse date {}", st.getObject().stringValue());
×
649
                    }
3✔
650
                } else if (st.getPredicate().equals(KPXL_TERMS.HAS_ADMIN) && st.getObject() instanceof IRI obj) {
42!
651
                    data.addAdmin(obj, rootNanopub.getUri().stringValue());
24✔
652
                } else if (st.getPredicate().equals(KPXL_TERMS.HAS_PINNED_TEMPLATE) && st.getObject() instanceof IRI obj) {
15!
653
                    data.pinnedResources.add(TemplateData.get().getTemplate(obj.stringValue()));
×
654
                } else if (st.getPredicate().equals(KPXL_TERMS.HAS_PINNED_QUERY) && st.getObject() instanceof IRI obj) {
15!
655
                    data.pinnedResources.add(GrlcQuery.get(obj.stringValue()));
×
656
                } else if (st.getPredicate().equals(NTEMPLATE.HAS_DEFAULT_PROVENANCE) && st.getObject() instanceof IRI obj) {
15!
657
                    data.defaultProvenance = obj;
3✔
658
                }
659
            } else if (st.getPredicate().equals(NTEMPLATE.HAS_TAG) && st.getObject() instanceof Literal l) {
×
660
                data.pinGroupTags.add(l.stringValue());
×
661
                Set<Serializable> list = data.pinnedResourceMap.get(l.stringValue());
×
662
                if (list == null) {
×
663
                    list = new HashSet<>();
×
664
                    data.pinnedResourceMap.put(l.stringValue(), list);
×
665
                }
666
                list.add(TemplateData.get().getTemplate(st.getSubject().stringValue()));
×
667
            }
668
        }
3✔
669
    }
3✔
670

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