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

knowledgepixels / nanopub-query / 16989716008

15 Aug 2025 12:12PM UTC coverage: 25.926% (+0.1%) from 25.779%
16989716008

push

github

ashleycaselli
refactor: update code style and files formatting

122 of 494 branches covered (24.7%)

Branch coverage included in aggregate %.

333 of 1261 relevant lines covered (26.41%)

1.29 hits per line

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

0.0
src/main/java/com/knowledgepixels/query/MainVerticle.java
1
package com.knowledgepixels.query;
2

3
import com.github.jsonldjava.shaded.com.google.common.base.Charsets;
4
import io.micrometer.prometheus.PrometheusMeterRegistry;
5
import io.vertx.core.AbstractVerticle;
6
import io.vertx.core.Future;
7
import io.vertx.core.MultiMap;
8
import io.vertx.core.Promise;
9
import io.vertx.core.http.*;
10
import io.vertx.ext.web.Router;
11
import io.vertx.ext.web.RoutingContext;
12
import io.vertx.ext.web.handler.CorsHandler;
13
import io.vertx.ext.web.handler.StaticHandler;
14
import io.vertx.ext.web.proxy.handler.ProxyHandler;
15
import io.vertx.httpproxy.*;
16
import io.vertx.micrometer.PrometheusScrapingHandler;
17
import io.vertx.micrometer.backends.BackendRegistries;
18
import org.apache.http.HttpStatus;
19
import org.eclipse.rdf4j.model.Value;
20
import org.eclipse.rdf4j.rio.RDFFormat;
21
import org.nanopub.MalformedNanopubException;
22
import org.nanopub.Nanopub;
23
import org.nanopub.NanopubImpl;
24

25
import java.io.InputStream;
26
import java.net.URLEncoder;
27
import java.util.*;
28
import java.util.Map.Entry;
29
import java.util.concurrent.Executors;
30
import java.util.concurrent.TimeUnit;
31

32
/**
33
 * Main verticle that coordinates the incoming HTTP requests.
34
 */
