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

knowledgepixels / nanodash / 19170532844

07 Nov 2025 01:56PM UTC coverage: 14.148% (-0.8%) from 14.95%
19170532844

push

github

tkuhn
feat(Space): Part-level elements for Spaces, also namespace-declared

518 of 4596 branches covered (11.27%)

Branch coverage included in aggregate %.

1335 of 8501 relevant lines covered (15.7%)

0.7 hits per line

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

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

3
import com.google.common.collect.ArrayListMultimap;
4
import com.google.common.collect.Multimap;
5
import com.knowledgepixels.nanodash.*;
6
import com.knowledgepixels.nanodash.component.*;
7
import jakarta.servlet.http.HttpServletRequest;
8
import net.trustyuri.TrustyUriUtils;
9
import org.apache.wicket.RestartResponseException;
10
import org.apache.wicket.markup.html.WebMarkupContainer;
11
import org.apache.wicket.markup.html.basic.Label;
12
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
13
import org.apache.wicket.markup.html.link.ExternalLink;
14
import org.apache.wicket.model.Model;
15
import org.apache.wicket.request.flow.RedirectToUrlException;
16
import org.apache.wicket.request.mapper.parameter.INamedParameters.NamedPair;
17
import org.apache.wicket.request.mapper.parameter.PageParameters;
18
import org.commonjava.mimeparse.MIMEParse;
19
import org.eclipse.rdf4j.model.Statement;
20
import org.eclipse.rdf4j.model.vocabulary.DCTERMS;
21
import org.eclipse.rdf4j.model.vocabulary.SKOS;
22
import org.nanopub.Nanopub;
23
import org.nanopub.NanopubUtils;
24
import org.nanopub.extra.security.SignatureUtils;
25
import org.nanopub.extra.services.ApiResponse;
26
import org.nanopub.extra.services.QueryRef;
27
import org.nanopub.vocabulary.NPX;
28
import org.nanopub.vocabulary.NTEMPLATE;
29
import org.slf4j.Logger;
30
import org.slf4j.LoggerFactory;
31

32
import java.util.HashMap;
33
import java.util.Map;
34
import java.util.Set;
35

36
/**
37
 * ExplorePage is a page that allows users to explore a specific Nanopublication or Thing.
38
 */
