Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -25,3 +25,4 @@
/tests/ui/node_modules
/tests/ui/out
/tests/ui/test-results
/rdf/target/
40 changes: 34 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ make down # Stop the services
make down -- -v # Stop and remove volumes
make drop # Complete reset (down -v, then wipe local dirs)

make cli # Build the ldh CLI, print the PATH export to run
make cli-version # Set cli/pom.xml to the platform version in pom.xml
make rdf # Install the linkeddatahub-rdf library
make cli # Build the ldh CLI (installs rdf first), print the PATH export
make cli-version # Set rdf/ and cli/ poms to the platform version in pom.xml
```

### Testing
Expand Down Expand Up @@ -155,15 +156,42 @@ into a shaded `cli/target/ldh.jar` that `cli/bin/ldh` launches. See `cli/README.
script → command table and the behavioral differences from the scripts.

```bash
cd cli && mvn package && export PATH="$PWD/bin:$PATH"
make cli && export PATH="$PWD/cli/bin:$PATH"

ldh create container --parent "$LDH_BASE" --title "Some" --slug some
ldh admin add agent --agent "$AGENT_URI" "${ADMIN_BASE}acl/groups/writers/"
```

`cli/` is not a module of the platform reactor (the root pom is the webapp artifact, so it cannot
carry `<modules>`), but it shares the platform's version: `release.sh` runs `versions:set` on it
around both release bumps, and `make cli-version` re-aligns it if it drifts.
## The RDF library

`rdf/` builds `com.atomgraph:linkeddatahub-rdf` — the vocabularies (`com.atomgraph.linkeddatahub.rdf.vocabulary`)
and the document shapes the HTTP API accepts (`Documents`, `Blocks`, `Views`, `Queries`, `Services`,
`Imports`, `Acl`, `Ontologies`, plus the SPARQL `Updates`). Jena and nothing else: no Jersey, no
picocli. Every consumer talks to the platform over HTTP its own way, so what is shared is the shape
of the request body, not how it is sent.

Two consumers today — the CLI, and Web-Algebra's `ldh-*` operations in `../REST-VKG` — which is why
the builders live here rather than on the picocli command classes that used to own them. A shape
described in one place cannot drift between them.

The platform keeps its own `com.atomgraph.linkeddatahub.vocabulary`, still duplicated with this
library's. Collapsing them would make the platform depend on `rdf/`, and the Dockerfile builds the
webapp from `COPY src` + `COPY pom.xml` alone — so the dependency has to point away from the
platform, not at it.

Neither `rdf/` nor `cli/` is a module of the platform reactor (the root pom is the webapp artifact,
so it cannot carry `<modules>`), but both share the platform's version: `release.sh` runs
`versions:set` on them around both release bumps, and `make cli-version` re-aligns them if they
drift. `cli/pom.xml` resolves the library by `${project.version}`, so the two move together.
`make cli` installs `rdf/` first; building `cli/` on its own needs `make rdf` to have run at least
once since the last version bump.

`linkeddatahub-rdf` publishes to Maven Central on its own, since `release:perform` only carries
reactor modules: `release.sh` deploys it right after the platform, extracting `rdf/` from the release
tag with `git archive` because the working tree has already moved on to the next SNAPSHOT by then.
A snapshot can be published by hand with `cd rdf && mvn -Prelease clean deploy` — the `release`
profile attaches the sources and javadoc jars and signs them, which is what
`<releaseProfiles>release</releaseProfiles>` gets the platform.

`LDH_CERT_FILE`, `LDH_CERT_PASSWORD`, `LDH_BASE` and `LDH_PROXY` supply defaults for `-c`, `-p`,
`-b` and `--proxy`. `-c/--cert` takes either format the agent's credential comes in — a PKCS12
Expand Down
6 changes: 6 additions & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,17 @@ make cli
which prints the `export PATH=...` line to run afterwards. It is the equivalent of:

```bash
cd rdf && mvn install && cd ..
cd cli
mvn package
export PATH="$PWD/bin:$PATH"
```

The `rdf/` step installs `com.atomgraph:linkeddatahub-rdf`, which holds the vocabularies and the
document shapes the commands build — shared with Web-Algebra's `ldh-*` operations, so the two
cannot drift. It is resolved by `${project.version}`, so it has to be installed again after a
version bump; `make cli` does that for you.