35
public class MainVerticle extends AbstractVerticle {
×
36

37
    private boolean server1Started = false;
×
38
    private boolean server2Started = false;
×
39

40
    private static String css = null;
×
41

42
    private boolean allServersStarted() {
43
        return server1Started && server2Started;
×
44
    }
45

46
    /**
47
     * Start the main verticle.
48
     *
49
     * @param startPromise the promise to complete when the verticle is started
50
     * @throws Exception if an error occurs during startup
51
     */
52
    @Override
53
    public void start(Promise<Void> startPromise) throws Exception {
54
        HttpClient httpClient = vertx.createHttpClient(
×
55
                new HttpClientOptions()
56
                        .setConnectTimeout(1000).setIdleTimeoutUnit(TimeUnit.SECONDS)
×
57
                        .setIdleTimeout(60).setReadIdleTimeout(60).setWriteIdleTimeout(60),
×
58
                new PoolOptions().setHttp1MaxSize(200).setHttp2MaxSize(200)
×
59
        );
60

61
        HttpServer proxyServer = vertx.createHttpServer();
×
62
        Router proxyRouter = Router.router(vertx);
×
63
        proxyRouter.route().handler(CorsHandler.create().addRelativeOrigin(".*"));
×
64

65
        // Metrics
66
        final var metricsHttpServer = vertx.createHttpServer();
×
67
        final var metricsRouter = Router.router(vertx);
×
68
        metricsHttpServer.requestHandler(metricsRouter).listen(9394);
×
69

70
        final var metricsRegistry = (PrometheusMeterRegistry) BackendRegistries.getDefaultNow();
×
71
        final var collector = new MetricsCollector(metricsRegistry);
×
72
        metricsRouter.route("/metrics").handler(PrometheusScrapingHandler.create(metricsRegistry));
×
73
        // ----------
74
        // This part is only used if the redirection is not done through Nginx.
75
        // See nginx.conf and this bug report: https://github.com/eclipse-rdf4j/rdf4j/discussions/5120
76
        HttpProxy rdf4jProxy = HttpProxy.reverseProxy(httpClient);
×
77
        String proxy = Utils.getEnvString("RDF4J_PROXY_HOST", "rdf4j");
×
78
        int proxyPort = Utils.getEnvInt("RDF4J_PROXY_PORT", 8080);
×
79
        rdf4jProxy.origin(proxyPort, proxy);
×
80

81
        rdf4jProxy.addInterceptor(new ProxyInterceptor() {
×
82

83
            @Override
84
            public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
85
                ProxyRequest request = context.request();
×
86
                request.setURI(request.getURI().replaceAll("/", "_").replaceFirst("^_repo_", "/rdf4j-server/repositories/"));
×
87
                // For later to try to get HTML tables out:
88
//                                if (request.headers().get("Accept") == null) {
89
//                                        request.putHeader("Accept", "text/html");
90
//                                }
91
//                                request.putHeader("Accept", "application/json");
92
                return ProxyInterceptor.super.handleProxyRequest(context);
×
93
            }
94

95
            @Override
96
            public Future<Void> handleProxyResponse(ProxyContext context) {
97
                ProxyResponse resp = context.response();
×
98
                resp.putHeader("Access-Control-Allow-Origin", "*");
×
99
                resp.putHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
×
100
                // For later to try to get HTML tables out:
101
//                                String acceptHeader = context.request().headers().get("Accept");
102
//                                if (acceptHeader != null && acceptHeader.contains("text/html")) {
103
//                                        resp.putHeader("Content-Type", "text/html");
104
//                                        resp.setBody(Body.body(Buffer.buffer("<html><body><strong>test</strong></body></html>")));
105
//                                }
106
                return ProxyInterceptor.super.handleProxyResponse(context);
×
107
            }
108

109
        });
110
        // ----------
111

112
        proxyRouter.route(HttpMethod.GET, "/repo").handler(req -> handleRedirect(req, "/repo"));
×
113
        proxyRouter.route(HttpMethod.GET, "/repo/*").handler(ProxyHandler.create(rdf4jProxy));
×
114
        proxyRouter.route(HttpMethod.POST, "/repo/*").handler(ProxyHandler.create(rdf4jProxy));
×
115
        proxyRouter.route(HttpMethod.HEAD, "/repo/*").handler(ProxyHandler.create(rdf4jProxy));
×
116
        proxyRouter.route(HttpMethod.OPTIONS, "/repo/*").handler(ProxyHandler.create(rdf4jProxy));
×
117
        proxyRouter.route(HttpMethod.GET, "/tools/*").handler(req -> {
×
118
            final String yasguiPattern = "^/tools/([a-zA-Z0-9-_]+)(/([a-zA-Z0-9-_]+))?/yasgui\\.html$";
×
119
            if (req.normalizedPath().matches(yasguiPattern)) {
×
120
                String repo = req.normalizedPath().replaceFirst(yasguiPattern, "$1$2");
×
121
                req.response()
×
122
                        .putHeader("content-type", "text/html")
×
123
                        .end("<!DOCTYPE html>\n"
×
124
                                + "<html lang=\"en\">\n"
125
                                + "<head>\n"
126
                                + "<meta charset=\"utf-8\">\n"
127
                                + "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n"
128
                                + "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n"
129
                                + "<title>Nanopub Query SPARQL Editor for repository: " + repo + "</title>\n"
130
                                + "<link rel=\"stylesheet\" href=\"/style.css\">\n"
131
                                + "<link href='https://cdn.jsdelivr.net/yasgui/2.6.1/yasgui.min.css' rel='stylesheet' type='text/css'/>\n"
132
                                + "<style>.yasgui .endpointText {display:none !important;}</style>\n"
133
                                + "<script type=\"text/javascript\">localStorage.clear();</script>\n"
134
                                + "</head>\n"
135
                                + "<body>\n"
136
                                + "<h3>Nanopub Query SPARQL Editor for repository: " + repo + "</h3>\n"
137
                                + "<div id='yasgui'></div>\n"
138
                                + "<script src='https://cdn.jsdelivr.net/yasgui/2.6.1/yasgui.min.js'></script>\n"
139
                                + "<script type=\"text/javascript\">\n"
140
                                + "var yasgui = YASGUI(document.getElementById(\"yasgui\"), {\n"
141
                                + "  yasqe:{sparql:{endpoint:'/repo/" + repo + "'},value:'" + Utils.defaultQuery.replaceAll("\n", "\\\\n") + "'}\n"
×
142
                                + "});\n"
143
                                + "</script>\n"
144
                                + "</body>\n"
145
                                + "</html>");
146
            } else {
×
147
                req.response()
×
148
                        .putHeader("content-type", "text/plain")
×
149
                        .setStatusCode(404)
×
150
                        .end("not found");
×
151
            }
152
        });
×
153
        proxyRouter.route(HttpMethod.GET, "/page").handler(req -> handleRedirect(req, "/page"));
×
154
        proxyRouter.route(HttpMethod.GET, "/page/*").handler(req -> {
×
155
            final String pagePattern = "^/page/([a-zA-Z0-9-_]+)(/([a-zA-Z0-9-_]+))?$";
×
156
            if (req.normalizedPath().matches(pagePattern)) {
×
157
                String repo = req.normalizedPath().replaceFirst(pagePattern, "$1$2");
×
158
                req.response()
×
159
                        .putHeader("content-type", "text/html")
×
160
                        .end("<!DOCTYPE html>\n"
×
161
                                + "<html lang=\"en\">\n"
162
                                + "<head>\n"
163
                                + "<meta charset=\"utf-8\">\n"
164
                                + "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n"
165
                                + "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n"
166
                                + "<title>Nanopub Query repo: " + repo + "</title>\n"
167
                                + "<link rel=\"stylesheet\" href=\"/style.css\">\n"
168
                                + "</head>\n"
169
                                + "<body>\n"
170
                                + "<h3>Nanopub Query repo: " + repo + "</h3>\n"
171
                                + "<p>Endpoint: <a href=\"/repo/" + repo + "\">/repo/" + repo + "</a></p>"
172
                                + "<p>YASGUI: <a href=\"/tools/" + repo + "/yasgui.html\">/tools/" + repo + "/yasgui.hml</a></p>"
173
                                + "</body>\n"
174
                                + "</html>");
175
            } else {
×
176
                req.response()
×
177
                        .putHeader("content-type", "text/plain")
×
178
                        .setStatusCode(404)
×
179
                        .end("not found");
×
180
            }
181
        });
×
182
        proxyRouter.route(HttpMethod.GET, "/").handler(req -> {
×
183
            String repos = "";
×
184
            List<String> repoList = new ArrayList<>(TripleStore.get().getRepositoryNames());
×
185
            Collections.sort(repoList);
×
186
            for (String s : repoList) {
×
187
                if (s.startsWith("pubkey_") || s.startsWith("type_")) continue;
×
188
                repos += "<li><code><a href=\"/page/" + s + "\">" + s + "</a></code></li>";
×
189
            }
×
190
            String pinnedApisValue = Utils.getEnvString("NANOPUB_QUERY_PINNED_APIS", "");
×
191
            String[] pinnedApis = pinnedApisValue.split(" ");
×
192
            String pinnedApiLinks = "";
×
193
            if (!pinnedApisValue.isEmpty()) {
×
194
                for (String s : pinnedApis) {
×
195
                    pinnedApiLinks = pinnedApiLinks + "<li><a href=\"openapi/?url=spec/" + s + "%3Fapi-version=latest\">" + s.replaceFirst("^.*/", "") + "</a></li>";
×
196
                }
197
                pinnedApiLinks = "<p>Pinned APIs:</p>\n" +
×
198
                        "<ul>\n" +
199
                        pinnedApiLinks +
200
                        "</ul>\n";
201
            }
202
            req.response()
×
203
                    .putHeader("content-type", "text/html")
×
204
                    .end("<!DOCTYPE html>\n"
×
205
                            + "<html lang='en'>\n"
206
                            + "<head>\n"
207
                            + "<title>Nanopub Query</title>\n"
208
                            + "<meta charset='utf-8'>\n"
209
                            + "<link rel=\"stylesheet\" href=\"/style.css\">\n"
210
                            + "</head>\n"
211
                            + "<body>\n"
212
                            + "<h1>Nanopub Query</h1>"
213
                            + "<p>General repos:</p>"
214
                            + "<ul>" + repos + "</ul>"
215
                            + "<p>Specific repos:</p>"
216
                            + "<ul>"
217
                            + "<li><a href=\"/pubkeys\">Pubkey Repos</a></li>"
218
                            + "<li><a href=\"/types\">Type Repos</a></li>"
219
                            + "</ul>"
220
                            + pinnedApiLinks
221
                            + "</body>\n"
222
                            + "</html>");
223
        });
×
224
        proxyRouter.route(HttpMethod.GET, "/pubkeys").handler(req -> {
×
225
            String repos = "";
×
226
            List<String> repoList = new ArrayList<>(TripleStore.get().getRepositoryNames());
×
227
            Collections.sort(repoList);
×
228
            for (String s : repoList) {
×
229
                if (!s.startsWith("pubkey_")) continue;
×
230
                String hash = s.replaceFirst("^([a-zA-Z0-9-]+)_([a-zA-Z0-9-_]+)$", "$2");
×
231
                Value hashObj = Utils.getObjectForHash(hash);
×
232
                String label;
233
                if (hashObj == null) {
×
234
                    label = "";
×
235
                } else {
236
                    label = " (" + Utils.getShortPubkeyName(hashObj.stringValue()) + ")";
×
237
                }
238
                s = s.replaceFirst("^([a-zA-Z0-9-]+)_([a-zA-Z0-9-_]+)$", "$1/$2");
×
239
                repos += "<li><code><a href=\"/page/" + s + "\">" + s + "</a>" + label + "</code></li>";
×
240
            }
×
241
            req.response()
×
242
                    .putHeader("content-type", "text/html")
×
243
                    .end("<!DOCTYPE html>\n"
×
244
                            + "<html lang='en'>\n"
245
                            + "<head>\n"
246
                            + "<title>Nanopub Query: Pubkey Repos</title>\n"
247
                            + "<meta charset='utf-8'>\n"
248
                            + "<link rel=\"stylesheet\" href=\"/style.css\">\n"
249
                            + "</head>\n"
250
                            + "<body>\n"
251
                            + "<h3>Pubkey Repos</h3>"
252
                            + "<p>Repos:</p>"
253
                            + "<ul>" + repos + "</ul>"
254
                            + "</body>\n"
255
                            + "</html>");
256
        });
×
257
        proxyRouter.route(HttpMethod.GET, "/types").handler(req -> {
×
258
            String repos = "";
×
259
            List<String> repoList = new ArrayList<>(TripleStore.get().getRepositoryNames());
×
260
            Collections.sort(repoList);
×
261
            for (String s : repoList) {
×
262
                if (!s.startsWith("type_")) continue;
×
263
                String hash = s.replaceFirst("^([a-zA-Z0-9-]+)_([a-zA-Z0-9-_]+)$", "$2");
×
264
                Value hashObj = Utils.getObjectForHash(hash);
×
265
                String label;
266
                if (hashObj == null) {
×
267
                    label = "";
×
268
                } else {
269
                    label = " (" + hashObj.stringValue() + ")";
×
270
                }
271
                s = s.replaceFirst("^([a-zA-Z0-9-]+)_([a-zA-Z0-9-_]+)$", "$1/$2");
×
272
                repos += "<li><code><a href=\"/page/" + s + "\">" + s + "</a>" + label + "</code></li>";
×
273
            }
×
274
            req.response()
×
275
                    .putHeader("content-type", "text/html")
×
276
                    .end("<!DOCTYPE html>\n"
×
277
                            + "<html lang='en'>\n"
278
                            + "<head>\n"
279
                            + "<title>Nanopub Query: Type Repos</title>\n"
280
                            + "<meta charset='utf-8'>\n"
281
                            + "<link rel=\"stylesheet\" href=\"/style.css\">\n"
282
                            + "</head>\n"
283
                            + "<body>\n"
284
                            + "<h3>Type Repos</h3>"
285
                            + "<p>Repos:</p>"
286
                            + "<ul>" + repos + "</ul>"
287
                            + "</body>\n"
288
                            + "</html>");
289
        });
×
290
        proxyRouter.route(HttpMethod.GET, "/style.css").handler(req -> {
×
291
            if (css == null) {
×
292
                css = getResourceAsString("style.css");
×
293
            }
294
            req.response().end(css);
×
295
        });
×
296

297
        proxyRouter.route(HttpMethod.GET, "/grlc-spec/*").handler(req -> {
×
298
            GrlcSpecPage gsp = new GrlcSpecPage(req.normalizedPath(), req.queryParams());
×
299
            String spec = gsp.getSpec();
×
300
            if (spec == null) {
×
301
                req.response().setStatusCode(404).end("query definition not found / not valid");
×
302
            } else {
303
                req.response().putHeader("content-type", "text/yaml").end(spec);
×
304
            }
305
        });
×
306

307
        proxyRouter.route(HttpMethod.GET, "/openapi/spec/*").handler(req -> {
×
308
            OpenApiSpecPage osp = new OpenApiSpecPage(req.normalizedPath(), req.queryParams());
×
309
            String spec = osp.getSpec();
×
310
            if (spec == null) {
×
311
                req.response().setStatusCode(404).end("query definition not found / not valid");
×
312
            } else {
313
                req.response().putHeader("content-type", "text/yaml").end(spec);
×
314
            }
315
        });
×
316

317
        proxyRouter.route("/openapi/*").handler(StaticHandler.create("com/knowledgepixels/query/swagger"));
×
318

319
        HttpProxy grlcProxy = HttpProxy.reverseProxy(httpClient);
×
320
        grlcProxy.origin(80, "grlc");
×
321
        grlcProxy.addInterceptor(new ProxyInterceptor() {
×
322

323
            @Override
324
            public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
325
                final String apiPattern = "^/api/(RA[a-zA-Z0-9-_]{43})/([a-zA-Z0-9-_]+)([?].*)?$";
×
326
                if (context.request().getURI().matches(apiPattern)) {
×
327
                    String artifactCode = context.request().getURI().replaceFirst(apiPattern, "$1");
×
328
                    String queryName = context.request().getURI().replaceFirst(apiPattern, "$2");
×
329
                    String grlcUrlParams = "";
×
330
                    String grlcSpecUrlParams = "";
×
331
                    MultiMap pm = context.request().proxiedRequest().params();
×
332
                    for (Entry<String, String> e : pm) {
×
333
                        if (e.getKey().equals("api-version")) {
×
334
                            grlcSpecUrlParams += "&" + e.getKey() + "=" + URLEncoder.encode(e.getValue(), Charsets.UTF_8);
×
335
                        } else {
336
                            grlcUrlParams += "&" + e.getKey() + "=" + URLEncoder.encode(e.getValue(), Charsets.UTF_8);
×
337
                        }
338
                    }
×
339
                    String url = "/api-url/" + queryName +
×
340
                            "?specUrl=" + URLEncoder.encode(GrlcSpecPage.nanopubQueryUrl + "grlc-spec/" + artifactCode + "/?" +
×
341
                            grlcSpecUrlParams, Charsets.UTF_8) + grlcUrlParams;
342
                    context.request().setURI(url);
×
343
                }
344
                return context.sendRequest();
×
345
            }
346

347
            @Override
348
            public Future<Void> handleProxyResponse(ProxyContext context) {
349
                // To avoid double entries:
350
                context.response().headers().remove("Access-Control-Allow-Origin");
×
351
                return context.sendResponse();
×
352
            }
353

354
        });
