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

knowledgepixels / nanodash / 18883723711

28 Oct 2025 05:30PM UTC coverage: 13.555% (+0.07%) from 13.485%
18883723711

push

github

tkuhn
feat(MaintainedResource): Support for part-level views

483 of 4478 branches covered (10.79%)

Branch coverage included in aggregate %.

1259 of 8373 relevant lines covered (15.04%)

0.67 hits per line

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

0.0
src/main/java/com/knowledgepixels/nanodash/MaintainedResource.java
1
package com.knowledgepixels.nanodash;
2

3
import java.io.Serializable;
4
import java.util.ArrayList;
5
import java.util.HashMap;
6
import java.util.List;
7
import java.util.Map;
8
import java.util.Set;
9

10
import org.eclipse.rdf4j.model.IRI;
11
import org.nanopub.Nanopub;
12
import org.nanopub.extra.services.ApiResponse;
13
import org.nanopub.extra.services.ApiResponseEntry;
14
import org.nanopub.extra.services.QueryRef;
15
import org.slf4j.Logger;
16
import org.slf4j.LoggerFactory;
17

18
public class MaintainedResource implements Serializable {
19

20
    private static final Logger logger = LoggerFactory.getLogger(MaintainedResource.class);
×
21

22
    private static List<MaintainedResource> resourceList;
23
    private static Map<String, MaintainedResource> resourcesById;
24
    private static Map<String, MaintainedResource> resourcesByNamespace;
25
    private static Map<Space, List<MaintainedResource>> resourcesBySpace;
26
    private static boolean loaded = false;
×
27

28
    public static synchronized void refresh(ApiResponse resp) {
29
        System.err.println("REFRESH...");
×
30
        resourceList = new ArrayList<>();
×
31
        resourcesById = new HashMap<>();
×
32
        resourcesBySpace = new HashMap<>();
×
33
        resourcesByNamespace = new HashMap<>();
×
34
        for (ApiResponseEntry entry : resp.getData()) {
×
35
            Space space = Space.get(entry.get("space"));
×
36
            if (space == null) continue;
×
37
            MaintainedResource resource = new MaintainedResource(entry, space);
×
38
            if (resourcesById.containsKey(resource.getId())) continue;
×
39
            resourceList.add(resource);
×
40
            resourcesById.put(resource.getId(), resource);
×
41
            resourcesBySpace.computeIfAbsent(space, k -> new ArrayList<>()).add(resource);
×
42
            if (resource.getNamespace() != null) {
×
43
                // TODO Handle conflicts when two resources claim the same namespace:
44
                resourcesByNamespace.put(resource.getNamespace(), resource);
×
45
            }
46
        }
×
47
        loaded = true;
×
48
    }
×
49

50
    /**
51
     * Check if the resources have been loaded.
52
     *
53
     * @return true if loaded, false otherwise.
54
     */
55
    public static boolean isLoaded() {
56
        return loaded;
×
57
    }
58

59
    /**
60
     * Ensure that the resources are loaded, fetching them from the API if necessary.
61
     */
62
    public static void ensureLoaded() {
63
        if (resourceList == null) {
×
64
            refresh(QueryApiAccess.forcedGet(new QueryRef("get-maintained-resources")));
×
65
        }
66
    }
×
67

68
    /**
69
     * Get the list of all maintained resources.
70
     *
71
     * @return List of resources.
72
     */
73
    public static List<MaintainedResource> getResourceList() {
74
        ensureLoaded();
×
75
        return resourceList;
×
76
    }
77

78
    public static List<MaintainedResource> getResourcesBySpace(Space space) {
79
        return resourcesBySpace.computeIfAbsent(space, k -> new ArrayList<>());
×
80
    }
81

82
    /**
83
     * Get a maintained resource by its id.
84
     *
85
     * @param id The id of the resource.
86
     * @return The corresponding MaintainedResource object, or null if not found.
87
     */
88
    public static MaintainedResource get(String id) {
89
        ensureLoaded();
×
90
        return resourcesById.get(id);
×
91
    }
92

93
    public static MaintainedResource getByNamespace(String namespace) {
94
        return resourcesByNamespace.get(namespace);
×
95
    }
96

97
    public static String getNamespace(Object stringOrIri) {
98
        return stringOrIri.toString().replaceFirst("([#/])[^#/]+$", "$1");
×
99
    }
100

101
    public static void refresh() {
102
        ensureLoaded();
×
103
        for (MaintainedResource resource : resourceList) {
×
104
            resource.dataNeedsUpdate = true;
×
105
        }
×
106
    }
×
107

108
    private String id, label, nanopubId, namespace;
109
    private Space space;
110
    private Nanopub nanopub;
111
    private ResourceData data = new ResourceData();
×
112

113
    private boolean dataInitialized = false;
×
114
    private boolean dataNeedsUpdate = true;
×
115

116
    private static class ResourceData implements Serializable {
×
117
        List<ResourceView> topLevelViews = new ArrayList<>();
×
118
        List<ResourceView> partLevelViews = new ArrayList<>();
×
119
    }
120

121
    private MaintainedResource(ApiResponseEntry resp, Space space) {
×
122
        this.space = space;
×
123
        this.id = resp.get("resource");
×
124
        this.label = resp.get("label");
×
125
        this.nanopubId = resp.get("np");
×
126
        this.namespace = resp.get("namespace");
×
127
        if (namespace != null && namespace.isBlank()) namespace = null;
×
128
        this.nanopub = Utils.getAsNanopub(nanopubId);
×
129
    }
×
130

131
    public Space getSpace() {
132
        return space;
×
133
    }
134

135
    public String getId() {
136
        return id;
×
137
    }
138

139
    public String getNanopubId() {
140
        return nanopubId;
×
141
    }
142

143
    public Nanopub getNanopub() {
144
        return nanopub;
×
145
    }
146

147
    public String getLabel() {
148
        return label;
×
149
    }
150

151
    public String getNamespace() {
152
        return namespace;
×
153
    }
154

155
    public boolean isDataInitialized() {
156
        triggerDataUpdate();
×
157
        return dataInitialized;
×
158
    }
159

160
    public List<ResourceView> getTopLevelViews() {
161
        triggerDataUpdate();
×
162
        // TODO Check for compliance with target classes here too:
163
        return data.topLevelViews;
×
164
    }
165

166
    public List<ResourceView> getPartLevelViews(Set<IRI> classes) {
167
        triggerDataUpdate();
×
168
        List<ResourceView> views = new ArrayList<>();
×
169
        for (ResourceView v : data.partLevelViews) {
×
170
            if (v.hasTargetClasses()) {
×
171
                for (IRI c : classes) {
×
172
                    if (v.hasTargetClass(c)) {
×
173
                        views.add(v);
×
174
                        break;
×
175
                    }
176
                }
×
177
            } else {
178
                views.add(v);
×
179
            }
180
        }
×
181
        return views;
×
182
    }
183

184
    private synchronized void triggerDataUpdate() {
185
        if (dataNeedsUpdate) {
×
186
            new Thread(() -> {
×
187
                try {
188
                    ResourceData newData = new ResourceData();
×
189

190
                    for (ApiResponseEntry r : QueryApiAccess.get(new QueryRef("get-view-displays", "resource", id)).getData()) {
×
191
                        if (!space.isAdminPubkey(r.get("pubkey"))) continue;
×
192
                        ResourceView view = ResourceView.get(r.get("view"));
×
193
                        if (view == null) continue;
×
194
                        if (ResourceView.PART_LEVEL_VIEW_DISPLAY.stringValue().equals(r.get("displayType"))) {
×
195
                            newData.partLevelViews.add(view);
×
196
                        } else {
197
                            newData.topLevelViews.add(view);
×
198
                        }
199
                    }
×
200
                    data = newData;
×
201
                    dataInitialized = true;
×
202
                } catch (Exception ex) {
×
203
                    logger.error("Error while trying to update space data: {}", ex);
×
204
                    dataNeedsUpdate = true;
×
205
                }
×
206
            }).start();
×
207
            dataNeedsUpdate = false;
×
208
        }
209
    }
×
210

211
    @Override
212
    public String toString() {
213
        return id;
×
214
    }
215

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