diff --git a/experimental/uloapi/README.md b/experimental/uloapi/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9b93224b33a9fa044b1090e62d18e97f0ba3f31f --- /dev/null +++ b/experimental/uloapi/README.md @@ -0,0 +1,24 @@ +uloapi +====== + +This repository contains the `uloapi` codebase, a JVM (Java) project +that uses the RDF4J library [1] which I might end up using for +connecting MMT to the data set extracted/indexed from MathHub. + +Running +------- + +To build and start the demo, first make sure the configuration file +`uloapi.properties` is to your liking. Once ready, simply run + + mvn compile exec:java + +to run the demo. To compile all classes including dependencies in one +single JAR, run + + mvn install + +References +---------- + +[1] https://rdf4j.org/ diff --git a/experimental/uloapi/pom.xml b/experimental/uloapi/pom.xml index 950618486c30fc1581c3df7abe8d5c39ddc75010..e30da410e63f73c685cdc190e8f849ab40784016 100644 --- a/experimental/uloapi/pom.xml +++ b/experimental/uloapi/pom.xml @@ -83,5 +83,10 @@ <artifactId>spark-template-freemarker</artifactId> <version>2.7.1</version> </dependency> + <dependency> + <groupId>org.jetbrains</groupId> + <artifactId>annotations</artifactId> + <version>19.0.0</version> + </dependency> </dependencies> </project> \ No newline at end of file diff --git a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Errors.java b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Errors.java index 23b78eadfd3d130fecbec56679087e406b34e2df..dce0b3aa40251aa7e7c05d7f21ca58989841aaaf 100644 --- a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Errors.java +++ b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Errors.java @@ -1,10 +1,9 @@ package info.mathhub.uloapi.html; import org.eclipse.jetty.http.HttpStatus; -import spark.ModelAndView; -import spark.Request; -import spark.Response; -import spark.Route; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import spark.*; import spark.template.freemarker.FreeMarkerEngine; import java.util.HashMap; @@ -13,6 +12,8 @@ import java.util.Map; public class Errors { private Errors() {}; + private static final Logger log = LoggerFactory.getLogger(Errors.class); + /** * Singleton instance of the Freemarker engine for use with errors. * Used in {@link Errors#createError}. @@ -35,7 +36,22 @@ public class Errors { return createError(HttpStatus.INTERNAL_SERVER_ERROR_500).handle(request, response); }; - private static Route createError(int status) { + public static final ExceptionHandler<Exception> exceptionHandler = (exception, request, response) -> { + final Map<String, Object> model = new HashMap<>(); + model.put("exception_message", exception.getMessage()); + + try { + createError(HttpStatus.INTERNAL_SERVER_ERROR_500, model).handle(request, response); + } catch (Exception e) { + log.error(e.getMessage()); + for (final StackTraceElement element : e.getStackTrace()) { + log.error(element.toString()); + } + } + }; + + @SafeVarargs + private static Route createError(int status, Map<String, Object> ...additionalModels) { return (Request request, Response response) -> { // set content type @@ -44,8 +60,12 @@ public class Errors { // prepare model final Map<String, Object> model = new HashMap<>(); - model.put("status", status); - model.put("description", HttpStatus.getMessage(status)); + model.put("http_status", status); + model.put("http_description", HttpStatus.getMessage(status)); + + for (final Map<String, Object> additionalModel : additionalModels) { + model.putAll(additionalModel); + } // render diff --git a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Main.java b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Main.java index 16812fb32ad8e3c5bd90787a42a645e01c747c35..f84bdfcd6d28fa221ef14b83ced3e75d2dc0c9b8 100644 --- a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Main.java +++ b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Main.java @@ -12,9 +12,10 @@ public class Main { public static void main(String[] args) { get("/", Routes.index, new FreeMarkerEngine()); + get("/statistics", Routes.statistics, new FreeMarkerEngine()); - notFound(Errors.notFound); internalServerError(Errors.internalServerError); + notFound(Errors.notFound); after(Filters.setHtmlContentType); } diff --git a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Routes.java b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Routes.java index 4371cf7151bf824d625ce8b335da31855f30d9ec..1776d2b9d2ddcbac7c0564f9cbea0bd9063636d8 100644 --- a/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Routes.java +++ b/experimental/uloapi/src/main/java/info/mathhub/uloapi/html/Routes.java @@ -1,6 +1,7 @@ package info.mathhub.uloapi.html; import info.mathhub.uloapi.query.Query; +import info.mathhub.uloapi.query.Statistics; import spark.*; import java.util.HashMap; @@ -15,4 +16,16 @@ public class Routes { public static final TemplateViewRoute index = (Request request, Response response) -> { return new ModelAndView(null, "index.flt"); }; + + public static final TemplateViewRoute statistics = (Request request, Response response) -> { + final Query query = Query.getSingleton(); + final Statistics statistics = query.getStatistics(); + + final Map<String, Object> model = new HashMap<>(); + model.put("statistics_num_triplets", statistics.numTriplets); + model.put("statistics_is_writeable", Boolean.toString(statistics.isWriteable)); + model.put("statistics_data_dir", statistics.dataDir); + + return new ModelAndView(model, "statistics.flt"); + }; } diff --git a/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Query.java b/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Query.java index 70175d7ee0b7dd5866e132e0876b71fb9f0a4b24..8369c91dfa3b5d90f6a430dce769895c9db8d121 100644 --- a/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Query.java +++ b/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Query.java @@ -2,6 +2,8 @@ package info.mathhub.uloapi.query; import info.mathhub.uloapi.config.Config; +import java.io.File; + public class Query { private final String serverUrl; private final String repository; @@ -22,11 +24,23 @@ public class Query { } public Statistics getStatistics() { - final GraphDB.Operation<Long> operation = (manager, repository, connection) -> { - return connection.size(); + final GraphDB.Operation<Statistics> operation = (manager, repository, connection) -> { + final Statistics statistics = new Statistics(); + + statistics.isWriteable = repository.isWritable(); + statistics.numTriplets = connection.size(); + + { + final File dataDir = repository.getDataDir(); + + if (dataDir != null) { + statistics.dataDir = dataDir.getAbsolutePath(); + } + } + + return statistics; }; - final long numTriplets = GraphDB.execute(this.serverUrl, this.repository, operation); - return new Statistics(numTriplets); + return GraphDB.execute(this.serverUrl, this.repository, operation); } } diff --git a/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Statistics.java b/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Statistics.java index 380e6ca9d46f6c31d9c247c943d25f563ce77e3f..a5735868b8edf2e49d831851625dc3504522d5b8 100644 --- a/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Statistics.java +++ b/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/Statistics.java @@ -1,5 +1,7 @@ package info.mathhub.uloapi.query; +import org.jetbrains.annotations.NotNull; + /** * Contains statistic information about the backing storage. */ @@ -9,7 +11,15 @@ public class Statistics { */ public long numTriplets; - Statistics(long numTriplets) { - this.numTriplets = numTriplets; - } + /** + * Whether the data in this repository is writeable. If it isn't, + * it is only readable. + */ + public boolean isWriteable; + + /** + * The directory on the server where the data is stored. + */ + @NotNull + public String dataDir = "unknown"; } diff --git a/experimental/uloapi/src/main/resources/spark/template/freemarker/base.flt b/experimental/uloapi/src/main/resources/spark/template/freemarker/base.flt index 00db730910a21bcef2d729cd062a81f5ccd55be8..a0d1317491b573468964f577969c6b2fe067f9aa 100644 --- a/experimental/uloapi/src/main/resources/spark/template/freemarker/base.flt +++ b/experimental/uloapi/src/main/resources/spark/template/freemarker/base.flt @@ -18,12 +18,30 @@ font-size: 12pt; } + nav { + border-bottom: solid 1px; + padding-bottom: 1em; + padding-top: 1em; + } + + code { + font-family: monospace; + } + a { color: blue; } + + h1 { + display: inline-block; + font-weight: bold; + } </style> </head> <body> + <nav> + <h1><a href="/">uloapi</a></h1> | <a href="/statistics">Statistics</a> | <a href="/queries">Queries</a> + </nav> <main> <@page_main/> </main> diff --git a/experimental/uloapi/src/main/resources/spark/template/freemarker/error.flt b/experimental/uloapi/src/main/resources/spark/template/freemarker/error.flt index aab46438a25ba64d3a5c06602f3fa4719e9cf52f..810c1695682b05f2700eb2ecc5ed72dcf7d5b45f 100644 --- a/experimental/uloapi/src/main/resources/spark/template/freemarker/error.flt +++ b/experimental/uloapi/src/main/resources/spark/template/freemarker/error.flt @@ -1,12 +1,17 @@ <#include "base.flt"> <#macro page_title> - Error ${status} + Error ${http_status} </#macro> <#macro page_main> - <h1>Error ${status}: ${description}</h1> - <p>Grow old or die trying.</p> + <h2>Error ${http_status}: ${http_description}</h2> + + <#if message?has_content> + <code> + ${exception_message} + </code> + </#if> </#macro> <@display_page/> diff --git a/experimental/uloapi/src/main/resources/spark/template/freemarker/index.flt b/experimental/uloapi/src/main/resources/spark/template/freemarker/index.flt index 9f0757657d6a33ef790a760c752b7fff48827c55..6a0791ec765a2edd3ddbbbfc630b2f2fb88f927a 100644 --- a/experimental/uloapi/src/main/resources/spark/template/freemarker/index.flt +++ b/experimental/uloapi/src/main/resources/spark/template/freemarker/index.flt @@ -5,9 +5,9 @@ </#macro> <#macro page_main> - <h1>ULO/RDF Endpoint</h1> + <h2>ULO/RDF Endpoint</h2> <p>This is a technology demo of an ULO/RDF Endpoint.</p> - <h2>Introduction</h2> + <h3>Introduction</h3> <p> Working with RDF triplets is somewhat easy with the <a href="https://rdf4j.org">RDF4J</a> library. This demo uses RDF4J to illustrate that (1) a connection to an existing database can be established @@ -18,10 +18,6 @@ It is no incident that this demo is hacked together with a JVM-based stack. Potential integration into MMT should be easier with lessons learned from this demo. </p> - <h2>Demos</h2> - <ul> - <li><a href="/statistics">Show (not every interesting) Statistics</a> about the imported ULO/RDF dataset.</li> - </ul> </#macro> <@display_page/> \ No newline at end of file diff --git a/experimental/uloapi/src/main/resources/spark/template/freemarker/statistics.flt b/experimental/uloapi/src/main/resources/spark/template/freemarker/statistics.flt new file mode 100644 index 0000000000000000000000000000000000000000..750b534a437ca4d54bbb661616019a4aac39d535 --- /dev/null +++ b/experimental/uloapi/src/main/resources/spark/template/freemarker/statistics.flt @@ -0,0 +1,24 @@ +<#include "base.flt"> + +<#macro page_title> + Statistics +</#macro> + +<#macro page_main> + <h2>Statistics</h2> + + <p> + Show not very interesting statistics about the connected database. Illustrates + that we made a connection and can take a look at imported data. + </p> + + <h3>Counts</h3> + + <ul> + <li>Total Triplets in Repository: <code>${statistics_num_triplets}</code></li> + <li>Repository Writeable: <code>${statistics_is_writeable}</code></li> + <li>Repository Data directory: <code>${statistics_data_dir}</code></li> + </ul> +</#macro> + +<@display_page/>