355

356
        proxyServer.requestHandler(req -> {
×
357
            applyGlobalHeaders(req.response());
×
358
            proxyRouter.handle(req);
×
359
        });
×
360
        proxyServer.listen(9393);
×
361

362
        proxyRouter.route("/api/*").handler(ProxyHandler.create(grlcProxy));
×
363
        proxyRouter.route("/static/*").handler(ProxyHandler.create(grlcProxy));
×
364

365
        vertx.createHttpServer().requestHandler(req -> {
×
366
            try {
367
                final StringBuilder payload = new StringBuilder();
×
368
                req.handler(data -> payload.append(data.toString("UTF-8")));
×
369
                req.endHandler(handler -> {
×
370
                    final String dataString = payload.toString();
×
371
                    try {
372
                        Nanopub np = new NanopubImpl(dataString, RDFFormat.TRIG);
×
373
                        NanopubLoader.load(np, -1);
×
374
                    } catch (MalformedNanopubException ex) {
×
375
                        req.response().setStatusCode(HttpStatus.SC_BAD_REQUEST)
×
376
                                .setStatusMessage(Arrays.toString(ex.getStackTrace()))
×
377
                                .end();
×
378
                        ex.printStackTrace();
×
379
                        return;
×
380
                    }
×
381
                    req.response()
×
382
                            .setStatusCode(HttpStatus.SC_OK)
×
383
                            .end();
×
384
                });
×
385
            } catch (Exception ex) {
×
386
                req.response().setStatusCode(HttpStatus.SC_BAD_REQUEST)
×
387
                        .setStatusMessage(Arrays.toString(ex.getStackTrace()))
×
388
                        .end();
×
389
            }
×
390
        }).listen(9300).onComplete(http -> {
×
391
            if (http.succeeded()) {
×
392
                server2Started = true;
×
393
                if (allServersStarted()) startPromise.complete();
×
394
                System.out.println("HTTP server started on port 9300");
×
395
            } else {
396
                startPromise.fail(http.cause());
×
397
            }
398
        });
