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

knowledgepixels / nanopub-registry / 28113618611

24 Jun 2026 04:28PM UTC coverage: 31.926% (-0.2%) from 32.089%
28113618611

Pull #116

github

web-flow
Merge d931f8afc into eebd16ba4
Pull Request #116: Enhance and standardize logging across multiple components

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

89.72
src/main/java/com/knowledgepixels/registry/Page.java
1
package com.knowledgepixels.registry;
2

3
import com.mongodb.client.ClientSession;
4
import io.vertx.core.http.HttpMethod;
5
import io.vertx.ext.web.RoutingContext;
6
import org.apache.commons.lang.StringEscapeUtils;
7
import org.bson.Document;
8
import org.slf4j.Logger;
9
import org.slf4j.LoggerFactory;
10

11
import java.io.IOException;
12
import java.text.DecimalFormat;
13

14
import static com.knowledgepixels.registry.RegistryDB.collection;
15
import static com.knowledgepixels.registry.RegistryDB.getMaxValue;
16

17
public abstract class Page {
18

19
    private static final Logger logger = LoggerFactory.getLogger(Page.class);
9✔
20

21
    protected static final DecimalFormat df8 = new DecimalFormat("0.00000000");
15✔
22
    protected static final DecimalFormat df1 = new DecimalFormat("0.0");
18✔
23

24
    private RoutingContext context;
25
    protected ClientSession mongoSession;
26
    protected Document serverInfo;
27

28
    private String presentationFormat;
29
    private String extension;
30
    private String requestString;
31

32
    /**
33
     * Constructor for the Page class.
34
     *
35
     * @param mongoSession The MongoDB client session.
36
     * @param context      The routing context.
37
     */
38
    public Page(ClientSession mongoSession, RoutingContext context) {
6✔
39
        this.mongoSession = mongoSession;
9✔
40
        this.context = context;
9✔
41
        context.response().setChunked(true);
15✔
42

43
        // Fetch all serverInfo key-value pairs in one query instead of separate getValue calls
44
        serverInfo = new Document();
15✔
45
        for (Document d : collection(Collection.SERVER_INFO.toString()).find(mongoSession)) {
42✔
46
            serverInfo.put(d.getString("_id"), d.get("value"));
30✔
47
        }
3✔
48
        context.response().putHeader("Nanopub-Registry-Version", Utils.getVersion());
18✔
49
        context.response().putHeader("Nanopub-Registry-Status", serverInfo.get("status") + "");
33✔
50
        context.response().putHeader("Nanopub-Registry-Setup-Id", serverInfo.get("setupId") + "");
33✔
51
        context.response().putHeader("Nanopub-Registry-Trust-State-Counter", serverInfo.get("trustStateCounter") + "");
33✔
52
        context.response().putHeader("Nanopub-Registry-Last-Trust-State-Update", serverInfo.get("lastTrustStateUpdate") + "");
33✔
53
        context.response().putHeader("Nanopub-Registry-Trust-State-Hash", serverInfo.get("trustStateHash") + "");
33✔
54
        Object maxCounter = getMaxValue(mongoSession, Collection.NANOPUBS.toString(), "counter");
18✔
55
        context.response().putHeader("Nanopub-Registry-Load-Counter", maxCounter + "");
24✔
56
        context.response().putHeader("Nanopub-Registry-Nanopub-Count", collection(Collection.NANOPUBS.toString()).estimatedDocumentCount() + "");
30✔
57
        context.response().putHeader("Nanopub-Registry-Test-Instance", String.valueOf(serverInfo.get("testInstance") != null && (Boolean) serverInfo.get("testInstance")));
57!
58
        context.response().putHeader("Nanopub-Registry-Coverage-Types", serverInfo.get("coverageTypes") != null ? serverInfo.get("coverageTypes").toString() : "all");
33!
59
        context.response().putHeader("Nanopub-Registry-Coverage-Agents", serverInfo.get("coverageAgents") != null ? serverInfo.get("coverageAgents").toString() : "viaSetting");
33!
60

61
        String r = context.request().path().substring(1);
18✔
62
        if (r.endsWith(".txt")) {
12✔
63
            presentationFormat = "text/plain";
9✔
64
            r = r.replaceFirst("\\.txt$", "");
18✔
65
        } else if (r.endsWith(".html")) {
12✔
66
            presentationFormat = "text/html";
9✔
67
            r = r.replaceFirst("\\.html$", "");
15✔
68
//                } else if (r.endsWith(".gz")) {
69
//                        presentationFormat = "application/x-gzip";
70
//                        r = r.replaceFirst("\\.gz$", "");
71
        }
72
        if (r.matches(".*\\.[a-z]{1,10}")) {
12✔
73
            extension = r.replaceFirst("^.*\\.([a-z]{1,10})$", "$1");
18✔
74
            requestString = r.replaceFirst("^(.*)\\.[a-z]{1,10}$", "$1");
21✔
75
        } else {
76
            requestString = r;
9✔
77
        }
78

79
        logger.debug("Initialized Page for path={} requestString={} extension={} presentationFormat={}",
24✔
80
                context.request().path(), requestString, extension, presentationFormat);
54✔
81
        if (serverInfo.get("setupId") == null || serverInfo.get("status") == null) {
30!
82
            logger.warn("Server info incomplete for request {}: setupId={} status={}", getFullRequest(), serverInfo.get("setupId"), serverInfo.get("status"));
×
83
        }
84
    }
3✔
85

86
    /**
87
     * Get the routing context.
88
     *
89
     * @return The routing context.
90
     */
91
    public RoutingContext getContext() {
92
        return context;
9✔
93
    }
94

95
    /**
96
     * Print a line to the response.
97
     *
98
     * @param s The string to print.
99
     */
100
    public void println(String s) {
101
        print(s + "\n");
12✔
102
    }
3✔
103

104
    /**
105
     * Print a string to the response.
106
     *
107
     * @param s The string to print.
108
     */
109
    public void print(String s) {
110
        if (context.request().method() == HttpMethod.HEAD) {
18!
111
            logger.debug("Suppressing response body for HEAD request: {}", context.request().path());
×
112
            return;
×
113
        }
114
        context.response().write(s);
18✔
115
    }
3✔
116

117
    /**
118
     * Set the response content type.
119
     *
120
     * @param contentType The content type.
121
     */
122
    public void setRespContentType(String contentType) {
123
        if (context.request().method() == HttpMethod.HEAD) {
18✔
124
            logger.debug("Suppressing Content-Type header for HEAD request: {}", context.request().path());
21✔
125
            return;
3✔
126
        }
127
        context.response().putHeader("Content-Type", contentType);
21✔
128
        logger.debug("Set Content-Type={} for request={}", contentType, context.request().path());
24✔
129
    }
3✔
130

131
    /**
132
     * Show the page.
133
     *
134
     * @throws IOException If an I/O error occurs while showing the page.
135
     */
136
    protected abstract void show() throws IOException;
137

138
    /**
139
     * Print the HTML header.
140
     *
141
     * @param title The title of the page.
142
     */
143
    public void printHtmlHeader(String title) {
144
        println("<!DOCTYPE HTML>");
9✔
145
        println("<html><head>");
9✔
146
        println("<title>" + title + "</title>");
12✔
147
        println("<meta charset=\"utf-8\"/>");
9✔
148
        println("<script type=\"text/javascript\" src=\"/scripts/nanopub.js\"></script>");
9✔
149
        println("<link rel=\"stylesheet\" href=\"/style.css\" type=\"text/css\" media=\"screen\" title=\"Stylesheet\" />");
9✔
150
        println("</head><body>");
9✔
151
    }
3✔
152

153
    /**
154
     * Print the HTML footer.
155
     */
156
    public void printHtmlFooter() {
157
        println("</body></html>");
9✔
158
    }
3✔
159

160
    /**
161
     * Escape HTML special characters in a string.
162
     *
163
     * @param text The text to escape.
164
     * @return The escaped text.
165
     */
166
    public String escapeHtml(String text) {
167
        return StringEscapeUtils.escapeHtml(text);
×
168
    }
169

170
    /**
171
     * Set the canonical link for this page.
172
     *
173
     * @param url The canonical URL.
174
     */
175
    public void setCanonicalLink(String url) {
176
        context.response().putHeader("Link", "<" + url + ">; rel=\"canonical\"");
24✔
177
    }
3✔
178

179
    /**
180
     * Get the presentation format requested, if any.
181
     *
182
     * @return The presentation format.
183
     */
184
    public String getPresentationFormat() {
185
        return presentationFormat;
9✔
186
    }
187

188
    /**
189
     * Get the extension requested, if any.
190
     *
191
     * @return The extension.
192
     */
193
    public String getExtension() {
194
        return extension;
9✔
195
    }
196

197
    /**
198
     * Get the request string with the leading slash and without extension.
199
     *
200
     * @return The request string.
201
     */
202
    public String getRequestString() {
203
        return "/" + requestString;
12✔
204
    }
205

206
    /**
207
     * Get the full request path.
208
     *
209
     * @return The full request path.
210
     */
211
    public String getFullRequest() {
212
        return context.request().path();
15✔
213
    }
214

215
    /**
216
     * Get a parameter from the request.
217
     *
218
     * @param name         The name of the parameter.
219
     * @param defaultValue The default value of the parameter.
220
     * @return The value of the parameter.
221
     */
222
    public String getParam(String name, String defaultValue) {
223
        String value = context.request().getParam(name);
18✔
224
        if (value == null) {
6✔
225
            value = defaultValue;
6✔
226
        }
227
        return value;
6✔
228
    }
229

230
    /**
231
     * Check whether the request is empty.
232
     *
233
     * @return True if the request is empty, false otherwise.
234
     */
235
    public boolean isEmpty() {
236
        return requestString.isEmpty();
12✔
237
    }
238

239
    /**
240
     * Check whether the request contains an artifact code.
241
     *
242
     * @return True if the request contains an artifact code, false otherwise.
243
     */
244
    public boolean hasArtifactCode() {
245
        return requestString.matches("RA[A-Za-z0-9\\-_]{43}");
15✔
246
    }
247

248
    /**
249
     * Get the artifact code from the request, if present.
250
     *
251
     * @return The artifact code, or null if not present.
252
     */
253
    public String getArtifactCode() {
254
        if (hasArtifactCode()) {
9✔
255
            return requestString;
9✔
256
        }
257
        return null;
6✔
258
    }
259

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