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

knowledgepixels / nanodash / 19366908152

14 Nov 2025 02:02PM UTC coverage: 14.317% (+0.4%) from 13.87%
19366908152

push

github

tkuhn
feat: "refresh-upon-publish" PublishPage param to force cache refreshing

546 of 4776 branches covered (11.43%)

Branch coverage included in aggregate %.

1401 of 8823 relevant lines covered (15.88%)

0.71 hits per line

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

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

3
import static com.knowledgepixels.nanodash.Utils.vf;
4

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

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

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

34
import jakarta.xml.bind.DatatypeConverter;
35

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

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

43
    /**
44
     * The predicate to assign the admins of the space.
45
     */
46
    public static final IRI HAS_ADMIN = vf.createIRI("https://w3id.org/kpxl/gen/terms/hasAdmin");
4✔
47

48
    /**
49
     * The predicate for pinned templates in the space.
50
     */
51
    public static final IRI HAS_PINNED_TEMPLATE = vf.createIRI("https://w3id.org/kpxl/gen/terms/hasPinnedTemplate");
4✔
52

53
    /**
54
     * The predicate for pinned queries in the space.
55
     */
56
    public static final IRI HAS_PINNED_QUERY = vf.createIRI("https://w3id.org/kpxl/gen/terms/hasPinnedQuery");
4✔
57

58
    private static List<Space> spaceList;
59
    private static Map<String, List<Space>> spaceListByType;
60
    private static Map<String, Space> spacesByCoreInfo = new HashMap<>();
4✔
61
    private static Map<String, Space> spacesById;
62
    private static Map<Space, Set<Space>> subspaceMap;
63
    private static Map<Space, Set<Space>> superspaceMap;
64
    private static boolean loaded = false;
2✔
65
    private static Long runRootUpdateAfter = null;
3✔
66

67
    /**
68
     * Refresh the list of spaces from the API response.
69
     *
70
     * @param resp The API response containing space data.
71
     */
72
    public static synchronized void refresh(ApiResponse resp) {
73
        spaceList = new ArrayList<>();
4✔
74
        spaceListByType = new HashMap<>();
4✔
75
        Map<String, Space> prevSpacesByCoreInfoPrev = spacesByCoreInfo;
2✔
76
        spacesByCoreInfo = new HashMap<>();
4✔
77
        spacesById = new HashMap<>();
4✔
78
        subspaceMap = new HashMap<>();
4✔
79
        superspaceMap = new HashMap<>();
4✔
80
        for (ApiResponseEntry entry : resp.getData()) {
11✔
81
            Space space = new Space(entry);
5✔
82
            Space prevSpace = prevSpacesByCoreInfoPrev.get(space.getCoreInfoString());
6✔
83
            if (prevSpace != null) space = prevSpace;
4✔
84
            spaceList.add(space);
4✔
85
            spaceListByType.computeIfAbsent(space.getType(), k -> new ArrayList<>()).add(space);
13✔
86
            spacesByCoreInfo.put(space.getCoreInfoString(), space);
6✔
87
            spacesById.put(space.getId(), space);
6✔
88
        }
1✔
89
        for (Space space : spaceList) {
10✔
90
            Space superSpace = space.getIdSuperspace();
3✔
91
            if (superSpace == null) continue;
3✔
92
            subspaceMap.computeIfAbsent(superSpace, k -> new HashSet<>()).add(space);
12✔
93
            superspaceMap.computeIfAbsent(space, k -> new HashSet<>()).add(superSpace);
12✔
94
        }
1✔
95
        loaded = true;
2✔
96
    }
1✔
97

98
    /**
99
     * Check if the spaces have been loaded.
100
     *
101
     * @return true if loaded, false otherwise.
102
     */
103
    public static boolean isLoaded() {
104
        return loaded;
×
105
    }
106

107
    public static boolean areAllSpacesInitialized() {
108
        for (Space space : spaceList) {
×
109
            if (!space.isDataInitialized()) return false;
×
110
        }
×
111
        return true;
×
112
    }
113

114
    public static void triggerAllDataUpdates() {
115
        for (Space space : spaceList) {
×
116
            space.triggerDataUpdate();
×
117
        }
×
118
    }
