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

knowledgepixels / nanopub-registry / 28155387420

25 Jun 2026 07:53AM UTC coverage: 31.926% (-0.2%) from 32.089%
28155387420

push

github

web-flow
chore: enhance and standardize logging across multiple components (#116)

* chore(EntryStatus): enhance logging for null and unsupported status value handling

* chore(logging): standardize logger variable names across multiple classes

* chore(CoverageFilter): enhance logging for coverage filter initialization and type checks

* chore(RegistryPeerConnector): enhance logging for peer connection and nanopub fetching

* chore(logging): enhance logging for request handling and error reporting in multiple pages

* chore(MainVerticle): enhance logging for HTTP server startup, request routing, and POST processing

* chore(Task): improve logging messages

* chore(Task): enhance logging for server status checks and account loading processes

* chore(RegistryInfo): add logging messages for RegistryInfo snapshot assembly and JSON serialization

* chore(logging): enhance logging throughout various components for better traceability and debugging

* chore(Utils): enhance logging for user IRI extraction in IntroNanopub

* chore(TrustStatePage): enhance logging for trust-state snapshot resolution and querying

* chore(NanopubLoader): enhance logging for nanopub retrieval and processing

* chore(Task): enhance logging for task execution and status transitions

313 of 1106 branches covered (28.3%)

Branch coverage included in aggregate %.

1048 of 3157 relevant lines covered (33.2%)

5.51 hits per line

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

65.85
src/main/java/com/knowledgepixels/registry/NanopubPage.java
1
package com.knowledgepixels.registry;
2

3
import com.github.jsonldjava.shaded.com.google.common.base.Charsets;
4
import com.mongodb.client.ClientSession;
5
import eu.neverblink.jelly.core.utils.IoUtils;
6
import io.vertx.ext.web.RoutingContext;
7
import org.apache.commons.lang.StringEscapeUtils;
8
import org.bson.Document;
9
import org.bson.types.Binary;
10
import org.eclipse.rdf4j.common.exception.RDF4JException;
11
import org.eclipse.rdf4j.rio.RDFFormat;
12
import org.nanopub.MalformedNanopubException;
13
import org.nanopub.Nanopub;
14
import org.nanopub.NanopubImpl;
15
import org.nanopub.NanopubUtils;
16
import org.slf4j.Logger;
17
import org.slf4j.LoggerFactory;
18

19
import java.io.IOException;
20

21
import static com.knowledgepixels.registry.RegistryDB.collection;
22
import static com.knowledgepixels.registry.RegistryDB.isSet;
23
import static com.knowledgepixels.registry.Utils.*;
24

25
public class NanopubPage extends Page {
26

27
    private static final Logger logger = LoggerFactory.getLogger(NanopubPage.class);
12✔
28

29
    static final String NANODASH_BASE_URL_DEFAULT = "https://nanodash.knowledgepixels.com/";
30

31
    static String getNanodashBaseUrl() {
32
        return Utils.getEnv("REGISTRY_NANODASH_BASE_URL", NANODASH_BASE_URL_DEFAULT);
12✔
33
    }
34

35
    private final boolean forwardHtml;
36

37
    public static void show(RoutingContext context) {
38
        show(context, false);
×
39
    }
×
40

41
    public static void show(RoutingContext context, boolean forwardHtml) {
42
        NanopubPage page;
43
        logger.info("Received nanopub request: {} forwardHtml={}", context.request().path(), forwardHtml);
24✔
44
        try (ClientSession s = RegistryDB.getClient().startSession()) {
9✔
45
            s.startTransaction();
6✔
46
            page = new NanopubPage(s, context, forwardHtml);
21✔
47
            page.show();
6✔
48
        } catch (IOException ex) {
×
49
            logger.warn("Failed to show nanopub for request {}: {} ({})", context.request().path(), ex.getMessage(), ex.getClass().getSimpleName(), ex);
×
50
        } finally {
51
            logger.debug("Ending response for nanopub request: {}", context.request().path());
18✔
52
            context.response().end();
12✔
53
            // TODO Clean-up here?
54
        }
55
    }
3✔
56

57
    private NanopubPage(ClientSession mongoSession, RoutingContext context, boolean forwardHtml) {
58
        super(mongoSession, context);
12✔
59
        this.forwardHtml = forwardHtml;
9✔
60
    }
3✔
61

62
    protected void show() throws IOException {
63
        RoutingContext c = getContext();
9✔
64
        String ext = getExtension();
9✔
65
        String format = Utils.getType(ext);
9✔
66
        final String req = getRequestString();
9✔
67

68
        logger.debug("Preparing nanopub response for request: {} (ext={}, resolvedFormat={})", getFullRequest(), ext, format);
54✔
69

70
        if (format == null) {
6✔
71
            format = Utils.getMimeType(c, SUPPORTED_TYPES_NANOPUB);
12✔
72
            logger.debug("Resolved format from Accept header: {}", format);
12✔
73
        }
74
        if (format == null) {
6!
75
            logger.warn("Invalid nanopub request (could not determine format): {}", getFullRequest());
×
76
            c.response().setStatusCode(400).setStatusMessage("Invalid request: " + getFullRequest());
×
77
            return;
×
78
        }
79

80
        var presentationFormat = getPresentationFormat();
9✔
81
        if (presentationFormat != null) {
6!
82
            setRespContentType(presentationFormat);
×
83
            logger.debug("Overriding response content type with presentation format: {}", presentationFormat);
×
84
        } else {
85
            setRespContentType(format);
9✔
86
            logger.debug("Set response content type: {}", format);
12✔
87
        }
88

89
        if (req.matches("/(np|get)/RA[a-zA-Z0-9-_]{43}(\\.[a-z]+)?")) {
12!
90
            String ac = req.replaceFirst("/(np|get)/(RA[a-zA-Z0-9-_]{43})(\\.[a-z]+)?", "$2");
15✔
91
            logger.debug("Lookup nanopub id: {}", ac);
12✔
92
            Document npDoc = collection(Collection.NANOPUBS.toString()).find(new Document("_id", ac)).first();
36✔
93
            if (npDoc == null) {
6✔
94
                if (!isSet(mongoSession, Collection.SERVER_INFO.toString(), "testInstance")) {
21!
95
                    //getResp().sendError(404, "Not found: " + ac);
96
                    logger.info("Nanopub {} not found locally; redirecting to external resolver", ac);
12✔
97
                    c.response().setStatusCode(307);
15✔
98
                    c.response().putHeader("Location", "https://np.knowledgepixels.com/" + ac);
21✔
99
                    return;
3✔
100
                } else {
101
                    logger.warn("Nanopub {} not found (test instance): {}", ac, getFullRequest());
×
102
                    c.response().setStatusCode(404).setStatusMessage("Not found: " + getFullRequest());
×
103
                    return;
×
104
                }
105
            }
106
            //                String url = ServerConf.getInfo().getPublicUrl();
107
            if (TYPE_TRIG.equals(format)) {
12✔
108
                logger.info("Serving nanopub {} as TRIG", ac);
12✔
109
                println(npDoc.getString("content"));
18✔
110
            } else if (TYPE_JELLY.equals(format)) {
12!
111
                if (presentationFormat != null && presentationFormat.startsWith("text")) {
×
112
                    // Parse the Jelly frame and return it as Protobuf Text Format Language
113
                    // https://protobuf.dev/reference/protobuf/textformat-spec/
114
                    // It's better than bombarding the browser with a binary file.
115
                    var frame = eu.neverblink.jelly.core.proto.google.v1.RdfStreamFrame
×
116
                            .parseFrom(((Binary) npDoc.get("jelly")).getData());
×
117
                    println(frame.toString());
×
118
                } else {
×
119
                    // To return this correctly, we would need to prepend the delimiter byte before the Jelly frame
120
                    // (the DB stores is non-delimited and the HTTP response must be delimited).
121
                    BufferOutputStream outputStream = new BufferOutputStream();
×
122
                    IoUtils.writeFrameAsDelimited(
×
123
                            ((Binary) npDoc.get("jelly")).getData(),
×
124
                            outputStream
125
                    );
126
                    c.response().write(outputStream.getBuffer());
×
127
                    logger.info("Served nanopub {} as Jelly frame (bytes written)", ac);
×
128
                }
×
129
            } else if (format != null && format.equals(TYPE_NQUADS)) {
18!
130
                logger.info("Serving nanopub {} as N-Quads", ac);
×
131
                outputNanopub(npDoc, RDFFormat.NQUADS);
×
132
            } else if (format != null && format.equals(TYPE_JSONLD)) {
18!
133
                logger.info("Serving nanopub {} as JSON-LD", ac);
×
134
                outputNanopub(npDoc, RDFFormat.JSONLD);
×
135
            } else if (format != null && format.equals(TYPE_TRIX)) {
18!
136
                logger.info("Serving nanopub {} as TriX", ac);
×
137
                outputNanopub(npDoc, RDFFormat.TRIX);
×
138
            } else if (forwardHtml && isHtmlRequested(c)) {
18✔
139
                String fullId = npDoc.getString("fullId");
12✔
140
                logger.info("Forwarding HTML request for nanopub {} to Nanodash (url={})", ac, getNanodashBaseUrl());
15✔
141
                c.response().setStatusCode(302);
15✔
142
                c.response().putHeader("Location", getNanodashBaseUrl() + "explore?id=" + Utils.urlEncode(fullId));
27✔
143
                return;
3✔
144
            } else if (forwardHtml) {
9✔
145
                // Non-HTML default for /get/ path (e.g. Accept: */*): serve as trig
146
                logger.info("Forwarding non-HTML /get/ request for {} as TRIG", ac);
12✔
147
                setRespContentType(TYPE_TRIG);
9✔
148
                println(npDoc.getString("content"));
18✔
149
            } else {
150
                logger.info("Rendering HTML detail view for nanopub {}", ac);
12✔
151
                printHtmlHeader("Nanopublication " + ac + " - Nanopub Registry");
12✔
152
                println("<h1>Nanopublication</h1>");
9✔
153
                println("<p><a href=\"/\">&lt; Home</a></p>");
9✔
154
                println("<h3>ID</h3>");
9✔
155
                String fullId = npDoc.getString("fullId");
12✔
156
                println("<p><a href=\"" + fullId + "\"><code>" + fullId + "</code></a></p>");
15✔
157
                println("<h3>Formats</h3>");
9✔
158
                println("<p>");
9✔
159
                println("<a href=\"/np/" + ac + ".trig\">.trig</a> |");
12✔
160
                println("<a href=\"/np/" + ac + ".trig.txt\">.trig.txt</a> |");
12✔
161
                println("<a href=\"/np/" + ac + ".jelly\">.jelly</a> |");
12✔
162
                println("<a href=\"/np/" + ac + ".jelly.txt\">.jelly.txt</a> |");
12✔
163
                println("<a href=\"/np/" + ac + ".jsonld\">.jsonld</a> |");
12✔
164
                println("<a href=\"/np/" + ac + ".jsonld.txt\">.jsonld.txt</a> |");
12✔
165
                println("<a href=\"/np/" + ac + ".nq\">.nq</a> |");
12✔
166
                println("<a href=\"/np/" + ac + ".nq.txt\">.nq.txt</a> |");
12✔
167
                println("<a href=\"/np/" + ac + ".xml\">.xml</a> |");
12✔
168
                println("<a href=\"/np/" + ac + ".xml.txt\">.xml.txt</a>");
12✔
169
                println("</p>");
9✔
170
                println("<h3>Content</h3>");
9✔
171
                println("<pre>");
9✔
172
                println(StringEscapeUtils.escapeHtml(npDoc.getString("content")));
18✔
173
                println("</pre>");
9✔
174
                printHtmlFooter();
6✔
175
            }
176
        } else {
3✔
177
            logger.warn("Invalid nanopub request path: {}", getFullRequest());
×
178
            c.response().setStatusCode(400).setStatusMessage("Invalid request: " + getFullRequest());
×
179
        }
180
    }
3✔
181

182
    private static boolean isHtmlRequested(RoutingContext c) {
183
        String accept = c.request().getHeader("Accept");
15✔
184
        return accept != null && accept.contains("text/html");
30!
185
    }
186

187
    private void outputNanopub(Document npDoc, RDFFormat rdfFormat) {
188
        RoutingContext c = getContext();
×
189
        try {
190
            Nanopub np = new NanopubImpl(npDoc.getString("content"), RDFFormat.TRIG);
×
191
            c.response().write(NanopubUtils.writeToString(np, rdfFormat), Charsets.UTF_8.toString());
×
192
            logger.info("Transformed nanopub {} to {}", npDoc.getString("_id"), rdfFormat);
×
193
        } catch (RDF4JException | MalformedNanopubException | IOException ex) {
×
194
            logger.warn("Failed transforming nanopub {} to {}: {} ({})", npDoc.getString("_id"), rdfFormat, ex.getMessage(), ex.getClass().getSimpleName(), ex);
×
195
            c.response().setStatusCode(500).setStatusMessage("Failed transforming nanopub: " + getFullRequest());
×
196
        }
×
197
    }
×
198

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