×
399

400
        // Periodic metrics update
401
        vertx.setPeriodic(1000, id -> collector.updateMetrics());
×
402

403

404
        new Thread(() -> {
×
405
            try {
406
                var status = StatusController.get().initialize();
×
407
                System.err.println("Current state: " + status.state + ", last committed counter: " + status.loadCounter);
×
408
                if (status.state == StatusController.State.LAUNCHING || status.state == StatusController.State.LOADING_INITIAL) {
×
409
                    // Do the initial nanopublication loading
410
                    StatusController.get().setLoadingInitial(status.loadCounter);
×
411
                    // Fall back to local nanopub loading if the local files are present
412
                    if (!LocalNanopubLoader.init()) {
×
413
                        JellyNanopubLoader.loadInitial(status.loadCounter);
×
414
                    } else {
415
                        System.err.println("Local nanopublication loading finished");
×
416
                    }
417
                    StatusController.get().setReady();
×
418
                } else {
419
                    System.err.println("Initial load is already done");
×
420
                    StatusController.get().setReady();
×
421
                }
422
            } catch (Exception ex) {
×
423
                ex.printStackTrace();
×
424
                System.err.println("Initial load failed, terminating...");
×
425
                Runtime.getRuntime().exit(1);
×
426
            }
×
427

428
            // Start periodic nanopub loading
429
            System.err.println("Starting periodic nanopub loading...");
×
430
            var executor = Executors.newSingleThreadScheduledExecutor();
×
431
            executor.scheduleWithFixedDelay(
×
432
                    JellyNanopubLoader::loadUpdates,
433
                    JellyNanopubLoader.UPDATES_POLL_INTERVAL,
434
                    JellyNanopubLoader.UPDATES_POLL_INTERVAL,
435
                    TimeUnit.MILLISECONDS
436
            );
437
        }).start();