×
119

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

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

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

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

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

177
    /**
178
     * Mark all spaces as needing a data update.
179
     */
180
    public static void refresh() {
181
        refresh(QueryApiAccess.forcedGet(new QueryRef("get-spaces")));
6✔
182
        for (Space space : spaceList) {
10✔
183
            space.dataNeedsUpdate = true;
3✔
184
        }
1✔
185
    }
1✔
186

187
    public void forceRefresh(long waitMillis) {
188
        dataNeedsUpdate = true;
×
189
        dataInitialized = false;
×
190
        runUpdateAfter = System.currentTimeMillis() + waitMillis;
×
191
    }
×
192

193
    private String id, label, rootNanopubId, type;
194
    private Nanopub rootNanopub = null;
3✔
195
    private SpaceData data = new SpaceData();
5✔
196

197
    private static class SpaceData implements Serializable {
2✔
198

199
        List<String> altIds = new ArrayList<>();
5✔
200

201
        String description = null;
3✔
202
        Calendar startDate, endDate;
203
        IRI defaultProvenance = null;
3✔
204

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

210
        Map<String, IRI> adminPubkeyMap = new HashMap<>();
5✔
211
        Set<Serializable> pinnedResources = new HashSet<>();
5✔
212
        List<ViewDisplay> topLevelViews = new ArrayList<>();
5✔
213
        List<ViewDisplay> partLevelViews = new ArrayList<>();
5✔
214
        Set<String> pinGroupTags = new HashSet<>();
5✔
215
        Map<String, Set<Serializable>> pinnedResourceMap = new HashMap<>();
6✔
216

217
        void addAdmin(IRI admin) {
218
            // TODO This isn't efficient for long owner lists:
219
            if (admins.contains(admin)) return;
5!
220
            admins.add(admin);
5✔
221
            UserData ud = User.getUserData();
2✔
222
            for (String pubkeyhash : ud.getPubkeyhashes(admin, true)) {
14✔
223
                adminPubkeyMap.put(pubkeyhash, admin);
6✔
224
            }
1✔
225
            users.computeIfAbsent(admin, (k) -> new HashSet<>()).add(SpaceMemberRole.ADMIN_ROLE);
13✔
226
        }
1✔
227

228
    }
229

230
    private boolean dataInitialized = false;
3✔
231
    private boolean dataNeedsUpdate = true;
3✔
232
    private Long runUpdateAfter = null;
3✔
233

234
    private Space(ApiResponseEntry resp) {
2✔
235
        this.id = resp.get("space");
5✔
236
        this.label = resp.get("label");
5✔
237
        this.type = resp.get("type");
5✔
238
        this.rootNanopubId = resp.get("np");
5✔
239
        this.rootNanopub = Utils.getAsNanopub(rootNanopubId);
5✔
240
        setCoreData(data);
4✔
241
    }
1✔
242

243
    /**
244
     * Get the ID of the space.
245
     *
246
     * @return The space ID.
247
     */
248
    public String getId() {
249
        return id;
3✔
250
    }
251

252
    /**
253
     * Get the root nanopublication ID of the space.
254
     *
255
     * @return The root nanopub ID.
256
     */
257
    public String getRootNanopubId() {
258
        return rootNanopubId;
×
259
    }
260

261
    /**
262
     * Get a string combining the space ID and root nanopub ID for core identification.
263
     *
264
     * @return The core info string.
265
     */
266
    public String getCoreInfoString() {
267
        return id + " " + rootNanopubId;
6✔
268
    }
269

270
    /**
271
     * Get the root nanopublication of the space.
272
     *
273
     * @return The root Nanopub object.
274
     */
275
    public Nanopub getRootNanopub() {
276
        return rootNanopub;
×
277
    }
278

279
    /**
280
     * Get the label of the space.
281
     *
282
     * @return The space label.
283
     */
284
    public String getLabel() {
285
        return label;
×
286
    }
287

288
    /**
289
     * Get the type of the space.
290
     *
291
     * @return The space type.
292
     */
293
    public String getType() {
294
        return type;
3✔
295
    }
296

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

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

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

324
    /**
325
     * Get the description of the space.
326
     *
327
     * @return The description string.
328
     */