39
public class ExplorePage extends NanodashPage {
40

41
    private static final Logger logger = LoggerFactory.getLogger(ExplorePage.class);
×
42

43
    /**
44
     * The mount path for this page.
45
     */
46
    public static final String MOUNT_PATH = "/explore";
47

48
    /**
49
     * {@inheritDoc}
50
     */
51
    @Override
52
    public String getMountPath() {
53
        return MOUNT_PATH;
×
54
    }
55

56
    private Nanopub publishedNanopub = null;
×
57

58
    /**
59
     * Constructor for ExplorePage.
60
     *
61
     * @param parameters Page parameters containing the ID of the Nanopublication or Thing to explore.
62
     */
63
    public ExplorePage(final PageParameters parameters) {
64
        super(parameters);
×
65
        add(new Label("publish-confirm-panel").setVisible(false));
×
66
        initPage();
×
67
    }
×
68

69
    public ExplorePage(final Nanopub publishedNanopub, final PageParameters parameters) {
70
        super(parameters.set("id", publishedNanopub.getUri()));
×
71
        this.publishedNanopub = publishedNanopub;
×
72

73
        WebMarkupContainer publishConfirmPanel = new WebMarkupContainer("publish-confirm-panel");
×
74
        final NanodashSession session = NanodashSession.get();
×
75
        boolean hasKnownOwnLocalIntro = session.getLocalIntroCount() > 0;
×
76
        boolean someIntroJustNowPublished = Utils.usesPredicateInAssertion(publishedNanopub, NPX.DECLARED_BY);
×
77
        if (someIntroJustNowPublished) NanodashSession.get().setIntroPublishedNow();
×
78
        boolean lastIntroPublishedMoreThanFiveMinsAgo = session.getTimeSinceLastIntroPublished() > 5 * 60 * 1000;
×
79
        if (!hasKnownOwnLocalIntro && session.hasIntroPublished()) User.refreshUsers();
×
80
        publishConfirmPanel.add(new WebMarkupContainer("missing-intro-warning").setVisible(!hasKnownOwnLocalIntro && lastIntroPublishedMoreThanFiveMinsAgo));
×
81

82
        PageParameters plainLinkParams = new PageParameters();
×
83
        plainLinkParams.set("template", parameters.get("template"));
×
84
        if (!parameters.get("template-version").isEmpty()) {
×
85
            plainLinkParams.set("template-version", parameters.get("template-version"));
×
86
        }
87
        publishConfirmPanel.add(new BookmarkablePageLink<Void>("publish-another-link", PublishPage.class, plainLinkParams));
×
88

89
        PageParameters linkParams = new PageParameters(parameters);
×
90
        linkParams.remove("supersede");
×
91
        linkParams.remove("supersede-a");
×
92
        boolean publishAnotherFilledLinkVisible = false;
×
93
        for (NamedPair n : linkParams.getAllNamed()) {
×
94
            if (n.getKey().matches("(param|prparam|piparam[1-9][0-9]*)_.*")) {
×
95
                publishAnotherFilledLinkVisible = true;
×
96
                break;
×
97
            }
98
        }
×
99
        if (publishAnotherFilledLinkVisible) {
×
100
            publishConfirmPanel.add(new BookmarkablePageLink<Void>("publish-another-filled-link", PublishPage.class, linkParams));
×
101
        } else {
102
            publishConfirmPanel.add(new Label("publish-another-filled-link", "").setVisible(false));
×
103
        }
104
        add(publishConfirmPanel);
×
105

106
        initPage();
×
107
    }
×
108

109
    private void initPage() {
110
        PageParameters parameters = getPageParameters();
×
111

112
        add(new TitleBar("titlebar", this, null));
×
113

114
        String tempRef = parameters.get("id").toString();
×
115

116
        String contextId = parameters.get("context").toString("");
×
117
        if (Space.get(contextId) != null) {
×
118
            add(new BookmarkablePageLink<Void>("back-to-context-link", SpacePage.class, new PageParameters().set("id", contextId)).setBody(Model.of("back to " + Space.get(contextId).getLabel())));
×
119
        } else if (MaintainedResource.get(contextId) != null) {
×
120
            add(new BookmarkablePageLink<Void>("back-to-context-link", MaintainedResourcePage.class, new PageParameters().set("id", contextId)).setBody(Model.of("back to " + MaintainedResource.get(contextId).getLabel())));
×
121
        } else {
122
            add(new Label("back-to-context-link").setVisible(false));
×
123
        }
124

125
        if (User.getUserData().isUser(tempRef)) {
×
126
            add(new BookmarkablePageLink<Void>("to-specific-page-link", UserPage.class, parameters).setBody(Model.of("go to user page")));
×
127
        } else if (Space.get(tempRef) != null) {
×
128
            add(new BookmarkablePageLink<Void>("to-specific-page-link", SpacePage.class, parameters).setBody(Model.of("go to Space page")));
×
129
        } else {
130
            add(new Label("to-specific-page-link").setVisible(false));
×
131
        }
132

133
        WebMarkupContainer raw = new WebMarkupContainer("raw");
×
134
        add(raw);
×
135

136
        Map<String, String> nanopubParams = new HashMap<>();
×
137
        nanopubParams.put("ref", tempRef);
×
138
        Nanopub np = Utils.getAsNanopub(tempRef);
×
139
        boolean isNanopubId = (np != null);
×
140
        if (isNanopubId) {
×
141
            tempRef = np.getUri().stringValue();
×
142
        }
143
        if (!isNanopubId && tempRef.matches("^(.*[^A-Za-z0-9-_])?RA[A-Za-z0-9-_]{43}[^A-Za-z0-9-_].*$")) {
×
144
            np = Utils.getAsNanopub(tempRef.replaceFirst("^(.*[^A-Za-z0-9-_])?(RA[A-Za-z0-9-_]{43})[^A-Za-z0-9-_].*$", "$2"));
×
145
            if (np != null) {
×
146
                String npId = np.getUri().stringValue();
×
147
                tempRef = npId + tempRef.replaceFirst("^(.*[^A-Za-z0-9-_])?(RA[A-Za-z0-9-_]{43})([^A-Za-z0-9-_].*)$", "$3");
×
148
                Multimap<String, String> params = ArrayListMultimap.create();
×
149
                params.put("thing", tempRef);
×
150
                params.put("np", npId);
×
151
                ApiResponse resp = QueryApiAccess.forcedGet(new QueryRef("get-latest-thing-nanopub", params));
×
152
                if (!resp.getData().isEmpty()) {
×
153
                    // TODO We take the most recent in case more than one latest version exists. Make other latest versions visible too.
154
                    npId = resp.getData().get(0).get("latestVersion");
×
155
                }
156
                np = Utils.getAsNanopub(npId);
×
157
            }
158
        }
159

160
        if (parameters.get("forward-to-part").toString("").equals("true") && !contextId.isEmpty()) {
×
161
            parameters.remove("forward-to-part");
×
162
            if (np != null) {
×
163
                Set<String> introducedIds = Utils.getIntroducedIriIds(np);
×
164
                if (introducedIds.size() == 1) {
×
165
                    String subj = introducedIds.iterator().next();
×
166
                    for (Statement st : np.getAssertion()) {
×
167
                        if (!st.getSubject().stringValue().equals(subj)) continue;
×
168
                        if (!st.getPredicate().equals(DCTERMS.IS_PART_OF) && !st.getPredicate().equals(SKOS.IN_SCHEME))
×
169
                            continue;
×
170
                        String resourceId = st.getObject().stringValue();
×
171
                        if (MaintainedResource.get(resourceId) == null) continue;
×
172
                        throw new RestartResponseException(ResourcePartPage.class, parameters);
×
173
                    }
174
                }
175
            }
176
            // TODO Improve this so we have just one check:
177
            if (Space.get(contextId) != null && Space.get(contextId).coversElement(tempRef)) {
×
178
                throw new RestartResponseException(ResourcePartPage.class, parameters);
×
179
            } else if (MaintainedResource.get(contextId) != null && MaintainedResource.get(contextId).coversElement(tempRef)) {
×
180
                throw new RestartResponseException(ResourcePartPage.class, parameters);
×
181
            }
182
            
183
        }
184

185
        if (np == null) {
×
186
            raw.setVisible(false);
×
187
            add(new Label("nanopub-header", ""));
×
188
            add(new Label("nanopub", ""));
×
189
            add(new WebMarkupContainer("use-template").setVisible(false));
×
190
            add(new WebMarkupContainer("run-query").setVisible(false));
×
191
        } else {
192

193
            // Check whether we should redirect to Nanopub Registry for machine-friendly formats:
194
            String mimeType = Utils.TYPE_HTML;
×
195
            try {
196
                HttpServletRequest httpRequest = (HttpServletRequest) getRequest().getContainerRequest();
×
197
                mimeType = MIMEParse.bestMatch(Utils.SUPPORTED_TYPES_LIST, httpRequest.getHeader("Accept"));
×
198
            } catch (Exception ex) {
×
199
                logger.error("Error determining MIME type from Accept header.", ex);
×
200
            }
×
201
            if (!mimeType.equals(Utils.TYPE_HTML)) {
×
202
                logger.info("Non-HTML content type: {}", mimeType);
×
203
                // TODO Make this registry URL configurable/dynamic:
204
                String redirectUrl = Utils.getMainRegistryUrl() + "np/" + TrustyUriUtils.getArtifactCode(np.getUri().stringValue());
×
205
                logger.info("Redirecting to: {}", redirectUrl);
×
206
                throw new RedirectToUrlException(redirectUrl, 302);
×
207
            }
208

209
            String nanopubHeaderLabel = "<h4>%s</h4>";
×
210
            if (isNanopubId) {
×
211
                nanopubHeaderLabel = String.format(nanopubHeaderLabel, "Nanopublication");
×
212
            } else {
213
                nanopubHeaderLabel = String.format(nanopubHeaderLabel, "Minted in Nanopublication");
×
214
            }
215
            add(new Label("nanopub-header", nanopubHeaderLabel).setEscapeModelStrings(false));
×
216
            add(new NanopubItem("nanopub", NanopubElement.get(np)));
×
217
            String url = Utils.getMainRegistryUrl() + "np/" + TrustyUriUtils.getArtifactCode(np.getUri().stringValue());
×
218
            raw.add(new ExternalLink("trig-txt", url + ".trig.txt"));
×
219
            raw.add(new ExternalLink("jsonld-txt", url + ".jsonld.txt"));
×
220
            raw.add(new ExternalLink("nq-txt", url + ".nq.txt"));
×
221
            raw.add(new ExternalLink("xml-txt", url + ".xml.txt"));
×
222
            raw.add(new ExternalLink("trig", url + ".trig"));
×
223
            raw.add(new ExternalLink("jsonld", url + ".jsonld"));
×
224
            raw.add(new ExternalLink("nq", url + ".nq"));
×
225
            raw.add(new ExternalLink("xml", url + ".xml"));
×
226
            if (Utils.isNanopubOfClass(np, NTEMPLATE.ASSERTION_TEMPLATE)) {
×
227
                add(new WebMarkupContainer("use-template").add(new BookmarkablePageLink<Void>("template-link", PublishPage.class, new PageParameters().set("template", np.getUri()))));
×
228
            } else {
229
                add(new WebMarkupContainer("use-template").setVisible(false));
×
230
            }
231
            if (Utils.isNanopubOfClass(np, GrlcQuery.GRLC_QUERY_CLASS)) {
×
232
                add(new WebMarkupContainer("run-query").add(new BookmarkablePageLink<Void>("query-link", QueryPage.class, new PageParameters().set("id", np.getUri()))));
×
233
            } else {
234
                add(new WebMarkupContainer("run-query").setVisible(false));
×
235
            }
236
        }
237

238
        final String ref = tempRef;
×
239
        final String shortName;
240
        if (publishedNanopub != null) {
×
241
            shortName = NanopubUtils.getLabel(np);
×
242
        } else if (parameters.get("label").isEmpty()) {
×
243
            shortName = Utils.getShortNameFromURI(ref);
×
244
        } else {
245
            shortName = parameters.get("label").toString();
×
246
        }
247
        add(new Label("pagetitle", shortName + " (explore) | nanodash"));
×
248
        add(new Label("termname", shortName));
×
249
        add(new ExternalLink("urilink", ref, ref));
×
250
        if (publishedNanopub != null) {
×
251
            add(new Label("statusline", "<h4>Status</h4><p>Successfully published.</p>").setEscapeModelStrings(false));
×
252
        } else if (isNanopubId && SignatureUtils.seemsToHaveSignature(np)) {
×
253
            add(StatusLine.createComponent("statusline", ref));
×
254
        } else {
255
            add(new Label("statusline").setVisible(false));
×
256
        }
257
        if (publishedNanopub != null) {
×
258
            add(new Label("classes-panel").setVisible(false));
×
259
        } else {
260
            add(ThingListPanel.createComponent("classes-panel", ThingListPanel.Mode.CLASSES, ref, "<em>Searching for classes...</em>"));
×
261
        }
262
        if (isNanopubId) {
×
263
            add(new Label("definitions-panel").setVisible(false));
×
264
            add(new Label("instances-panel").setVisible(false));
×
265
            add(new Label("parts-panel").setVisible(false));
×
266
            add(new Label("templates-panel").setVisible(false));
×
267
        } else {
268
            add(ThingListPanel.createComponent("definitions-panel", ThingListPanel.Mode.DESCRIPTIONS, ref, "<em>Searching for term descriptions...</em>"));
×
269
            add(ThingListPanel.createComponent("instances-panel", ThingListPanel.Mode.INSTANCES, ref, "<em>Searching for instances...</em>"));
×
270
            add(ThingListPanel.createComponent("parts-panel", ThingListPanel.Mode.PARTS, ref, "<em>Searching for parts...</em>"));
×
271
            add(ThingListPanel.createComponent("templates-panel", ThingListPanel.Mode.TEMPLATES, ref, "<em>Searching for templates...</em>"));
×
272
        }
273
        add(ExploreDataTable.createComponent("reftable", ref));
×
274
    }
×
275

276
    @Override
277
    protected void onBeforeRender() {
278
        if (publishedNanopub != null && !getPageParameters().get("postpub-redirect-url").isNull()) {
×
279
            String forwardUrl = getPageParameters().get("postpub-redirect-url").toString();
×
280
            if (forwardUrl.contains("?")) {
×
281
                // TODO: Add here URI of created nanopublication too?
282
                throw new RedirectToUrlException(forwardUrl);
×
283
            } else {
284
                String paramString = Utils.getPageParametersAsString(new PageParameters().set("id", publishedNanopub.getUri()));
×
285
                throw new RedirectToUrlException(forwardUrl + "?" + paramString);
×
286
            }
287
        }
288
        super.onBeforeRender();
×
289
    }
×
290

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