×
438

439
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
×
440
            try {
441
                System.err.println("Gracefully shutting down...");
×
442
                TripleStore.get().shutdownRepositories();
×
443
                vertx.close().toCompletionStage().toCompletableFuture().get(5, TimeUnit.SECONDS);
×
444
                System.err.println("Graceful shutdown completed");
×
445
            } catch (Exception ex) {
×
446
                System.err.println("Graceful shutdown failed");
×
447
                ex.printStackTrace();
×
448
            }
×
449
        }));
×
450
    }
×
451

452
    private String getResourceAsString(String file) {
453
        InputStream is = getClass().getClassLoader().getResourceAsStream("com/knowledgepixels/query/" + file);
×
454
        try (Scanner s = new Scanner(is).useDelimiter("\\A")) {
×
455
            String fileContent = s.hasNext() ? s.next() : "";
×
456
            return fileContent;
×
457
        }
458
    }
459

460
    private static void handleRedirect(RoutingContext req, String path) {
461
        String queryString = "";
×
462
        if (!req.queryParam("query").isEmpty())
×
463
            queryString = "?query=" + URLEncoder.encode(req.queryParam("query").get(0), Charsets.UTF_8);
×
464
        if (req.queryParam("for-type").size() == 1) {
×
465
            String type = req.queryParam("for-type").get(0);
×
466
            req.response().putHeader("location", path + "/type/" + Utils.createHash(type) + queryString);
×
467
            req.response().setStatusCode(301).end();
×
468
        } else if (req.queryParam("for-pubkey").size() == 1) {
×
469
            String type = req.queryParam("for-pubkey").get(0);
×
470
            req.response().putHeader("location", path + "/pubkey/" + Utils.createHash(type) + queryString);
×
471
            req.response().setStatusCode(301).end();
×
472
        } else if (req.queryParam("for-user").size() == 1) {
×
473
            String type = req.queryParam("for-user").get(0);
×
474
            req.response().putHeader("location", path + "/user/" + Utils.createHash(type) + queryString);
×
475
            req.response().setStatusCode(301).end();
×
476
        }
477
    }
×
478

479
    /**
480
     * Apply headers to the response that should be present for all requests.
481
     *
482
     * @param response The response to which the headers should be applied.
483
     */
484
    private static void applyGlobalHeaders(HttpServerResponse response) {
485
        response.putHeader("Nanopub-Query-Status", StatusController.get().getState().state.toString());
×
486
    }
×
487
}
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