329
    public String getDescription() {
330
        return data.description;
×
331
    }
332

333
    /**
334
     * Check if the space data has been initialized.
335
     *
336
     * @return true if initialized, false otherwise.
337
     */
338
    public boolean isDataInitialized() {
339
        triggerDataUpdate();
×
340
        return dataInitialized;
×
341
    }
342

343
    /**
344
     * Get the list of admins in this space.
345
     *
346
     * @return List of admin IRIs.
347
     */
348
    public List<IRI> getAdmins() {
349
        ensureInitialized();
×
350
        return data.admins;
×
351
    }
352

353
    /**
354
     * Get the list of members in this space.
355
     *
356
     * @return List of member IRIs.
357
     */
358
    public List<IRI> getUsers() {
359
        ensureInitialized();
×
360
        List<IRI> users = new ArrayList<IRI>(data.users.keySet());
×
361
        users.sort(User.getUserData().userComparator);
×
362
        return users;
×
363
    }
364

365
    /**
366
     * Get the roles of a specific member in this space.
367
     *
368
     * @param userId The IRI of the member.
369
     * @return Set of roles assigned to the member, or null if the member is not part of this space.
370
     */
371
    public Set<SpaceMemberRole> getMemberRoles(IRI userId) {
372
        ensureInitialized();
×
373
        return data.users.get(userId);
×
374
    }
375

376
    /**
377
     * Check if a user is a member of this space.
378
     *
379
     * @param userId The IRI of the user to check.
380
     * @return true if the user is a member, false otherwise.
381
     */
382
    public boolean isMember(IRI userId) {
383
        ensureInitialized();
×
384
        return data.users.containsKey(userId);
×
385
    }
386

387
    public boolean isAdminPubkey(String pubkey) {
388
        ensureInitialized();
×
389
        return data.adminPubkeyMap.containsKey(pubkey);
×
390
    }
391

392
    /**
393
     * Get the list of pinned resources in this space.
394
     *
395
     * @return List of pinned resources.
396
     */
397
    public Set<Serializable> getPinnedResources() {
398
        ensureInitialized();
×
399
        return data.pinnedResources;
×
400
    }
401

402
    /**
403
     * Get the set of tags used for grouping pinned resources.
404
     *
405
     * @return Set of tags.
406
     */
407
    public Set<String> getPinGroupTags() {
408
        ensureInitialized();
×
409
        return data.pinGroupTags;
×
410
    }
411

412
    /**
413
     * Get a map of pinned resources grouped by their tags.
414
     *
415
     * @return Map where keys are tags and values are lists of pinned resources (Templates or GrlcQueries).
416
     */
417
    public Map<String, Set<Serializable>> getPinnedResourceMap() {
418
        ensureInitialized();
×
419
        return data.pinnedResourceMap;
×
420
    }
421

422
    /**
423
     * Returns the view displays and their associated nanopub IDs.
424
     *
425
     * @return Map of views to nanopub IDs
426
     */
427
    public List<ViewDisplay> getTopLevelViews() {
428
        return data.topLevelViews;
×
429
    }
430

431
    public List<ViewDisplay> getPartLevelViews(Set<IRI> classes) {
432
        triggerDataUpdate();
×
433
        List<ViewDisplay> viewDisplays = new ArrayList<>();
×
434
        for (ViewDisplay v : data.partLevelViews) {
×
435
            if (v.getView().hasTargetClasses()) {
×
436
                for (IRI c : classes) {
×
437
                    if (v.getView().hasTargetClass(c)) {
×
438
                        viewDisplays.add(v);
×
439
                        break;
×
440
                    }
441
                }
×
442
            } else {
443
                viewDisplays.add(v);
×
444
            }
445
        }
×
446
        return viewDisplays;
×
447
    }
448

449
    public boolean coversElement(String elementId) {
450
        triggerDataUpdate();
×
451
        for (ViewDisplay v : data.topLevelViews) {
×
452
            if (v.getView().coversElement(elementId)) return true;
×
453
        }
×
454
        for (ViewDisplay v : data.partLevelViews) {
×
455
            if (v.getView().coversElement(elementId)) return true;
×
456
        }
×
457
        return false;
×
458
    }
459

