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

knowledgepixels / nanopub-registry / 24087317420

07 Apr 2026 02:39PM UTC coverage: 32.924% (+1.1%) from 31.828%
24087317420

push

github

web-flow
Merge pull request #94 from knowledgepixels/feat/type-coverage-enforcement

feat: enforce type coverage restrictions across all loading paths

242 of 796 branches covered (30.4%)

Branch coverage included in aggregate %.

750 of 2217 relevant lines covered (33.83%)

5.73 hits per line

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

96.34
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

8
import java.io.IOException;
9
import java.text.DecimalFormat;
10

11
import static com.knowledgepixels.registry.RegistryDB.*;
12

13
public abstract class Page {
14

15
    protected static final DecimalFormat df8 = new DecimalFormat("0.00000000");
15✔
16
    protected static final DecimalFormat df1 = new DecimalFormat("0.0");
18✔
17

18
    private RoutingContext context;
19
    protected ClientSession mongoSession;
20

21
    private String presentationFormat;
22
    private String extension;
23
    private String requestString;
24

25
    /**
26
     * Constructor for the Page class.
27
     *
28
     * @param mongoSession The MongoDB client session.
29
     * @param context      The routing context.
30
     */
31
    public Page(ClientSession mongoSession, RoutingContext context) {
6✔
32
        this.mongoSession = mongoSession;
9✔
33
        this.context = context;
9✔
34
        context.response().setChunked(true);
15✔
35

36
        // TODO See whether we can cache these better on our side. Not sure how efficient the MongoDB caching is for these
37
        //      kinds of DB queries...
38
        context.response().putHeader("Nanopub-Registry-Status", getValue(mongoSession, Collection.SERVER_INFO.toString(), "status") + "");
36✔
39
        context.response().putHeader("Nanopub-Registry-Setup-Id", getValue(mongoSession, Collection.SERVER_INFO.toString(), "setupId") + "");
36✔
40
        context.response().putHeader("Nanopub-Registry-Trust-State-Counter", getValue(mongoSession, Collection.SERVER_INFO.toString(), "trustStateCounter") + "");
36✔
41
        context.response().putHeader("Nanopub-Registry-Last-Trust-State-Update", getValue(mongoSession, Collection.SERVER_INFO.toString(), "lastTrustStateUpdate") + "");
36✔
42
        context.response().putHeader("Nanopub-Registry-Trust-State-Hash", getValue(mongoSession, Collection.SERVER_INFO.toString(), "trustStateHash") + "");
36✔
43
        context.response().putHeader("Nanopub-Registry-SeqNum", getMaxValue(mongoSession, Collection.NANOPUBS.toString(), "seqNum") + "");
36✔
44
        context.response().putHeader("Nanopub-Registry-Nanopub-Count", collection(Collection.NANOPUBS.toString()).estimatedDocumentCount() + "");
30✔
45
        // TODO(transition): Remove after all peers upgraded
46
        // Must send max(seqNum) here, not document count — old peers use Load-Counter as a cursor
47
        // value for afterCounter, not just a count. Sending the count would cause re-fetching.
48
        context.response().putHeader("Nanopub-Registry-Load-Counter", getMaxValue(mongoSession, Collection.NANOPUBS.toString(), "seqNum") + "");
36✔
49
        context.response().putHeader("Nanopub-Registry-Test-Instance", String.valueOf(isSet(mongoSession, Collection.SERVER_INFO.toString(), "testInstance")));
33✔
50
        String coveredTypes = CoverageFilter.getCoveredTypeHashesAsString();
6✔
51
        if (coveredTypes != null) {
6✔
52
            context.response().putHeader("Nanopub-Registry-Coverage-Types", coveredTypes);
18✔
53
        }
54

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

74
    /**
75
     * Get the routing context.
76
     *
77
     * @return The routing context.
78
     */
79
    public RoutingContext getContext() {
80
        return context;
9✔
81
    }
82

83
    /**
84
     * Print a line to the response.
85
     *
86
     * @param s The string to print.
87
     */
88
    public void println(String s) {
89
        print(s + "\n");
12✔
90
    }
3✔
91

92
    /**
93
     * Print a string to the response.
94
     *
95
     * @param s The string to print.
96
     */
97
    public void print(String s) {
98
        if (context.request().method() == HttpMethod.HEAD) {
18!
99
            return;
×
100
        }
101
        context.response().write(s);
18✔
102
    }
3✔
103

104
    /**
105
     * Set the response content type.
106
     *
107
     * @param contentType The content type.
108
     */
109
    public void setRespContentType(String contentType) {
110
        if (context.request().method() == HttpMethod.HEAD) {
18✔
111
            return;
3✔
112
        }
113
        context.response().putHeader("Content-Type", contentType);
21✔
114
    }
3✔
115

116
    /**
117
     * Show the page.
118
     *
119
     * @throws IOException
120
     */
121
    protected abstract void show() throws IOException;
122

123
    /**
124
     * Print the HTML header.
125
     *
126
     * @param title The title of the page.
127
     */
128
    public void printHtmlHeader(String title) {
129
        println("<!DOCTYPE HTML>");
9✔
130
        println("<html><head>");
9✔
131
        println("<title>" + title + "</title>");
12✔
132
        println("<meta charset=\"utf-8\"/>");
9✔
133
        println("<script type=\"text/javascript\" src=\"/scripts/nanopub.js\"></script>");
9✔
134
        println("<link rel=\"stylesheet\" href=\"/style.css\" type=\"text/css\" media=\"screen\" title=\"Stylesheet\" />");
9✔
135
        println("</head><body>");
9✔
136
    }
3✔
137

138
    /**
139
     * Print the HTML footer.
140
     */
141
    public void printHtmlFooter() {
142
        println("</body></html>");
9✔
143
    }
3✔
144

145
    /**
146
     * Escape HTML special characters in a string.
147
     *
148
     * @param text The text to escape.
149
     * @return The escaped text.
150
     */
151
    public String escapeHtml(String text) {
152
        return StringEscapeUtils.escapeHtml(text);
×
153
    }
154

155
    /**
156
     * Set the canonical link for this page.
157
     *
158
     * @param url The canonical URL.
159
     */
160
    public void setCanonicalLink(String url) {
161
        context.response().putHeader("Link", "<" + url + ">; rel=\"canonical\"");
24✔
162
    }
3✔
163

164
    /**
165
     * Get the presentation format requested, if any.
166
     *
167
     * @return The presentation format.
168
     */
169
    public String getPresentationFormat() {
170
        return presentationFormat;
9✔
171
    }
172

173
    /**
174
     * Get the extension requested, if any.
175
     *
176
     * @return The extension.
177
     */
178
    public String getExtension() {
179
        return extension;
9✔
180
    }
181

182
    /**
183
     * Get the request string with the leading slash and without extension.
184
     *
185
     * @return The request string.
186
     */
187
    public String getRequestString() {
188
        return "/" + requestString;
12✔
189
    }
190

191
    /**
192
     * Get the full request path.
193
     *
194
     * @return The full request path.
195
     */
196
    public String getFullRequest() {
197
        return context.request().path();
15✔
198
    }
199

200
    /**
201
     * Get a parameter from the request.
202
     *
203
     * @param name         The name of the parameter.
204
     * @param defaultValue The default value of the parameter.
205
     * @return The value of the parameter.
206
     */
207
    public String getParam(String name, String defaultValue) {
208
        String value = context.request().getParam(name);
18✔
209
        if (value == null) value = defaultValue;
12✔
210
        return value;
6✔
211
    }
212

213
    /**
214
     * Check whether the request is empty.
215
     *
216
     * @return True if the request is empty, false otherwise.
217
     */
218
    public boolean isEmpty() {
219
        return requestString.isEmpty();
12✔
220
    }
221

222
    /**
223
     * Check whether the request contains an artifact code.
224
     *
225
     * @return True if the request contains an artifact code, false otherwise.
226
     */
227
    public boolean hasArtifactCode() {
228
        return requestString.matches("RA[A-Za-z0-9\\-_]{43}");
15✔
229
    }
230

231
    /**
232
     * Get the artifact code from the request, if present.
233
     *
234
     * @return The artifact code, or null if not present.
235
     */
236
    public String getArtifactCode() {
237
        if (hasArtifactCode()) {
9✔
238
            return requestString;
9✔
239
        }
240
        return null;
6✔
241
    }
242

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