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

knowledgepixels / nanodash / 19765556252

28 Nov 2025 01:43PM UTC coverage: 14.068% (-0.3%) from 14.373%
19765556252

push

github

tkuhn
feat(ResourceView): Support new appliesToInstancesOf/Namespace preds

522 of 4868 branches covered (10.72%)

Branch coverage included in aggregate %.

1419 of 8929 relevant lines covered (15.89%)

0.7 hits per line

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

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

3
import com.github.jsonldjava.shaded.com.google.common.collect.Ordering;
4
import com.google.common.collect.ArrayListMultimap;
5
import com.google.common.collect.Multimap;
6
import com.knowledgepixels.nanodash.template.Template;
7
import com.knowledgepixels.nanodash.template.TemplateData;
8
import com.knowledgepixels.nanodash.vocabulary.KPXL_TERMS;
9
import jakarta.xml.bind.DatatypeConverter;
10
import org.apache.commons.lang3.tuple.Pair;
11
import org.eclipse.rdf4j.model.IRI;
12
import org.eclipse.rdf4j.model.Literal;
13
import org.eclipse.rdf4j.model.Statement;
14
import org.eclipse.rdf4j.model.vocabulary.DCTERMS;
15
import org.eclipse.rdf4j.model.vocabulary.OWL;
16
import org.nanopub.Nanopub;
17
import org.nanopub.extra.services.ApiResponse;
18
import org.nanopub.extra.services.ApiResponseEntry;
19
import org.nanopub.extra.services.QueryRef;
20
import org.nanopub.vocabulary.NTEMPLATE;
21
import org.slf4j.Logger;
22
import org.slf4j.LoggerFactory;
23

24
import java.io.Serializable;
25
import java.util.*;
26

27
/**
28
 * Class representing a "Space", which can be any kind of collaborative unit, like a project, group, or event.
29
 */