460
    /**
461
     * Get the default provenance IRI for this space.
462
     *
463
     * @return The default provenance IRI, or null if not set.
464
     */
465
    public IRI getDefaultProvenance() {
466
        return data.defaultProvenance;
×
467
    }
468

469
    /**
470
     * Get the roles defined in this space.
471
     *
472
     * @return List of roles.
473
     */
474
    public List<SpaceMemberRole> getRoles() {
475
        return data.roles;
×
476
    }
477

478
    /**
479
     * Get the super ID of the space.
480
     *
481
     * @return Always returns null. Use getIdSuperspace() instead.
482
     */
483
    public String getSuperId() {
484
        return null;
×
485
    }
486

487
    /**
488
     * Get the superspace ID.
489
     *
490
     * @return The superspace, or null if not applicable.
491
     */
492
    public Space getIdSuperspace() {
493
        if (!id.matches("https?://[^/]+/.*/[^/]*/?")) return null;
5!
494
        String superId = id.replaceFirst("(https?://[^/]+/.*)/[^/]*/?", "$1");
6✔
495
        if (spacesById.containsKey(superId)) {
4✔
496
            return spacesById.get(superId);
5✔
497
        }
498
        return null;
2✔
499
    }
500

501
    /**
502
     * Get superspaces of this space.
503
     *
504
     * @return List of superspaces.
505
     */
506
    public List<Space> getSuperspaces() {
507
        if (superspaceMap.containsKey(this)) {
×
508
            List<Space> superspaces = new ArrayList<>(superspaceMap.get(this));
×
509
            Collections.sort(superspaces, Ordering.usingToString());
×
510
            return superspaces;
×
511
        }
512
        return new ArrayList<>();
×
513
    }
514

515
    /**
516
     * Get subspaces of this space.
517
     *
518
     * @return List of subspaces.
519
     */
520
    public List<Space> getSubspaces() {
521
        if (subspaceMap.containsKey(this)) {
×
522
            List<Space> subspaces = new ArrayList<>(subspaceMap.get(this));
×
523
            Collections.sort(subspaces, Ordering.usingToString());
×
524
            return subspaces;
×
525
        }
526
        return new ArrayList<>();
×
527
    }
528

529
    /**
530
     * Get subspaces of a specific type.
531
     *
532
     * @param type The type of subspaces to retrieve.
533
     * @return List of subspaces of the specified type.
534
     */
535
    public List<Space> getSubspaces(String type) {
536
        List<Space> l = new ArrayList<>();
×
537
        for (Space s : getSubspaces()) {
×
538
            if (s.getType().equals(type)) l.add(s);
×
539
        }
×
540
        return l;
×
541
    }
542

543
    /**
544
     * Get alternative IDs for the space.
545
     *
546
     * @return List of alternative IDs.
547
     */
548
    public List<String> getAltIDs() {
549
        return data.altIds;
×
550
    }
551

552
    private synchronized void ensureInitialized() {
553
        Thread thread = triggerDataUpdate();
×
554
        if (!dataInitialized && thread != null) {
×
555
            try {
556
                thread.join();
×
557
            } catch (InterruptedException ex) {
×
558
                logger.error("failed to join thread", ex);
×
559
            }
×
560
        }
561
    }
×
562

