Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9292463
[maven-release-plugin] prepare for next development iteration
namedgraph Jun 9, 2026
b05cb82
Post-release version bump
namedgraph Jun 9, 2026
ff479c3
Add regression test for Varnish cache poisoning via On-Behalf-Of dele…
namedgraph Jun 17, 2026
d937d8c
Bypass varnish-frontend cache for On-Behalf-Of requests
namedgraph Jun 17, 2026
72804d7
Show progress cursor while 3D graph requests are in flight
namedgraph Jun 17, 2026
cd7dd01
Defer 'active' token on new tab panes to ldh:ActivateTab
namedgraph Jun 17, 2026
62656d7
Extend cache-poisoning regression to the Client-Cert + RDF path
namedgraph Jun 18, 2026
699bddd
Bypass varnish-frontend cache for any Client-Cert request outside /st…
namedgraph Jun 18, 2026
5febdea
Trim cache-poisoning regression failure output
namedgraph Jun 18, 2026
9ec3b67
Forward upstream validators for HEAD proxy responses
namedgraph Jun 18, 2026
2b2cc67
Javadoc fix
namedgraph Jun 18, 2026
a6d71b5
Use ParameterizedSparqlString for proxy namespace DESCRIBE query
namedgraph Jun 18, 2026
1bff739
Add unit tests for graph store, RDF import streaming, and proxied Web…
namedgraph Jun 18, 2026
997da52
Jena 6 ont-api (#316)
namedgraph Jun 21, 2026
90cad29
HTTP test for bnodes after PATCH
namedgraph Jun 22, 2026
239dcf8
Skolemize bnodes after PATCH
namedgraph Jun 22, 2026
8dfd424
Removed unnecessary frontend purge
namedgraph Jun 23, 2026
d33e785
Set Fuseki memory limits, heap, and restart policy
namedgraph Jun 23, 2026
197485a
Merge branch 'master' into develop
namedgraph Jul 1, 2026
4293ee9
Removed unused imports
namedgraph Jul 1, 2026
7ba5dd0
Upgraded dependencies: Guava 33.6.0, twirl 2.0.0, client 5.0.1, jsoup…
namedgraph Jul 5, 2026
3fddca5
Web-Client bump
namedgraph Jul 5, 2026
a2dd80b
Re-trigger CI
namedgraph Jul 5, 2026
5be0d25
Adapt to StylesheetResolver(Client) constructor
namedgraph Jul 5, 2026
35e6b52
Make per-app OntologyRepository creation thread-safe
namedgraph Jul 5, 2026
b1d06bf
Drop dead cacheModelLoads and preemptiveAuth config flags
namedgraph Jul 5, 2026
8c49aa5
OntologyRepository: bound the ontology cache with an evicting store
namedgraph Jul 5, 2026
6b5315f
OntologyRepository: serve bundled vocabularies without querying SPARQL
namedgraph Jul 5, 2026
5d4d91a
OntologyFilter: materialize each ontology once under a lock
namedgraph Jul 5, 2026
b53a2cf
Seed the ad-hoc ontology repository in Namespace
namedgraph Jul 5, 2026
0e8c831
Web-Client bump
namedgraph Jul 6, 2026
6b7277f
Add ldh CLI: Java port of the bin/ HTTP API scripts
namedgraph Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
/http-tests/out
/fuseki
.claude/scheduled_tasks.lock
/cli/target/
2 changes: 0 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ ENV SOURCE_COMMIT=$SOURCE_COMMIT

WORKDIR $CATALINA_HOME

ENV CACHE_MODEL_LOADS=true

ENV STYLESHEET=static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/layout.xsl

ENV CACHE_STYLESHEET=true
Expand Down
128 changes: 128 additions & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# LinkedDataHub CLI

`ldh` is a command line interface for the [LinkedDataHub](https://github.com/AtomGraph/LinkedDataHub) HTTP API.
It mirrors the shell scripts in [`bin/`](../bin) one command per script, with the same option names,
implemented in Java on top of AtomGraph [Core](https://github.com/AtomGraph/Core)'s `GraphStoreClient`
(picocli + Apache Jena). It replaces the scripts' external dependencies (`curl`, `turtle`, `python`,
`uuidgen`, `shasum`) with a single executable jar.

## Build

Requires Java 21 and Maven:

```bash
cd cli
mvn package
```

This produces the self-contained `target/ldh.jar`. The `cli/bin/ldh` launcher runs it:

```bash
export PATH="$PATH:$(pwd)/bin"
ldh --help
```

## Authentication

Commands authenticate with a WebID client certificate from a **PKCS12 (.p12) keystore** — the format
produced by `bin/webid-keygen.sh`:

```bash
ldh get --accept text/turtle \
-f ssl/owner/keystore.p12 -p "$OWNER_CERT_PWD" \
https://localhost:4443/
```

Server certificates are not validated (equivalent of `curl -k`), matching the shell scripts'
behavior against self-signed development instances.

### Environment variable defaults

Repeated options can be set once via environment variables:

| Variable | Option |
|---|---|
| `LDH_CERT_FILE` | `-f`, `--cert-file` |
| `LDH_CERT_PASSWORD` | `-p`, `--cert-password` |
| `LDH_BASE` | `-b`, `--base` |
| `LDH_PROXY` | `--proxy` |

```bash
export LDH_CERT_FILE=ssl/owner/keystore.p12 LDH_CERT_PASSWORD=... LDH_BASE=https://localhost:4443/

ldh create-container --parent "$LDH_BASE" --title "Some" --slug some
ldh create-item --container https://localhost:4443/some/ --title "My item" --slug my-item
```

## Conventions

- Commands that create or append to a document print its URL as the only line on stdout, so shell
pipelines keep working: `item=$(ldh create-item ...)`. `add-file` prints the content-addressed
upload URI (`{base}uploads/{sha1}`). All diagnostics go to stderr.
- Exit codes: `0` success, `1` HTTP error status or runtime failure (message on stderr, stack trace
with `--verbose`), `2` usage error.
- `--proxy` rewrites the request URI's origin to the proxy's origin, like the scripts do; printed
URLs keep the logical origin.
- `post`/`put` read RDF from stdin and resolve relative URIs against the target URI (the scripts'
`turtle --base` piping); `patch` reads a SPARQL 1.1 update from stdin, validates it and sends it
verbatim.

Shell completion: `source <(ldh generate-completion)` (bash/zsh).

## Script → command migration

| Script | Command |
|---|---|
| `get.sh` | `ldh get` |
| `post.sh` | `ldh post` |
| `put.sh` | `ldh put` |
| `patch.sh` | `ldh patch` |
| `delete.sh` | `ldh delete` |
| `create-item.sh` | `ldh create-item` |
| `create-container.sh` | `ldh create-container` |
| `add-view.sh` | `ldh add-view` |
| `add-construct.sh` | `ldh add-construct` |
| `add-select.sh` | `ldh add-select` |
| `add-result-set-chart.sh` | `ldh add-result-set-chart` |
| `add-file.sh` | `ldh add-file` |
| `add-generic-service.sh` | `ldh add-generic-service` |
| `admin/clear-ontology.sh` | `ldh admin clear-ontology` |
| `admin/add-ontology-import.sh` | `ldh admin add-ontology-import` |
| `admin/ontologies/create-ontology.sh` | `ldh admin ontologies create-ontology` |
| `admin/ontologies/import-ontology.sh` | `ldh admin ontologies import-ontology` |
| `admin/ontologies/add-class.sh` | `ldh admin ontologies add-class` |
| `admin/ontologies/add-constructor.sh` | `ldh admin ontologies add-constructor` |
| `admin/ontologies/add-select.sh` | `ldh admin ontologies add-select` |
| `admin/ontologies/add-property-constraint.sh` | `ldh admin ontologies add-property-constraint` |
| `admin/ontologies/add-restriction.sh` | `ldh admin ontologies add-restriction` |
| `admin/acl/create-group.sh` | `ldh admin acl create-group` |
| `admin/acl/create-authorization.sh` | `ldh admin acl create-authorization` |
| `admin/acl/add-agent-to-group.sh` | `ldh admin acl add-agent-to-group` |
| `admin/acl/make-public.sh` | `ldh admin acl make-public` |
| `admin/packages/install-package.sh` | `ldh admin packages install-package` |
| `admin/packages/uninstall-package.sh` | `ldh admin packages uninstall-package` |
| `content/add-object-block.sh` | `ldh content add-object-block` |
| `content/add-xhtml-block.sh` | `ldh content add-xhtml-block` |
| `content/remove-block.sh` | `ldh content remove-block` |
| `imports/add-csv-import.sh` | `ldh imports add-csv-import` |
| `imports/add-rdf-import.sh` | `ldh imports add-rdf-import` |
| `imports/import-csv.sh` | `ldh imports import-csv` |
| `imports/import-rdf.sh` | `ldh imports import-rdf` |

Local certificate tooling (`webid-keygen.sh`, `webid-keygen-pem.sh`, `webid-uri.sh`,
`webid-modulus.sh`, `server-cert-gen.sh`) and the experimental `sitemap/` generator remain
shell scripts.

### Differences from the scripts

- `-f/--cert-pem-file` is now `-f/--cert-file` and takes the `.p12` keystore directly — no
PEM conversion needed.
- `create-group` writes the `--name` value into `foaf:name`/`dct:title` (the script wrote an
unset variable, producing empty literals).
- `add-generic-service` drops the documented-but-unparsed `--slug` option.
- `add-csv-import`/`import-csv` default `--delimiter` to `,` (the script required it despite
documenting a default).
- `install-package`/`uninstall-package` print nothing on success instead of the raw HTTP status
code; use the exit code.
- `import-csv`/`import-rdf` run their steps in-process instead of spawning subscripts, and pass
`--description` through to the import metadata.
8 changes: 8 additions & 0 deletions cli/bin/ldh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash

# Launcher for the LinkedDataHub CLI.
# Uses the jar built by `mvn package` unless LDH_JAR points elsewhere.

dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

exec java -jar "${LDH_JAR:-$dir/../target/ldh.jar}" "$@"
162 changes: 162 additions & 0 deletions cli/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.atomgraph</groupId>
<artifactId>linkeddatahub-cli</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>LinkedDataHub CLI</name>
<description>Command line interface for the LinkedDataHub HTTP API</description>
<url>https://github.com/AtomGraph/LinkedDataHub</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>21</maven.compiler.release>
<jersey.version>3.1.11</jersey.version>
</properties>

<dependencies>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.7.7</version>
</dependency>
<dependency>
<groupId>com.atomgraph</groupId>
<artifactId>core</artifactId>
<version>5.0.2</version>
<exclusions>
<!-- server-side container is not needed by the client -->
<exclusion>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>jena-arq</artifactId>
<version>6.1.0</version>
<exclusions>
<!-- exclude HTTP Client as its version clashes with Jersey's -->
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient-cache</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient-osgi</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore-osgi</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-apache-connector</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<!-- provides jakarta.activation.DataSource, silencing a Jersey provider warning -->
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<version>2.1.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>2.0.17</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.12.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<finalName>ldh</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>21</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.atomgraph.linkeddatahub.cli.LDH</mainClass>
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
</transformer>
<!-- merges META-INF/services/* across Jena jars; without it JenaSystem/RIOT initialization breaks in the shaded jar -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<!-- merges HK2 inhabitant files across hk2-locator jars; without it Jersey injection breaks in the shaded jar -->
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/hk2-locator/default</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer">
<addHeader>false</addHeader>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
<exclude>module-info.class</exclude>
<exclude>META-INF/versions/*/module-info.class</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
Loading
Loading