30
public class Space implements Serializable {
31

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

34
    private static List<Space> spaceList;
35
    private static Map<String, List<Space>> spaceListByType;
36
    private static Map<String, Space> spacesByCoreInfo = new HashMap<>();
4✔
37
    private static Map<String, Space> spacesById;
38
    private static Map<Space, Set<Space>> subspaceMap;
39
    private static Map<Space, Set<Space>> superspaceMap;
40
    private static boolean loaded = false;
2✔
41
    private static Long runRootUpdateAfter = null;
3✔
42

43
    /**
44
     * Refresh the list of spaces from the API response.
45
     *
46
     * @param resp The API response containing space data.
47
     */
48
    public static synchronized void refresh(ApiResponse resp) {
49
        spaceList = new ArrayList<>();
4✔
50
        spaceListByType = new HashMap<>();
4✔
51
        Map<String, Space> prevSpacesByCoreInfoPrev = spacesByCoreInfo;
2✔
52
        spacesByCoreInfo = new HashMap<>();
4✔
53
        spacesById = new HashMap<>();
4✔
54
        subspaceMap = new HashMap<>();
4✔
55
        superspaceMap = new HashMap<>();
4✔
56
        for (ApiResponseEntry entry : resp.getData()) {
11✔
57
            Space space = new Space(entry);
5✔
58
            Space prevSpace = prevSpacesByCoreInfoPrev.get(space.getCoreInfoString());
6✔
59
            if (prevSpace != null) space = prevSpace;
4✔
60
            spaceList.add(space);
4✔
61
            spaceListByType.computeIfAbsent(space.getType(), k -> new ArrayList<>()).add(space);
13✔
62
            spacesByCoreInfo.put(space.getCoreInfoString(), space);
6✔
63
            spacesById.put(space.getId(), space);
6✔
64
        }
1✔
65
        for (Space space : spaceList) {
10✔
66
            Space superSpace = space.getIdSuperspace();
3✔
67
            if (superSpace == null) continue;
3✔
68
            subspaceMap.computeIfAbsent(superSpace, k -> new HashSet<>()).add(space);
12✔
69
            superspaceMap.computeIfAbsent(space, k -> new HashSet<>()).add(superSpace);
12✔
70
        }
1✔
71
        loaded = true;
2✔
72
    }
1✔
73

74
    /**
75
     * Check if the spaces have been loaded.
76
     *
77
     * @return true if loaded, false otherwise.
78
     */
79
    public static boolean isLoaded() {
80
        return loaded;
×
81
    }
82

83
    public static boolean areAllSpacesInitialized() {
84
        for (Space space : spaceList) {
×
85
            if (!space.isDataInitialized()) return false;
×
86
        }
×
87
        return true;
×
88
    }
89

90
    public static void triggerAllDataUpdates() {
91
        for (Space space : spaceList) {
×
92
            space.triggerDataUpdate();
×
93
        }
×
94
    }
×
95

96
    /**
97
     * Ensure that the spaces are loaded, fetching them from the API if necessary.
98
     */
99
    public static void ensureLoaded() {
100
        if (spaceList == null) {
2✔
101
            try {
102
                if (runRootUpdateAfter != null) {
2!
103
                    while (System.currentTimeMillis() < runRootUpdateAfter) {
×
104
                        Thread.sleep(100);
×
105
                    }
106
                    runRootUpdateAfter = null;
×
107
                }
108
            } catch (InterruptedException ex) {
×
109
                logger.error("Interrupted", ex);
×
110
            }
1✔
111
            refresh(QueryApiAccess.forcedGet(new QueryRef("get-spaces")));
6✔
112
        }
113
    }
1✔
114

115
    public static void forceRootRefresh(long waitMillis) {
116
        spaceList = null;
×
117
        runRootUpdateAfter = System.currentTimeMillis() + waitMillis;
×
118
    }
×
119

120
    /**
121
     * Get the list of all spaces.
122
     *
123
     * @return List of spaces.
124
     */
125
    public static List<Space> getSpaceList() {
126
        ensureLoaded();
×
127
        return spaceList;
×
128
    }
129

130
    /**
131
     * Get the list of spaces of a specific type.
132
     *
133
     * @param type The type of spaces to retrieve.
134
     *             System.err.println("REFRESH...");
135
     * @return List of spaces of the specified type.
136
     */
137
    public static List<Space> getSpaceList(String type) {
138
        ensureLoaded();
×
139
        return spaceListByType.computeIfAbsent(type, k -> new ArrayList<>());
×
140
    }
141

142
    /**
143
     * Get a space by its id.
144
     *
145
     * @param id The id of the space.
146
     * @return The corresponding Space object, or null if not found.
147
     */
148
    public static Space get(String id) {
149
        ensureLoaded();
1✔
150
        return spacesById.get(id);
5✔
151
    }
152

153
    /**
154
     * Mark all spaces as needing a data update.
155
     */
156
    public static void refresh() {
157
        refresh(QueryApiAccess.forcedGet(new QueryRef("get-spaces")));
6✔
158
        for (Space space : spaceList) {
10✔
159
            space.dataNeedsUpdate = true;
3✔
160
        }
1✔
161
    }
1✔
162

163
    public void forceRefresh(long waitMillis) {
164
        dataNeedsUpdate = true;
×
165
        dataInitialized = false;
×
166
        runUpdateAfter = System.currentTimeMillis() + waitMillis;
×
167
    }
×
168

169
    private String id, label, rootNanopubId, type;
170
    private Nanopub rootNanopub = null;
3✔
171
    private SpaceData data = new SpaceData();
5✔
172

173
    private static class SpaceData implements Serializable {
2✔
174

175
        List<String> altIds = new ArrayList<>();
5✔
176

177
        String description = null;
3✔
178
        Calendar startDate, endDate;
179
        IRI defaultProvenance = null;
3✔
180

181
        List<IRI> admins = new ArrayList<>();
5✔
182
        // TODO Make Pair<SpaceMemberRole, String> a new class with SpaceMemberRole + nanopub URI
183
        Map<IRI, Set<Pair<SpaceMemberRole, String>>> users = new HashMap<>();
5✔
184
        List<Pair<SpaceMemberRole, String>> roles = new ArrayList<>();
5✔
185
        Map<IRI, SpaceMemberRole> roleMap = new HashMap<>();
5✔
186

187
        Map<String, IRI> adminPubkeyMap = new HashMap<>();
5✔
188
        Set<Serializable> pinnedResources = new HashSet<>();
5✔
189
        List<ViewDisplay> topLevelViews = new ArrayList<>();
5✔
190
        Set<String> topLevelViewKinds = new HashSet<>();
5✔
191
        List<ViewDisplay> partLevelViews = new ArrayList<>();
5✔
192
        Set<String> partLevelViewKinds = new HashSet<>();
5✔
193
        Set<String> pinGroupTags = new HashSet<>();
5✔
194
        Map<String, Set<Serializable>> pinnedResourceMap = new HashMap<>();
6✔
195

196
        void addAdmin(IRI admin, String npId) {
197
            // TODO This isn't efficient for long owner lists:
198
            if (admins.contains(admin)) return;
5!
199
            admins.add(admin);
5✔
200
            UserData ud = User.getUserData();
2✔
201
            for (String pubkeyhash : ud.getPubkeyhashes(admin, true)) {
14✔
202
                adminPubkeyMap.put(pubkeyhash, admin);
6✔
203
            }
1✔
204
            users.computeIfAbsent(admin, (k) -> new HashSet<>()).add(Pair.of(SpaceMemberRole.ADMIN_ROLE, npId));
15✔
205
        }
1✔
206

207
    }
208

209
    private boolean dataInitialized = false;
3✔
210
    private boolean dataNeedsUpdate = true;
3✔
211
    private Long runUpdateAfter = null;
3✔
212

213
    private Space(ApiResponseEntry resp) {
2✔
214
        this.id = resp.get("space");
5✔
215
        this.label = resp.get("label");
5✔
216
        this.type = resp.get("type");
5✔
217
        this.rootNanopubId = resp.get("np");
5✔
218
        this.rootNanopub = Utils.getAsNanopub(rootNanopubId);
5✔
219
        setCoreData(data);
4✔
220
    }
1✔
221

222
    /**
223
     * Get the ID of the space.
224
     *
225
     * @return The space ID.
226
     */
227
    public String getId() {
228
        return id;
3✔
229
    }
230

231
    /**
232
     * Get the root nanopublication ID of the space.
233
     *
234
     * @return The root nanopub ID.
235
     */
236
    public String getRootNanopubId() {
237
        return rootNanopubId;
×
238
    }
239

240
    /**
241
     * Get a string combining the space ID and root nanopub ID for core identification.
242
     *
243
     * @return The core info string.
244
     */
245
    public String getCoreInfoString() {
246
        return id + " " + rootNanopubId;
6✔
247
    }
248

249
    /**
250
     * Get the root nanopublication of the space.
251
     *
252
     * @return The root Nanopub object.
253
     */
254
    public Nanopub getRootNanopub() {
255
        return rootNanopub;
×
256
    }
257

258
    /**
259
     * Get the label of the space.
260
     *
261
     * @return The space label.
262
     */
263
    public String getLabel() {
264
        return label;
×
265
    }
266

267
    /**
268
     * Get the type of the space.
269
     *
270
     * @return The space type.
271
     */
272
    public String getType() {
273
        return type;
3✔
274
    }
275

276
    /**
277
     * Get the start date of the space.
278
     *
279
     * @return The start date as a Calendar object, or null if not set.
280
     */
281
    public Calendar getStartDate() {
282
        return data.startDate;
×
283
    }
284

285
    /**
286
     * Get the end date of the space.
287
     *
288
     * @return The end date as a Calendar object, or null if not set.
289
     */
290
    public Calendar getEndDate() {
291
        return data.endDate;
×
292
    }
293

294
    /**
295
     * Get a simplified label for the type of space by removing any namespace prefix.
296
     *
297
     * @return The simplified type label.
298
     */
299
    public String getTypeLabel() {
300
        return type.replaceFirst("^.*/", "");
×
301
    }
302

303
    /**
304
     * Get the description of the space.
305
     *
306
     * @return The description string.
307
     */
308
    public String getDescription() {
309
        return data.description;
×
310
    }
311

312
    /**
313
     * Check if the space data has been initialized.
314
     *
315
     * @return true if initialized, false otherwise.
316
     */
317
    public boolean isDataInitialized() {
318
        triggerDataUpdate();
×
319
        return dataInitialized;
×
320
    }
321

322
    /**
323
     * Get the list of admins in this space.
324
     *
325
     * @return List of admin IRIs.
326
     */
327
    public List<IRI> getAdmins() {
328
        ensureInitialized();
×
329
        return data.admins;
×
330
    }
331

332
    /**
333
     * Get the list of members in this space.
334
     *
335
     * @return List of member IRIs.
336
     */
337
    public List<IRI> getUsers() {
338
        ensureInitialized();
×
339
        List<IRI> users = new ArrayList<IRI>(data.users.keySet());
×
340
        users.sort(User.getUserData().userComparator);
×
341
        return users;
×
342
    }
343

344
    /**
345
     * Get the roles of a specific member in this space.
346
     *
347
     * @param userId The IRI of the member.
348
     * @return Set of roles assigned to the member, or null if the member is not part of this space.
349
     */
350
    public Set<Pair<SpaceMemberRole, String>> getMemberRoles(IRI userId) {
351
        ensureInitialized();
×
352
        return data.users.get(userId);
×
353
    }
354

355
    /**
356
     * Check if a user is a member of this space.
357
     *
358
     * @param userId The IRI of the user to check.
359
     * @return true if the user is a member, false otherwise.
360
     */
361
    public boolean isMember(IRI userId) {
362
        ensureInitialized();
×
363
        return data.users.containsKey(userId);
×
364
    }
365

366
    public boolean isAdminPubkey(String pubkey) {
367
        ensureInitialized();
×
368
        return data.adminPubkeyMap.containsKey(pubkey);
×
369
    }
370

371
    /**
372
     * Get the list of pinned resources in this space.
373
     *
374
     * @return List of pinned resources.
375
     */
376
    public Set<Serializable> getPinnedResources() {
377
        ensureInitialized();
×
378
        return data.pinnedResources;
×
379
    }
380

381
    /**
382
     * Get the set of tags used for grouping pinned resources.
383
     *
384
     * @return Set of tags.
385
     */
386
    public Set<String> getPinGroupTags() {
387
        ensureInitialized();
×
388
        return data.pinGroupTags;
×
389
    }
390

391
    /**
392
     * Get a map of pinned resources grouped by their tags.
393
     *
394
     * @return Map where keys are tags and values are lists of pinned resources (Templates or GrlcQueries).
395
     */
396
    public Map<String, Set<Serializable>> getPinnedResourceMap() {
397
        ensureInitialized();
×
398
        return data.pinnedResourceMap;
×
399
    }
400

401
    /**
402
     * Returns the view displays and their associated nanopub IDs.
403
     *
404
     * @return Map of views to nanopub IDs
405
     */
406
    public List<ViewDisplay> getTopLevelViews() {
407
        return data.topLevelViews;
×
408
    }
409

410
    public List<ViewDisplay> getPartLevelViews(Set<IRI> classes) {
411
        triggerDataUpdate();
×
412
        List<ViewDisplay> viewDisplays = new ArrayList<>();
×
413
        for (ViewDisplay v : data.partLevelViews) {
×
414
            if (v.getView().appliesToClasses()) {
×
415
                for (IRI c : classes) {
×
416
                    if (v.getView().appliesToClass(c)) {
×
417
                        viewDisplays.add(v);
×
418
                        break;
×
419
                    }
420
                }
×
421
            } else {
422
                viewDisplays.add(v);
×
423
            }
424
        }
×
425
        return viewDisplays;
×
426
    }
427

428
    public boolean appliesTo(String elementId, Set<IRI> classes) {
429
        triggerDataUpdate();
×
430
        for (ViewDisplay v : data.topLevelViews) {
×
431
            if (v.getView().appliesTo(elementId, classes)) return true;
×
432
        }
×
433
        for (ViewDisplay v : data.partLevelViews) {
×
434
            if (v.getView().appliesTo(elementId, classes)) return true;
×
435
        }
×
436
        return false;
×
437
    }
438

439
    /**
440
     * Get the default provenance IRI for this space.
441
     *
442
     * @return The default provenance IRI, or null if not set.
443
     */
444
    public IRI getDefaultProvenance() {
445
        return data.defaultProvenance;
×
446
    }
447

448
    /**
449
     * Get the roles defined in this space.
450
     *
451
     * @return List of roles.
452
     */
453
    public List<Pair<SpaceMemberRole, String>> getRoles() {
454
        return data.roles;
×
455
    }
456

457
    /**
458
     * Get the super ID of the space.
459
     *
460
     * @return Always returns null. Use getIdSuperspace() instead.
461
     */
462
    public String getSuperId() {
463
        return null;
×
464
    }
465

466
    /**
467
     * Get the superspace ID.
468
     *
469
     * @return The superspace, or null if not applicable.
470
     */
471
    public Space getIdSuperspace() {
472
        if (!id.matches("https?://[^/]+/.*/[^/]*/?")) return null;
5!
473
        String superId = id.replaceFirst("(https?://[^/]+/.*)/[^/]*/?", "$1");
6✔
474
        if (spacesById.containsKey(superId)) {
4✔
475
            return spacesById.get(superId);
5✔
476
        }
477
        return null;
2✔
478
    }
479

480
    /**
481
     * Get superspaces of this space.
482
     *
483
     * @return List of superspaces.
484
     */
485
    public List<Space> getSuperspaces() {
486
        if (superspaceMap.containsKey(this)) {
×
487
            List<Space> superspaces = new ArrayList<>(superspaceMap.get(this));
×
488
            Collections.sort(superspaces, Ordering.usingToString());
×
489
            return superspaces;
×
490
        }
491
        return new ArrayList<>();
×
492
    }
493

494
    /**
495
     * Get subspaces of this space.
496
     *
497
     * @return List of subspaces.
498
     */
499
    public List<Space> getSubspaces() {
500
        if (subspaceMap.containsKey(this)) {
×
501
            List<Space> subspaces = new ArrayList<>(subspaceMap.get(this));
×
502
            Collections.sort(subspaces, Ordering.usingToString());
×
503
            return subspaces;
×
504
        }
505
        return new ArrayList<>();
×
506
    }
507

508
    /**
509
     * Get subspaces of a specific type.
510
     *
511
     * @param type The type of subspaces to retrieve.
512
     * @return List of subspaces of the specified type.
513
     */
514
    public List<Space> getSubspaces(String type) {
515
        List<Space> l = new ArrayList<>();
×
516
        for (Space s : getSubspaces()) {
×
517
            if (s.getType().equals(type)) l.add(s);
×
518
        }
×
519
        return l;
×
520
    }
521

522
    /**
523
     * Get alternative IDs for the space.
524
     *
525
     * @return List of alternative IDs.
526
     */
527
    public List<String> getAltIDs() {
528
        return data.altIds;
×
529
    }
530

531
    private synchronized void ensureInitialized() {
532
        Thread thread = triggerDataUpdate();
×
533
        if (!dataInitialized && thread != null) {
×
534
            try {
535
                thread.join();
×
536
            } catch (InterruptedException ex) {
×
537
                logger.error("failed to join thread", ex);
×
538
            }
×
539
        }
540
    }
×
541

542
    private synchronized Thread triggerDataUpdate() {
543
        if (dataNeedsUpdate) {
×
544
            Thread thread = new Thread(() -> {
×
545
                try {
546
                    if (runUpdateAfter != null) {
×
547
                        while (System.currentTimeMillis() < runUpdateAfter) {
×
548
                            Thread.sleep(100);
×
549
                        }
550
                        runUpdateAfter = null;
×
551
                    }
552
                    SpaceData newData = new SpaceData();
×
553
                    setCoreData(newData);
×
554

555
                    newData.roles.add(Pair.of(SpaceMemberRole.ADMIN_ROLE, null));
×
556
                    newData.roleMap.put(KPXL_TERMS.HAS_ADMIN_PREDICATE, SpaceMemberRole.ADMIN_ROLE);
×
557

558
                    // TODO Improve this:
559
                    Multimap<String, String> spaceIds = ArrayListMultimap.create();
×
560
                    Multimap<String, String> resourceIds = ArrayListMultimap.create();
×
561
                    spaceIds.put("space", id);
×
562
                    resourceIds.put("resource", id);
×
563
                    for (String id : newData.altIds) {
×
564
                        spaceIds.put("space", id);
×
565
                        resourceIds.put("resource", id);
×
566
                    }
×
567

568
                    ApiResponse getAdminsResponse = QueryApiAccess.get(new QueryRef("get-admins", spaceIds));
×
569
                    boolean continueAddingAdmins = true;
×
570
                    while (continueAddingAdmins) {
×
571
                        continueAddingAdmins = false;
×
572
                        for (ApiResponseEntry r : getAdminsResponse.getData()) {
×
573
                            String pubkeyhash = r.get("pubkey");
×
574
                            if (newData.adminPubkeyMap.containsKey(pubkeyhash)) {
×
575
                                IRI adminId = Utils.vf.createIRI(r.get("admin"));
×
576
                                if (!newData.admins.contains(adminId)) {
×
577
                                    continueAddingAdmins = true;
×
578
                                    newData.addAdmin(adminId, r.get("np"));
×
579
                                }
580
                            }
581
                        }
×
582
                    }
583
                    newData.admins.sort(User.getUserData().userComparator);
×
584

585
                    Multimap<String, String> getSpaceMemberParams = ArrayListMultimap.create(spaceIds);
×
586

587
                    for (ApiResponseEntry r : QueryApiAccess.get(new QueryRef("get-space-member-roles", spaceIds)).getData()) {
×
588
                        if (!newData.adminPubkeyMap.containsKey(r.get("pubkey"))) continue;
×
589
                        SpaceMemberRole role = new SpaceMemberRole(r);
×
590
                        newData.roles.add(Pair.of(role, r.get("np")));
×
591

592
                        // TODO Handle cases of overlapping properties:
593
                        for (IRI p : role.getRegularProperties()) newData.roleMap.put(p, role);
×
594
                        for (IRI p : role.getInverseProperties()) newData.roleMap.put(p, role);
×
595

596
                        role.addRoleParams(getSpaceMemberParams);
×
597
                    }
×
598

599
                    for (ApiResponseEntry r : QueryApiAccess.get(new QueryRef("get-space-members", getSpaceMemberParams)).getData()) {
×
600
                        IRI memberId = Utils.vf.createIRI(r.get("member"));
×
601
                        SpaceMemberRole role = newData.roleMap.get(Utils.vf.createIRI(r.get("role")));
×
602
                        newData.users.computeIfAbsent(memberId, (k) -> new HashSet<>()).add(Pair.of(role, r.get("np")));
×
603
                    }
×
604

605
                    for (ApiResponseEntry r : QueryApiAccess.get(new QueryRef("get-pinned-templates", spaceIds)).getData()) {
×
606
                        if (!newData.adminPubkeyMap.containsKey(r.get("pubkey"))) continue;
×
607
                        Template t = TemplateData.get().getTemplate(r.get("template"));
×
608
                        if (t == null) continue;
×
609
                        newData.pinnedResources.add(t);
×
610
                        String tag = r.get("tag");
×
611
                        if (tag != null && !tag.isEmpty()) {
×
612
                            newData.pinGroupTags.add(r.get("tag"));
×
613
                            newData.pinnedResourceMap.computeIfAbsent(tag, k -> new HashSet<>()).add(TemplateData.get().getTemplate(r.get("template")));
×
614
                        }
615
                    }
×
616
                    for (ApiResponseEntry r : QueryApiAccess.get(new QueryRef("get-pinned-queries", spaceIds)).getData()) {
×
617
                        if (!newData.adminPubkeyMap.containsKey(r.get("pubkey"))) continue;
×
618
                        GrlcQuery query = GrlcQuery.get(r.get("query"));
×
619
                        if (query == null) continue;
×
620
                        newData.pinnedResources.add(query);
×
621
                        String tag = r.get("tag");
×
622
                        if (tag != null && !tag.isEmpty()) {
×
623
                            newData.pinGroupTags.add(r.get("tag"));
×
624
                            newData.pinnedResourceMap.computeIfAbsent(tag, k -> new HashSet<>()).add(query);
×
625
                        }
626
                    }
×
627
                    for (ApiResponseEntry r : QueryApiAccess.get(new QueryRef("get-view-displays", resourceIds)).getData()) {
×
628
                        if (!newData.adminPubkeyMap.containsKey(r.get("pubkey"))) continue;
×
629
                        try {
630
                            ViewDisplay vd = ViewDisplay.get(r.get("display"));
×
631
                            if (KPXL_TERMS.PART_LEVEL_VIEW_DISPLAY.stringValue().equals(r.get("displayType"))) {
×
632
                                if (newData.partLevelViewKinds.contains(r.get("viewKind"))) continue;
×
633
                                newData.partLevelViewKinds.add(r.get("viewKind"));
×
634
                                if (KPXL_TERMS.DEACTIVATED_VIEW_DISPLAY.stringValue().equals(r.get("displayMode"))) continue;
×
635
                                newData.partLevelViews.add(vd);
×
636
                            } else {
637
                                if (newData.topLevelViewKinds.contains(r.get("viewKind"))) continue;
×
638
                                newData.topLevelViewKinds.add(r.get("viewKind"));
×
639
                                if (KPXL_TERMS.DEACTIVATED_VIEW_DISPLAY.stringValue().equals(r.get("displayMode"))) continue;
×
640
                                newData.topLevelViews.add(vd);
×
641
                            }
642
                        } catch (IllegalArgumentException ex) {
×
643
                            logger.error("Couldn't generate view display object", ex);
×
644
                        }
×
645
                    }
×
646
                    Collections.sort(newData.topLevelViews);
×
647
                    Collections.sort(newData.partLevelViews);
×
648
                    data = newData;
×
649
                    dataInitialized = true;
×
650
                } catch (Exception ex) {
×
651
                    logger.error("Error while trying to update space data: {}", ex);
×
652
                }
×
653
            });
×
654
            thread.start();
×
655
            dataNeedsUpdate = false;
×
656
            return thread;
×
657
        }
658
        return null;
×
659
    }
660

661
    private void setCoreData(SpaceData data) {
662
        for (Statement st : rootNanopub.getAssertion()) {
12✔
663
            if (st.getSubject().stringValue().equals(getId())) {
7!
664
                if (st.getPredicate().equals(OWL.SAMEAS) && st.getObject() instanceof IRI objIri) {
14!
665
                    data.altIds.add(objIri.stringValue());
7✔
666
                } else if (st.getPredicate().equals(DCTERMS.DESCRIPTION)) {
5✔
667
                    data.description = st.getObject().stringValue();
6✔
668
                } else if (st.getPredicate().stringValue().equals("http://schema.org/startDate")) {
6✔
669
                    try {
670
                        data.startDate = DatatypeConverter.parseDateTime(st.getObject().stringValue());
6✔
671
                    } catch (IllegalArgumentException ex) {
×
672
                        logger.error("Failed to parse date {}", st.getObject().stringValue());
×
673
                    }
1✔
674
                } else if (st.getPredicate().stringValue().equals("http://schema.org/endDate")) {
6✔
675
                    try {
676
                        data.endDate = DatatypeConverter.parseDateTime(st.getObject().stringValue());
6✔
677
                    } catch (IllegalArgumentException ex) {
×
678
                        logger.error("Failed to parse date {}", st.getObject().stringValue());
×
679
                    }
1✔
680
                } else if (st.getPredicate().equals(KPXL_TERMS.HAS_ADMIN) && st.getObject() instanceof IRI obj) {
14!
681
                    data.addAdmin(obj, rootNanopub.getUri().stringValue());
8✔
682
                } else if (st.getPredicate().equals(KPXL_TERMS.HAS_PINNED_TEMPLATE) && st.getObject() instanceof IRI obj) {
5!
683
                    data.pinnedResources.add(TemplateData.get().getTemplate(obj.stringValue()));
×
684
                } else if (st.getPredicate().equals(KPXL_TERMS.HAS_PINNED_QUERY) && st.getObject() instanceof IRI obj) {
5!
685
                    data.pinnedResources.add(GrlcQuery.get(obj.stringValue()));
×
686
                } else if (st.getPredicate().equals(NTEMPLATE.HAS_DEFAULT_PROVENANCE) && st.getObject() instanceof IRI obj) {
5!
687
                    data.defaultProvenance = obj;
1✔
688
                }
689
            } else if (st.getPredicate().equals(NTEMPLATE.HAS_TAG) && st.getObject() instanceof Literal l) {
×
690
                data.pinGroupTags.add(l.stringValue());
×
691
                Set<Serializable> list = data.pinnedResourceMap.get(l.stringValue());
×
692
                if (list == null) {
×
693
                    list = new HashSet<>();
×
694
                    data.pinnedResourceMap.put(l.stringValue(), list);
×
695
                }
696
                list.add(TemplateData.get().getTemplate(st.getSubject().stringValue()));
×
697
            }
698
        }
1✔
699
    }
1✔
700

701
    @Override
702
    public String toString() {
703
        return id;
×
704
    }
705

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