563
    private synchronized Thread triggerDataUpdate() {
564
        if (dataNeedsUpdate) {
×
565
            Thread thread = new Thread(() -> {
×
566
                try {
567
                    if (runUpdateAfter != null) {
×
568
                        while (System.currentTimeMillis() < runUpdateAfter) {
×
569
                            Thread.sleep(100);
×
570
                        }
571
                        runUpdateAfter = null;
×
572
                    }
573
                    SpaceData newData = new SpaceData();
×
574
                    setCoreData(newData);
×
575

576
                    newData.roles.add(SpaceMemberRole.ADMIN_ROLE);
×
577
                    newData.roleMap.put(SpaceMemberRole.HAS_ADMIN_PREDICATE, SpaceMemberRole.ADMIN_ROLE);
×
578

579
                    // TODO Improve this:
580
                    Multimap<String, String> spaceIds = ArrayListMultimap.create();
×
581
                    Multimap<String, String> resourceIds = ArrayListMultimap.create();
×
582
                    spaceIds.put("space", id);
×
583
                    resourceIds.put("resource", id);
×
584
                    for (String id : newData.altIds) {
×
585
                        spaceIds.put("space", id);
×
586
                        resourceIds.put("resource", id);
×
587
                    }
×
588

589
                    ApiResponse getAdminsResponse = QueryApiAccess.get(new QueryRef("get-admins", spaceIds));
×
590
                    boolean continueAddingAdmins = true;
×
591
                    while (continueAddingAdmins) {
×
592
                        continueAddingAdmins = false;
×
593
                        for (ApiResponseEntry r : getAdminsResponse.getData()) {
×
594
                            String pubkeyhash = r.get("pubkey");
×
595
                            if (newData.adminPubkeyMap.containsKey(pubkeyhash)) {
×
596
                                IRI adminId = Utils.vf.createIRI(r.get("admin"));
×
597
                                if (!newData.admins.contains(adminId)) {
×
598
                                    continueAddingAdmins = true;
×
599
                                    newData.addAdmin(adminId);
×
600
                                }
601
                            }
602
                        }
×
603
                    }
604
                    newData.admins.sort(User.getUserData().userComparator);
×
605

606
                    Multimap<String, String> getSpaceMemberParams = ArrayListMultimap.create(spaceIds);
×
607

608
                    for (ApiResponseEntry r : QueryApiAccess.get(new QueryRef("get-space-member-roles", spaceIds)).getData()) {
×
609
                        if (!newData.adminPubkeyMap.containsKey(r.get("pubkey"))) continue;
×
610
                        SpaceMemberRole role = new SpaceMemberRole(r);
×
611
                        newData.roles.add(role);
×
612

613
                        // TODO Handle cases of overlapping properties:
614
                        for (IRI p : role.getRegularProperties()) newData.roleMap.put(p, role);
×
615
                        for (IRI p : role.getInverseProperties()) newData.roleMap.put(p, role);
×
616

617
                        role.addRoleParams(getSpaceMemberParams);
×
618
                    }
×
619

620
                    for (ApiResponseEntry r : QueryApiAccess.get(new QueryRef("get-space-members", getSpaceMemberParams)).getData()) {
×
621
                        IRI memberId = Utils.vf.createIRI(r.get("member"));
×
622
                        SpaceMemberRole role = newData.roleMap.get(Utils.vf.createIRI(r.get("role")));
×
623
                        newData.users.computeIfAbsent(memberId, (k) -> new HashSet<>()).add(role);
×
624
                    }
×
625

626
                    for (ApiResponseEntry r : QueryApiAccess.get(new QueryRef("get-pinned-templates", spaceIds)).getData()) {
×
627
                        if (!newData.adminPubkeyMap.containsKey(r.get("pubkey"))) continue;
×
628
                        Template t = TemplateData.get().getTemplate(r.get("template"));
×
629
                        if (t == null) continue;
×
630
                        newData.pinnedResources.add(t);
×
631
                        String tag = r.get("tag");
×
632
                        if (tag != null && !tag.isEmpty()) {
×
633
                            newData.pinGroupTags.add(r.get("tag"));
×
634
                            newData.pinnedResourceMap.computeIfAbsent(tag, k -> new HashSet<>()).add(TemplateData.get().getTemplate(r.get("template")));
×
635
                        }
636
                    }
×
637
                    for (ApiResponseEntry r : QueryApiAccess.get(new QueryRef("get-pinned-queries", spaceIds)).getData()) {
×
638
                        if (!newData.adminPubkeyMap.containsKey(r.get("pubkey"))) continue;
×
639
                        GrlcQuery query = GrlcQuery.get(r.get("query"));
×
640
                        if (query == null) continue;
×
641
                        newData.pinnedResources.add(query);
×
642
                        String tag = r.get("tag");
×
643
                        if (tag != null && !tag.isEmpty()) {
×
644
                            newData.pinGroupTags.add(r.get("tag"));
×
645
                            newData.pinnedResourceMap.computeIfAbsent(tag, k -> new HashSet<>()).add(query);
×
646
                        }
647
                    }
×
648
                    for (ApiResponseEntry r : QueryApiAccess.get(new QueryRef("get-view-displays", resourceIds)).getData()) {
×
649
                        if (!newData.adminPubkeyMap.containsKey(r.get("pubkey"))) continue;
×
650
                        try {
651
                            ViewDisplay vd = ViewDisplay.get(r.get("display"));
×
652
                            if (ResourceView.PART_LEVEL_VIEW_DISPLAY.stringValue().equals(r.get("displayType"))) {
×
653
                                newData.partLevelViews.add(vd);
×
654
                            } else {
655
                                newData.topLevelViews.add(vd);
×
656
                            }
657
                        } catch (IllegalArgumentException ex) {
×
658
                            logger.error("Couldn't generate view display object", ex);
×
659
                        }
×
660
                    }
×
661
                    Collections.sort(newData.topLevelViews);
×
662
                    Collections.sort(newData.partLevelViews);
×
663
                    data = newData;
×
664
                    dataInitialized = true;
×
665
                } catch (Exception ex) {
×
666
                    logger.error("Error while trying to update space data: {}", ex);
×
667
                }
×
668
            });
×
669
            thread.start();
×
670
            dataNeedsUpdate = false;
×
671
            return thread;
×
672
        }
673
        return null;
×
674
    }
