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

knowledgepixels / nanodash / 17852532121

19 Sep 2025 08:10AM UTC coverage: 13.568% (-0.3%) from 13.87%
17852532121

push

github

tkuhn
feat: Switch to QueryRef provided by nanopub, using multimap

428 of 4008 branches covered (10.68%)

Branch coverage included in aggregate %.

1104 of 7283 relevant lines covered (15.16%)

0.68 hits per line

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

0.0
src/main/java/com/knowledgepixels/nanodash/Project.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.HashSet;
8
import java.util.List;
9
import java.util.Set;
10
import java.util.concurrent.ConcurrentHashMap;
11
import java.util.concurrent.ConcurrentMap;
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.nanopub.Nanopub;
18
import org.nanopub.extra.services.ApiResponse;
19
import org.nanopub.extra.services.ApiResponseEntry;
20
import org.nanopub.extra.services.QueryRef;
21
import org.nanopub.vocabulary.NTEMPLATE;
22

23
import com.knowledgepixels.nanodash.template.Template;
24
import com.knowledgepixels.nanodash.template.TemplateData;
25

26
/**
27
 * Class representing a Nanodash project.
28
 */
29
public class Project implements Serializable {
30

31
    private static List<Project> projectList = null;
×
32
    private static ConcurrentMap<String,Project> projectsByCoreInfo = new ConcurrentHashMap<>();
×
33
    private static ConcurrentMap<String,Project> projectsById = new ConcurrentHashMap<>();
×
34

35
    public static synchronized void refresh(ApiResponse resp) {
36
        projectList = new ArrayList<>();
×
37
        ConcurrentMap<String,Project> prevProjectsByCoreInfoPrev = projectsByCoreInfo;
×
38
        projectsByCoreInfo = new ConcurrentHashMap<>();
×
39
        projectsById.clear();
×
40
        for (ApiResponseEntry entry : resp.getData()) {
×
41
            Project project = new Project(entry.get("project"), entry.get("label"), entry.get("np"));
×
42
            Project prevProject = prevProjectsByCoreInfoPrev.get(project.getCoreInfoString());
×
43
            if (prevProject != null) project = prevProject;
×
44
            projectList.add(project);
×
45
            projectsByCoreInfo.put(project.getCoreInfoString(), project);
×
46
            projectsById.put(project.getId(), project);
×
47
        }
×
48
    }
×
49

50
    public static void ensureLoaded() {
51
        if (projectList == null) {
×
52
            refresh(QueryApiAccess.forcedGet(new QueryRef("get-projects")));
×
53
        }
54
    }
×
55

56
    public static List<Project> getProjectList() {
57
        ensureLoaded();
×
58
        return projectList;
×
59
    }
60

61
    public static Project get(String id) {
62
        ensureLoaded();
×
63
        return projectsById.get(id);
×
64
    }
65

66
    public static void refresh() {
67
        ensureLoaded();
×
68
        for (Project project : projectList) {
×
69
            project.dataNeedsUpdate = true;
×
70
        }
×
71
    }
×
72

73
    private String id, label, rootNanopubId;
74
    private Nanopub rootNanopub = null;
×
75

76
    private String description = null;
×
77
    private List<IRI> owners = new ArrayList<>();
×
78
    private List<IRI> members = new ArrayList<>();
×
79
    private ConcurrentMap<String,IRI> ownerPubkeyMap = new ConcurrentHashMap<>();
×
80
    private List<Template> templates = new ArrayList<>();
×
81
    private Set<String> templateTags = new HashSet<>();
×
82
    private ConcurrentMap<String, List<Template>> templatesPerTag = new ConcurrentHashMap<>();
×
83
    private List<IRI> queryIds = new ArrayList<>();
×
84
    private IRI defaultProvenance = null;
×
85

86
    private boolean dataInitialized = false;
×
87
    private boolean dataNeedsUpdate = true;
×
88

89
    public static final IRI HAS_OWNER = vf.createIRI("https://w3id.org/kpxl/gen/terms/hasOwner");
×
90

91
    private Project(String id, String label, String rootNanopubId) {
×
92
        this.id = id;
×
93
        this.label = label;
×
94
        this.rootNanopubId = rootNanopubId;
×
95
        this.rootNanopub = Utils.getAsNanopub(rootNanopubId);
×
96

97
        for (Statement st : rootNanopub.getAssertion()) {
×
98
            if (st.getSubject().stringValue().equals(getId())) {
×
99
                if (st.getPredicate().equals(DCTERMS.DESCRIPTION)) {
×
100
                    description = st.getObject().stringValue();
×
101
                } else if (st.getPredicate().equals(HAS_OWNER) && st.getObject() instanceof IRI obj) {
×
102
                    addOwner(obj);
×
103
                } else if (st.getPredicate().equals(Space.HAS_PINNED_TEMPLATE) && st.getObject() instanceof IRI obj) {
×
104
                    templates.add(TemplateData.get().getTemplate(obj.stringValue()));
×
105
                } else if (st.getPredicate().equals(Space.HAS_PINNED_QUERY) && st.getObject() instanceof IRI obj) {
×
106
                    queryIds.add(obj);
×
107
                } else if (st.getPredicate().equals(NTEMPLATE.HAS_DEFAULT_PROVENANCE) && st.getObject() instanceof IRI obj) {
×
108
                    defaultProvenance = obj;
×
109
                }
110
            } else if (st.getPredicate().equals(NTEMPLATE.HAS_TAG) && st.getObject() instanceof Literal l) {
×
111
                templateTags.add(l.stringValue());
×
112
                List<Template> list = templatesPerTag.get(l.stringValue());
×
113
                if (list == null) {
×
114
                    list = new ArrayList<>();
×
115
                    templatesPerTag.put(l.stringValue(), list);
×
116
                }
117
                list.add(TemplateData.get().getTemplate(st.getSubject().stringValue()));
×
118
            }
119
        }
×
120

121
    }
×
122

123
    private void addOwner(IRI owner) {
124
        // TODO This isn't efficient for long owner lists:
125
        if (owners.contains(owner)) return;
×
126
        owners.add(owner);
×
127
        UserData ud = User.getUserData();
×
128
        for (String pubkeyhash : ud.getPubkeyhashes(owner, true)) {
×
129
            ownerPubkeyMap.put(pubkeyhash, owner);
×
130
        }
×
131
    }
×
132

133
    public String getId() {
134
        return id;
×
135
    }
136

137
    public String getRootNanopubId() {
138
        return rootNanopubId;
×
139
    }
140

141
    public String getCoreInfoString() {
142
        return id + " " + rootNanopubId;
×
143
    }
144

145
    public Nanopub getRootNanopub() {
146
        return rootNanopub;
×
147
    }
148

149
    public String getLabel() {
150
        return label;
×
151
    }
152

153
    public String getDescription() {
154
        return description;
×
155
    }
156

157
    public boolean isDataInitialized() {
158
        triggerDataUpdate();
×
159
        return dataInitialized;
×
160
    }
161

162
    public List<IRI> getOwners() {
163
        triggerDataUpdate();
×
164
        return owners;
×
165
    }
166

167
    public List<IRI> getMembers() {
168
        triggerDataUpdate();
×
169
        return members;
×
170
    }
171

172
    public List<Template> getTemplates() {
173
        return templates;
×
174
    }
175

176
    public Set<String> getTemplateTags() {
177
        return templateTags;
×
178
    }
179

180
    public ConcurrentMap<String, List<Template>> getTemplatesPerTag() {
181
        return templatesPerTag;
×
182
    }
183

184
    public List<IRI> getQueryIds() {
185
        return queryIds;
×
186
    }
187

188
    public IRI getDefaultProvenance() {
189
        return defaultProvenance;
×
190
    }
191

192
    private synchronized void triggerDataUpdate() {
193
        if (dataNeedsUpdate) {
×
194
            new Thread(() -> {
×
195
                for (ApiResponseEntry r : QueryApiAccess.forcedGet(new QueryRef("get-owners", "unit", id)).getData()) {
×
196
                    String pubkeyhash = r.get("pubkeyhash");
×
197
                    if (ownerPubkeyMap.containsKey(pubkeyhash)) {
×
198
                        addOwner(Utils.vf.createIRI(r.get("owner")));
×
199
                    }
200
                }
×
201
                members = new ArrayList<>();
×
202
                for (ApiResponseEntry r : QueryApiAccess.forcedGet(new QueryRef("get-members", "unit", id)).getData()) {
×
203
                    IRI memberId = Utils.vf.createIRI(r.get("member"));
×
204
                    // TODO These checks are inefficient for long member lists:
205
                    if (owners.contains(memberId)) continue;
×
206
                    if (members.contains(memberId)) continue;
×
207
                    members.add(memberId);
×
208
                }
×
209
                owners.sort(User.getUserData().userComparator);
×
210
                members.sort(User.getUserData().userComparator);
×
211
                dataInitialized = true;
×
212
            }).start();
×
213
            dataNeedsUpdate = false;
×
214
        }
215
    }
×
216

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