This produces the self-contained `target/ldh.jar`, which the `cli/bin/ldh` launcher runs. The
launcher prefers `LDH_JAR`, then a jar sitting beside it (the release archive layout), then
`../target/ldh.jar` (the source checkout layout).
Expand Down
25 changes: 25 additions & 0 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,32 @@
<jersey.version>3.1.11</jersey.version>
</properties>

<!-- where linkeddatahub-rdf comes from between releases. This project has never needed a
repository before: everything it depends on is released to Maven Central, which does not serve
snapshots, and the platform pom's own declaration does not reach here because the two are
separate builds. Without this a clean checkout resolves the library only if it happens to be in
the local repository, which is how CI first failed. -->
<repositories>
<repository>
<id>central-portal-snapshots</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>

<dependencies>
<dependency>
<!-- the vocabularies and the document shapes, shared with the platform's other API
clients; this project adds the command line over them -->
<groupId>com.atomgraph</groupId>
<artifactId>linkeddatahub-rdf</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
Expand Down
15 changes: 0 additions & 15 deletions cli/src/main/java/com/atomgraph/linkeddatahub/cli/BaseCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import java.util.concurrent.Callable;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFLanguages;
import org.apache.jena.riot.RDFParser;
Expand Down Expand Up @@ -124,20 +123,6 @@ protected static void put(LDHClient client, URI target, Model model)
HttpException.check(target, client.put(target, Entity.entity(model, TEXT_TURTLE_TYPE), ACCEPT_TURTLE)).close();
}

/**
* Returns the subject resource for an appended description: the <code>--uri</code> value
* resolved against the target document URI, or a fresh blank node when not given.
*
* @param model model to create the resource in
* @param target target document URI
* @param uri <code>--uri</code> option value (absolute or relative, can be null)
* @return subject resource
*/
protected static Resource createSubject(Model model, URI target, String uri)
{
return uri != null ? model.createResource(target.resolve(uri).toString()) : model.createResource();
}

/**
* Parses an RDF stream into a model, resolving relative URIs against the base URI
* (the equivalent of the scripts' <code>turtle --base</code> piping).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,11 @@
import com.atomgraph.linkeddatahub.cli.BaseCommand;
import com.atomgraph.linkeddatahub.cli.http.LDHClient;
import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin;
import com.atomgraph.linkeddatahub.cli.vocab.LDH;
import com.atomgraph.linkeddatahub.cli.vocab.SP;
import com.atomgraph.linkeddatahub.rdf.Queries;
import com.atomgraph.linkeddatahub.rdf.vocabulary.SP;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.vocabulary.DCTerms;
import org.apache.jena.vocabulary.RDF;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;
Expand Down Expand Up @@ -88,33 +83,7 @@ public Integer call() throws Exception
*/
public static void core(LDHClient client, URI target, String uri, String title, String queryText, URI service, String description)
{
post(client, target, buildModel(target, uri, SP.Construct, title, queryText, service, description));
}

