Backlinks
Extend LinkedDataHub with custom Docker images, Java endpoints and XSLT stylesheets
Every component in LinkedDataHub is data-driven and was designed with extensibility in mind. You can override behavior (e.g. Java method or XSLT template) without having to modify LinkedDataHub's codebase, and more importantly, without having to write the same logic from scratch.
If you are building your first app, start with the tutorial — this guide covers the layers beyond it.
Docker
Mounting files — config, ontologies, stylesheets — into the default Docker setup covers
many cases; for local runs, mount them with docker-compose.override.yml as shown in Compose overrides. But you may also want to build a dedicated Docker image for your app using LinkedDataHub
as the base. Usually this is done to COPY files inside the image or RUN additional commands.
The recommended approach is a multi-stage Docker build: the first stage uses Maven to compile your WAR overlay, and the second stage copies it into the LinkedDataHub base image alongside any static files:
FROM maven:3.9-eclipse-temurin-21 AS maven WORKDIR /usr/src/myapp COPY src /usr/src/myapp/src COPY pom.xml /usr/src/myapp/pom.xml RUN mvn clean install # ================= FROM atomgraph/linkeddatahub:6.0.0 WORKDIR $CATALINA_HOME ENV SERVLET_NAME=com.example.myapp.Application COPY --from=maven /usr/src/myapp/target/ROOT webapps/ROOT COPY files/layout.xsl /usr/local/tomcat/webapps/ROOT/static/com/example/myapp/xsl/layout.xsl COPY files/client.xsl /usr/local/tomcat/webapps/ROOT/static/com/example/myapp/xsl/client.xsl COPY files/style.css /usr/local/tomcat/webapps/ROOT/static/com/example/myapp/css/style.css
Replace 6.0.0 with the LinkedDataHub release you are running.
SERVLET_NAME must be set to the fully-qualified name of your JAX-RS application class (see the
Java section below).
Java
The Java layer of LinkedDataHub is a Maven project with a webapp layout. It uses JAX-RS — specifically Jersey 3 — as the HTTP/REST framework, and Apache Jena 6 for RDF I/O.
If you want to extend the Java codebase, for example to add a custom REST endpoint, create a new Maven project (Java 21, packaged as WAR named ROOT) with LinkedDataHub as a WAR overlay dependency:
<dependencies>
<dependency>
<groupId>com.atomgraph</groupId>
<artifactId>linkeddatahub</artifactId>
<version>6.0.0</version>
<classifier>classes</classifier>
</dependency>
<dependency>
<groupId>com.atomgraph</groupId>
<artifactId>linkeddatahub</artifactId>
<version>6.0.0</version>
<type>war</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<release>21</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warName>ROOT</warName>
<webappDirectory>target/ROOT</webappDirectory>
<attachClasses>true</attachClasses>
<overlays>
<overlay>
<groupId>com.atomgraph</groupId>
<artifactId>linkeddatahub</artifactId>
</overlay>
</overlays>
</configuration>
</plugin>
</plugins>
</build>After adding a new endpoint, extend LinkedDataHub's JAX-RS application class (com.atomgraph.linkeddatahub.Application) and register your class there. Set the SERVLET_NAME Docker environment variable to the fully-qualified name of your subclass so LinkedDataHub
loads it instead of the default application.
By convention, static files (e.g. stylesheets, images) are placed in the src/main/webapp/static/ folder in the codebase, which then becomes /usr/local/tomcat/webapps/ROOT/static/ within the webapp deployed in the Docker container, and is served at static/ under the dataspace's base URI.
This means that if you want to deploy static files as part of your LinkedDataHub app, you will have to either mount them into the /usr/local/tomcat/webapps/ROOT/static/ folder in the container, or copy them into a custom Docker image to the same effect.
You can allow Java debugger access using configuration properties.
XSLT
LinkedDataHub uses XSLT 3.0 for UI rendering both on the server- and on the client-side.
You can specify a custom server-side XSLT 3.0 stylesheet in the dataspace configuration.
You can reuse LinkedDataHub's stylesheets by importing them as explained in the Change layout guide.
Server-side
The default server-side stylesheet layout.xsl and its imports can be found in the src/main/webapp/static/com/atomgraph/linkeddatahub/xsl folder.
Client-side
Client-side stylesheets render the layout in the browser and implement the interactive parts of the UI (event handling, AJAX calls etc.) using the IXSL extension provided by the Saxon-JS 3 library. After the server renders the initial page, the client-side stylesheet injects the left sidebar, navigation, document and tab panes, content blocks, forms and modal dialogs into the DOM, and re-renders in place as the user navigates. This makes the frontend almost entirely declarative: it requires virtually no hand-written JavaScript, apart from third-party libraries such as Google Charts and OpenLayers.
Client-side stylesheets share common document-, resource-, and property-level templates
with the server-side stylesheets. The client-side stylesheet may not contain any XML
entity declarations (limitation of
Saxon-JS) and must be compiled into a SEF file before it can be run by the Saxon-JS runtime.
The URL of the client-side SEF stylesheet is passed as the $client-stylesheet parameter of the document-level server-side xhtml:Script template.
You can also modify or extend the default RDF datasets used by LinkedDataHub. However, a better practice is to use the CLI to create documents and to import CSV and RDF data.
See the LinkedDataHub app repository for more examples.
Continue with the Change layout guide or see how these layers fit together in the Beyond low-code tutorial.