675

676
    private void setCoreData(SpaceData data) {
677
        for (Statement st : rootNanopub.getAssertion()) {
12✔
678
            if (st.getSubject().stringValue().equals(getId())) {
7!
679
                if (st.getPredicate().equals(OWL.SAMEAS) && st.getObject() instanceof IRI objIri) {
14!
680
                    data.altIds.add(objIri.stringValue());
7✔
681
                } else if (st.getPredicate().equals(DCTERMS.DESCRIPTION)) {
5✔
682
                    data.description = st.getObject().stringValue();
6✔
683
                } else if (st.getPredicate().stringValue().equals("http://schema.org/startDate")) {
6✔
684
                    try {
685
                        data.startDate = DatatypeConverter.parseDateTime(st.getObject().stringValue());
6✔
686
                    } catch (IllegalArgumentException ex) {
×
687
                        logger.error("Failed to parse date {}", st.getObject().stringValue());
×
688
                    }
1✔
689
                } else if (st.getPredicate().stringValue().equals("http://schema.org/endDate")) {
6✔
690
                    try {
691
                        data.endDate = DatatypeConverter.parseDateTime(st.getObject().stringValue());
6✔
692
                    } catch (IllegalArgumentException ex) {
×
693
                        logger.error("Failed to parse date {}", st.getObject().stringValue());
×
694
                    }
1✔
695
                } else if (st.getPredicate().equals(HAS_ADMIN) && st.getObject() instanceof IRI obj) {
14!
696
                    data.addAdmin(obj);
4✔
697
                } else if (st.getPredicate().equals(HAS_PINNED_TEMPLATE) && st.getObject() instanceof IRI obj) {
5!
698
                    data.pinnedResources.add(TemplateData.get().getTemplate(obj.stringValue()));
×
699
                } else if (st.getPredicate().equals(HAS_PINNED_QUERY) && st.getObject() instanceof IRI obj) {
5!
700
                    data.pinnedResources.add(GrlcQuery.get(obj.stringValue()));
×
701
                } else if (st.getPredicate().equals(NTEMPLATE.HAS_DEFAULT_PROVENANCE) && st.getObject() instanceof IRI obj) {
5!
702
                    data.defaultProvenance = obj;
1✔
703
                }
704
            } else if (st.getPredicate().equals(NTEMPLATE.HAS_TAG) && st.getObject() instanceof Literal l) {
×
705
                data.pinGroupTags.add(l.stringValue());
×
706
                Set<Serializable> list = data.pinnedResourceMap.get(l.stringValue());
×
707
                if (list == null) {
×
708
                    list = new HashSet<>();
×
709
                    data.pinnedResourceMap.put(l.stringValue(), list);
×
710
                }
711
                list.add(TemplateData.get().getTemplate(st.getSubject().stringValue()));
×
712
            }
713
        }
1✔
714
    }
1✔
715

716
    @Override
717
    public String toString() {
718
        return id;
×
719
    }
720

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