<https://docs.linkeddatahub.com/extending/build-apps/#content>
        a       <https://w3id.org/atomgraph/linkeddatahub#XHTML>;
        <http://www.w3.org/1999/02/22-rdf-syntax-ns#value>
                "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n    <p class=\"ldh-body-lg\">Extend LinkedDataHub with custom Docker images, Java endpoints and XSLT stylesheets</p>\n    <p>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\n        codebase, and more importantly, without having to write the same logic from scratch.</p>\n    <p>If you are building your first app, start with the <a href=\"../../tutorial/\">tutorial</a> — this guide covers the layers beyond it.</p>\n    <div>\n        <h2 id=\"docker\">Docker</h2>\n        <p>Mounting files — config, ontologies, stylesheets — into the default Docker setup covers many cases; for local runs, mount them with <samp>docker-compose.override.yml</samp> as shown in <a href=\"../../reference/configuration/#compose-override\">Compose overrides</a>. But you may also want to build a dedicated Docker image for your app using LinkedDataHub as the base. Usually this is done to <code>COPY</code> files inside the image or <code>RUN</code> additional commands.</p>\n        <p>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:</p>\n        <pre>FROM maven:3.9-eclipse-temurin-21 AS maven\n\nWORKDIR /usr/src/myapp\n\nCOPY src /usr/src/myapp/src\nCOPY pom.xml /usr/src/myapp/pom.xml\n\nRUN mvn clean install\n\n# =================\n\nFROM atomgraph/linkeddatahub:6.0.0\n\nWORKDIR $CATALINA_HOME\n\nENV SERVLET_NAME=com.example.myapp.Application\n\nCOPY --from=maven /usr/src/myapp/target/ROOT webapps/ROOT\n\nCOPY files/layout.xsl /usr/local/tomcat/webapps/ROOT/static/com/example/myapp/xsl/layout.xsl\nCOPY files/client.xsl /usr/local/tomcat/webapps/ROOT/static/com/example/myapp/xsl/client.xsl\nCOPY files/style.css  /usr/local/tomcat/webapps/ROOT/static/com/example/myapp/css/style.css</pre>\n        <p>Replace <samp>6.0.0</samp> with the LinkedDataHub release you are running.</p>\n        <p><code>SERVLET_NAME</code> must be set to the fully-qualified name of your JAX-RS application class (see the <a href=\"#java\">Java section</a> below).</p>\n    </div>\n    <div>\n        <h2 id=\"java\">Java</h2>\n        <p>The Java layer of LinkedDataHub is a Maven project with a webapp layout. It uses JAX-RS — specifically <a href=\"https://eclipse-ee4j.github.io/jersey/\" target=\"_blank\">Jersey 3</a> — as the HTTP/REST framework, and <a href=\"https://jena.apache.org\" target=\"_blank\">Apache Jena</a> 6 for RDF I/O.</p>\n        <p>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 <samp>ROOT</samp>) with LinkedDataHub as a WAR overlay dependency:</p>\n        <pre>&lt;dependencies&gt;\n    &lt;dependency&gt;\n        &lt;groupId&gt;com.atomgraph&lt;/groupId&gt;\n        &lt;artifactId&gt;linkeddatahub&lt;/artifactId&gt;\n        &lt;version&gt;6.0.0&lt;/version&gt;\n        &lt;classifier&gt;classes&lt;/classifier&gt;\n    &lt;/dependency&gt;\n    &lt;dependency&gt;\n        &lt;groupId&gt;com.atomgraph&lt;/groupId&gt;\n        &lt;artifactId&gt;linkeddatahub&lt;/artifactId&gt;\n        &lt;version&gt;6.0.0&lt;/version&gt;\n        &lt;type&gt;war&lt;/type&gt;\n    &lt;/dependency&gt;\n&lt;/dependencies&gt;\n&lt;build&gt;\n    &lt;plugins&gt;\n        &lt;plugin&gt;\n            &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;\n            &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;\n            &lt;configuration&gt;\n                &lt;release&gt;21&lt;/release&gt;\n            &lt;/configuration&gt;\n        &lt;/plugin&gt;\n        &lt;plugin&gt;\n            &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;\n            &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;\n            &lt;configuration&gt;\n                &lt;warName&gt;ROOT&lt;/warName&gt;\n                &lt;webappDirectory&gt;target/ROOT&lt;/webappDirectory&gt;\n                &lt;attachClasses&gt;true&lt;/attachClasses&gt;\n                &lt;overlays&gt;\n                    &lt;overlay&gt;\n                        &lt;groupId&gt;com.atomgraph&lt;/groupId&gt;\n                        &lt;artifactId&gt;linkeddatahub&lt;/artifactId&gt;\n                    &lt;/overlay&gt;\n                &lt;/overlays&gt;\n            &lt;/configuration&gt;\n        &lt;/plugin&gt;\n    &lt;/plugins&gt;\n&lt;/build&gt;</pre>\n        <p>After adding a new endpoint, extend LinkedDataHub's JAX-RS application class (<code>com.atomgraph.linkeddatahub.Application</code>) and register your class there. Set the <code>SERVLET_NAME</code> Docker environment variable to the fully-qualified name of your subclass so LinkedDataHub loads it instead of the default application.</p>\n        <p>By convention, static files (e.g. stylesheets, images) are placed in the <samp>src/main/webapp/static/</samp> folder in the codebase, which then becomes <samp>/usr/local/tomcat/webapps/ROOT/static/</samp> within the webapp deployed in the Docker container, and is served at <samp>static/</samp> under the dataspace's base URI.</p>\n        <p>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 <samp>/usr/local/tomcat/webapps/ROOT/static/</samp> folder in the container, or copy them into a custom Docker image to the same effect.</p>\n        <p>You can allow Java debugger access using <a href=\"../../reference/configuration/#debug\">configuration properties</a>.</p>\n    </div>\n    <div>\n        <h2 id=\"xslt\">XSLT</h2>\n        <p>LinkedDataHub uses <a href=\"https://www.w3.org/TR/xslt-30/\" target=\"_blank\">XSLT 3.0</a> for UI rendering both on the server- and on the client-side.</p>\n        <p>You can specify a custom server-side XSLT 3.0 stylesheet in the <a href=\"../../user-guide/manage-dataspaces/#change-stylesheet\">dataspace configuration</a>.</p>\n        <p>You can reuse LinkedDataHub's stylesheets by importing them as explained in the <a href=\"../change-layout/\">Change layout</a> guide.</p>\n        <h3 id=\"server-side-xslt\">Server-side</h3>\n        <p>The default server-side stylesheet <samp>layout.xsl</samp> and its imports can be found in the <samp>src/main/webapp/static/com/atomgraph/linkeddatahub/xsl</samp> folder.</p>\n        <h3 id=\"client-side-xslt\">Client-side</h3>\n        <p>Client-side stylesheets render the layout in the browser and implement the interactive parts of the UI (event handling, AJAX calls etc.) using the <a href=\"https://www.saxonica.com/saxonjs/documentation3/index.html#!ixsl-extension\" target=\"_blank\">IXSL extension</a>\n            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.</p>\n        <p>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\n            Saxon-JS) and must be <a href=\"https://www.saxonica.com/saxonjs/documentation3/index.html#!starting/export\" target=\"_blank\">compiled into a SEF file</a> before it can be run by the Saxon-JS runtime.\n            The URL of the client-side SEF stylesheet is passed as the <code>$client-stylesheet</code> parameter of the document-level server-side <code>xhtml:Script</code> template.</p>\n    </div>\n    <p>You can also modify or extend the <a href=\"../../reference/dataset/#default-datasets\">default RDF datasets</a> used by LinkedDataHub. However, a better practice is to use the\n        <a href=\"../../reference/command-line-interface/\">CLI</a> to create documents and to <a href=\"../../reference/imports/\">import CSV and RDF data</a>.</p>\n    <p><a href=\"https://github.com/AtomGraph/LinkedDataHub-Apps\" target=\"_blank\">See the LinkedDataHub app repository for more examples.</a></p>\n    <p class=\"ldh-body-lg\">Continue with the <a href=\"../change-layout/\">Change layout</a> guide or see how these layers fit together in the <a href=\"../../tutorial/beyond-low-code/\">Beyond low-code</a> tutorial.</p>\n</div>"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral> .

<https://docs.linkeddatahub.com/extending/build-apps/>
        a       <https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#Item>;
        <http://www.w3.org/1999/02/22-rdf-syntax-ns#_1>
                <https://docs.linkeddatahub.com/extending/build-apps/#content>;
        <http://purl.org/dc/terms/created>
                "2026-09-29T09:52:12.013Z"^^<http://www.w3.org/2001/XMLSchema#dateTime>;
        <http://purl.org/dc/terms/creator>
                <https://admin.linkeddatahub.com/acl/agents/5ba81960-d511-4a3b-8b9a-cb5bb278dd95/#this>;
        <http://purl.org/dc/terms/description>
                "Extend LinkedDataHub with custom Docker images, Java endpoints and XSLT stylesheets";
        <http://purl.org/dc/terms/title>
                "Build apps";
        <http://rdfs.org/sioc/ns#has_container>
                <https://docs.linkeddatahub.com/extending/>;
        <http://www.w3.org/ns/auth/acl#owner>
                <https://admin.linkeddatahub.com/acl/agents/5ba81960-d511-4a3b-8b9a-cb5bb278dd95/#this> .