/**
* Builds a SPIN query description.
*
* @param target target document URI
* @param uri query URI (optional)
* @param queryType SPIN query class (<code>sp:Construct</code> or <code>sp:Select</code>)
* @param title query title
* @param queryText query string
* @param service SPARQL service URI (optional)
* @param description query description (optional)
* @return query model
*/
public static Model buildModel(URI target, String uri, Resource queryType, String title, String queryText, URI service, String description)
{
Model model = ModelFactory.createDefaultModel();

Resource query = createSubject(model, target, uri).
addProperty(RDF.type, queryType).
addProperty(DCTerms.title, title).
addProperty(SP.text, queryText);
if (service != null) query.addProperty(LDH.service, model.createResource(service.toString()));
if (description != null) query.addProperty(DCTerms.description, description);

return model;
post(client, target, Queries.query(target, uri, SP.Construct, title, queryText, service, description));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import com.atomgraph.linkeddatahub.cli.http.HttpException;
import com.atomgraph.linkeddatahub.cli.http.LDHClient;
import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin;
import com.atomgraph.linkeddatahub.cli.util.Digests;
import com.atomgraph.linkeddatahub.cli.vocab.NFO;
import com.atomgraph.linkeddatahub.rdf.Digests;
import com.atomgraph.linkeddatahub.rdf.vocabulary.NFO;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.MediaType;
import java.io.IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,8 @@

import com.atomgraph.linkeddatahub.cli.BaseCommand;
import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin;
import com.atomgraph.linkeddatahub.cli.vocab.A;
import com.atomgraph.linkeddatahub.cli.vocab.SD;
import com.atomgraph.linkeddatahub.rdf.Services;
import java.net.URI;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.vocabulary.DCTerms;
import org.apache.jena.vocabulary.RDF;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;
Expand Down Expand Up @@ -72,41 +66,10 @@ public Integer call() throws Exception
{
baseMixin.require(getSpec()); // required by the script interface

post(getClient(), target, buildModel(target, uri, title, endpoint, graphStore, authUser, authPwd, description));
post(getClient(), target, Services.service(target, uri, title, endpoint, graphStore, authUser, authPwd, description));
print(target);

return 0;
}

/**
* Builds the service description.
*
* @param target target document URI
* @param uri service URI (optional)
* @param title service title
* @param endpoint SPARQL endpoint URI
* @param graphStore Graph Store Protocol endpoint URI (optional)
* @param authUser HTTP Basic auth username (optional)
* @param authPwd HTTP Basic auth password (optional)
* @param description service description (optional)
* @return service model
*/
public static Model buildModel(URI target, String uri, String title, URI endpoint, URI graphStore, String authUser, String authPwd, String description)
{
Model model = ModelFactory.createDefaultModel();

Resource service = createSubject(model, target, uri).
addProperty(RDF.type, SD.Service).
addProperty(DCTerms.title, title).
addProperty(SD.endpoint, model.createResource(endpoint.toString())).
addProperty(SD.supportedLanguage, SD.SPARQL11Query).
addProperty(SD.supportedLanguage, SD.SPARQL11Update);
if (graphStore != null) service.addProperty(A.graphStore, model.createResource(graphStore.toString()));
if (authUser != null) service.addProperty(A.authUser, authUser);
if (authPwd != null) service.addProperty(A.authPwd, authPwd);
if (description != null) service.addProperty(DCTerms.description, description);

return model;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import com.atomgraph.linkeddatahub.cli.BaseCommand;
import com.atomgraph.linkeddatahub.cli.http.HttpException;
import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin;
import com.atomgraph.linkeddatahub.cli.sparql.Updates;
import com.atomgraph.linkeddatahub.rdf.Updates;
import java.net.URI;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,8 @@

import com.atomgraph.linkeddatahub.cli.BaseCommand;
import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin;
import com.atomgraph.linkeddatahub.cli.vocab.LDH;
import com.atomgraph.linkeddatahub.cli.vocab.SPIN;
import com.atomgraph.linkeddatahub.rdf.Views;
import java.net.URI;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.vocabulary.DCTerms;
import org.apache.jena.vocabulary.RDF;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;
Expand Down Expand Up @@ -72,39 +66,10 @@ public Integer call() throws Exception
{
baseMixin.require(getSpec()); // required by the script interface

post(getClient(), target, buildModel(target, uri, title, query, chartType, categoryVarName, seriesVarName, description));
post(getClient(), target, Views.resultSetChart(target, uri, title, query, chartType, categoryVarName, seriesVarName, description));
print(target);

return 0;
}

/**
* Builds the chart description.
*
* @param target target document URI
* @param uri chart URI (optional)
* @param title chart title
* @param query SELECT query URI
* @param chartType chart type URI
* @param categoryVarName category variable name
* @param seriesVarName series variable name
* @param description chart description (optional)
* @return chart model
*/
public static Model buildModel(URI target, String uri, String title, URI query, URI chartType, String categoryVarName, String seriesVarName, String description)
{
Model model = ModelFactory.createDefaultModel();

Resource chart = createSubject(model, target, uri).
addProperty(RDF.type, LDH.ResultSetChart).
addProperty(DCTerms.title, title).
addProperty(SPIN.query, model.createResource(query.toString())).
addProperty(LDH.chartType, model.createResource(chartType.toString())).
addProperty(LDH.categoryVarName, categoryVarName).
addProperty(LDH.seriesVarName, seriesVarName);
if (description != null) chart.addProperty(DCTerms.description, description);

return model;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@

import com.atomgraph.linkeddatahub.cli.BaseCommand;
import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin;
import com.atomgraph.linkeddatahub.cli.vocab.SP;
import com.atomgraph.linkeddatahub.rdf.Queries;
import com.atomgraph.linkeddatahub.rdf.vocabulary.SP;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -62,7 +63,7 @@ public Integer call() throws Exception
{
baseMixin.require(getSpec()); // required by the script interface

post(getClient(), target, AddConstruct.buildModel(target, uri, SP.Select, title, Files.readString(queryFile), service, description));
post(getClient(), target, Queries.query(target, uri, SP.Select, title, Files.readString(queryFile), service, description));
print(target);

return 0;
Expand Down
Loading
Loading