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
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,3 @@ the `ncgen` command line tool must be available on your system.

You can use Maven to build this project and each of its modules with `mvn clean package`.
After building, the JAR for the command line application is located at `binary-array-ld-cli/target/bald-cli.jar`.



Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class BinaryArrayConvertCli {
addOption("a", "alias", true, "Comma-delimited list of RDF alias files.")
addOption("c", "context", true, "Comma-delimited list of JSON-LD context files.")
addOption("o", "output", true, "Output format. eg. ttl, json-ld, rdfxml.")
addOption("d", "download", true, "The URL from which the original file can be downloaded.")
addOption("h", "help", false, "Show help.")
}

Expand All @@ -42,7 +43,7 @@ class BinaryArrayConvertCli {
val context = context(opts.contextLocs)
val alias = alias(opts.aliasLocs)
val inputLoc = opts.inputLoc ?: throw IllegalArgumentException("First argument is required: NetCDF file to convert.")
val ba = NetCdfBinaryArray.create(inputLoc, opts.uri, context, alias)
val ba = NetCdfBinaryArray.create(inputLoc, opts.uri, context, alias, opts.downloadUrl)
val model = ba.use(ModelBinaryArrayConverter::convert)
val outputFormat = opts.outputFormat ?: "ttl"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ class CommandLineOptions(
val aliasLocs: List<String> get() = cmd.getOptionValue("alias")?.split(",") ?: emptyList()
val contextLocs: List<String> get() = cmd.getOptionValue("context")?.split(",") ?: emptyList()
val outputFormat: String? get() = cmd.getOptionValue("output")
val downloadUrl: String? get() = cmd.getOptionValue("download")
val help: Boolean get() = cmd.hasOption("help")
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,33 @@ class BinaryArrayConvertCliTest {
}
}

@Test
fun run_withDownloadUrl_outputsDownloadUrl() {
val inputFile = writeToNetCdf("/netcdf/identity.cdl")
val outputFile = createTempFile()
run(
"--uri", "http://test.binary-array-ld.net/example",
"--download", "http://test.binary-array-ld.net/download/example.nc",
inputFile.absolutePath,
outputFile.absolutePath
)

val model = createDefaultModel().read(outputFile.toURI().toString(), "ttl")
ModelVerifier(model).apply {
resource("http://test.binary-array-ld.net/example/") {
format()
statement(RDF.type, BALD.Container)
distribution("http://test.binary-array-ld.net/download/example.nc")
statement(BALD.contains, model.createResource("http://test.binary-array-ld.net/example/var0")) {
statement(RDF.type, BALD.Resource)
}
statement(BALD.contains, model.createResource("http://test.binary-array-ld.net/example/var1")) {
statement(RDF.type, BALD.Resource)
}
}
}
}

@Test
fun run_withOutputFormat_outputsToFile() {
val inputFile = writeToNetCdf("/netcdf/identity.cdl")
Expand Down Expand Up @@ -569,9 +596,10 @@ class BinaryArrayConvertCliTest {
}
}

private fun StatementsVerifier.distribution() {
private fun StatementsVerifier.distribution(downloadUrl: String? = null) {
statement(DCAT.distribution) {
statement(RDF.type, DCAT.Distribution)
if (downloadUrl != null) statement(DCAT.downloadURL, createResource(downloadUrl))
statement(DCAT.mediaType) {
statement(DCTerms.identifier, createStringLiteral("application/x-netcdf"))
statement(RDF.type, DCTerms.MediaType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static void convert() throws Exception {
public static void convertWithExternalPrefixes() throws Exception {
PrefixMapping prefix = ModelFactory.createDefaultModel().read("/path/to/context.json", "json-ld");
ModelContext context = ModelContext.create(prefix);
BinaryArray ba = NetCdfBinaryArray.create("/path/to/input.nc", "http://test.binary-array-ld.net/example", context, null);
BinaryArray ba = NetCdfBinaryArray.create("/path/to/input.nc", "http://test.binary-array-ld.net/example", context, null, null);
Model model = ModelBinaryArrayConverter.convert(ba);

try (OutputStream output = new FileOutputStream("/path/to/output.ttl")) {
Expand All @@ -38,7 +38,7 @@ public static void convertWithExternalPrefixes() throws Exception {
public static void convertWithAliases() throws Exception {
Model aliasModel = ModelFactory.createDefaultModel().read("/path/to/alias.ttl", "ttl");
AliasDefinition alias = ModelAliasDefinition.create(aliasModel);
BinaryArray ba = NetCdfBinaryArray.create("/path/to/input.nc", "http://test.binary-array-ld.net/example", null, alias);
BinaryArray ba = NetCdfBinaryArray.create("/path/to/input.nc", "http://test.binary-array-ld.net/example", null, alias, null);
Model model = ModelBinaryArrayConverter.convert(ba);

try (OutputStream output = new FileOutputStream("/path/to/output.ttl")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,4 @@ interface BinaryArray: Closeable {
* The distribution of the binary array, if it is available. Otherwise, null.
*/
val distribution: Distribution?

}
8 changes: 8 additions & 0 deletions binary-array-ld-lib/src/main/kotlin/net/bald/Distribution.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.bald

import org.apache.jena.rdf.model.Resource

/**
* A distribution of a binary array file.
*/
Expand All @@ -8,4 +10,10 @@ interface Distribution {
* The media type of the binary array file.
*/
val mediaType: String

/**
* The URL from which this distribution of the file can be downloaded, if it has one.
* Otherwise, null.
*/
val downloadUrl: Resource?
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ class ModelBinaryArrayBuilder(
val distribution = model.createResource()
.addProperty(RDF.type, DCAT.Distribution)
.addProperty(DCAT.mediaType, mediaType)
.apply {
dist.downloadUrl?.let { downloadUrl ->
addProperty(DCAT.downloadURL, downloadUrl)
}
}
root.addProperty(DCAT.distribution, distribution)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class ModelBinaryArrayBuilderTest {
}
private val distribution = mock<Distribution> {
on { mediaType } doReturn "application/x-netcdf"
on { downloadUrl } doReturn createResource("http://test.binary-array-ld.net/download/example.nc")
}
private val ba = mock<BinaryArray> {
on { this.root } doReturn root
Expand Down Expand Up @@ -93,7 +94,7 @@ class ModelBinaryArrayBuilderTest {
ModelVerifier(model).apply {
resource("http://test.binary-array-ld.net/example/") {
format()
distribution()
distribution("http://test.binary-array-ld.net/download/example.nc")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@ package net.bald.model

import bald.model.StatementsVerifier
import org.apache.jena.rdf.model.ResourceFactory
import org.apache.jena.rdf.model.ResourceFactory.createResource
import org.apache.jena.vocabulary.DCAT
import org.apache.jena.vocabulary.DCTerms
import org.apache.jena.vocabulary.RDF

fun StatementsVerifier.format() {
statement(DCTerms.format) {
statement(DCTerms.identifier,
ResourceFactory.createResource("http://vocab.nerc.ac.uk/collection/M01/current/NC/"))
statement(DCTerms.identifier, createResource("http://vocab.nerc.ac.uk/collection/M01/current/NC/"))
statement(RDF.type, DCTerms.MediaType)
}
}

fun StatementsVerifier.distribution() {
fun StatementsVerifier.distribution(downloadUrl: String? = null) {
statement(DCAT.distribution) {
statement(RDF.type, DCAT.Distribution)
if (downloadUrl != null) statement(DCAT.downloadURL, createResource(downloadUrl))
statement(DCAT.mediaType) {
statement(DCTerms.identifier, ResourceFactory.createStringLiteral("application/x-netcdf"))
statement(RDF.type, DCTerms.MediaType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import net.bald.Distribution
import net.bald.Format
import net.bald.alias.AliasDefinition
import net.bald.context.ModelContext
import org.apache.jena.rdf.model.ResourceFactory.createResource
import org.apache.jena.shared.PrefixMapping
import ucar.nc2.AttributeContainer
import ucar.nc2.Group
import ucar.nc2.NetcdfFile
import ucar.nc2.NetcdfFiles
import java.io.File
import java.net.URI

/**
* NetCDF implementation of [BinaryArray].
Expand All @@ -20,7 +22,8 @@ class NetCdfBinaryArray(
val uri: String,
private val file: NetcdfFile,
private val context: ModelContext,
val alias: AliasDefinition
val alias: AliasDefinition,
private val downloadUrl: String?
): BinaryArray {
override val root: NetCdfContainer get() = container(file.rootGroup)

Expand All @@ -32,7 +35,19 @@ class NetCdfBinaryArray(
}

override val format: Format get() = NetCdfFormat
override val distribution: Distribution get() = NetCdfDistribution()

override val distribution: Distribution get() {
val downloadUrl = downloadUrl ?: file.location.takeIf(::isHttp)
val res = downloadUrl?.let(::createResource)
return NetCdfDistribution(res)
}

private fun isHttp(loc: String): Boolean {
return try {
val scheme = URI(loc).scheme
scheme == "http" || scheme == "https"
} catch (e: Exception) { false }
}

val prefixSrc: String? get() = prefixSourceName()

Expand Down Expand Up @@ -75,18 +90,20 @@ class NetCdfBinaryArray(
* @param uri The URI which identifies the dataset.
* @param context The external context with which to resolve prefix mappings.
* @param alias The alias definition with which to resolve resource and property references.
* @param downloadUrl The URL from which the file can be downloaded, if it has one. Otherwise, null.
* @return A [BinaryArray] representation of the NetCDF file.
*/
@JvmStatic
fun create(
fileLoc: String,
uri: String? = null,
context: ModelContext? = null,
alias: AliasDefinition? = null
alias: AliasDefinition? = null,
downloadUrl: String? = null
): NetCdfBinaryArray {
val file = NetcdfFiles.open(fileLoc)
val requiredUri = uri ?: uri(fileLoc)
return create(file, requiredUri, context, alias)
return create(file, requiredUri, context, alias, downloadUrl)
}

/**
Expand All @@ -105,11 +122,12 @@ class NetCdfBinaryArray(
file: NetcdfFile,
uri: String,
context: ModelContext? = null,
alias: AliasDefinition? = null
alias: AliasDefinition? = null,
downloadUrl: String? = null
): NetCdfBinaryArray {
val requiredContext = context ?: ModelContext.Empty
val requiredAlias = alias ?: AliasDefinition.Empty
return NetCdfBinaryArray(uri, file, requiredContext, requiredAlias)
return NetCdfBinaryArray(uri, file, requiredContext, requiredAlias, downloadUrl)
}

private fun uri(fileLoc: String): String {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package net.bald.netcdf

import net.bald.Distribution
import org.apache.jena.rdf.model.Resource

/**
* NetCDF implementation of [Distribution].
*/
class NetCdfDistribution: Distribution {
class NetCdfDistribution(
override val downloadUrl: Resource? = null
): Distribution {
override val mediaType: String get() = "application/x-netcdf"
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,19 @@ import org.apache.jena.vocabulary.SKOS
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import kotlin.test.assertEquals
import kotlin.test.assertNull

class NetCdfBinaryArrayTest {

private fun fromCdl(cdlLoc: String, uri: String? = null, context: ModelContext? = null, alias: AliasDefinition? = null): BinaryArray {
private fun fromCdl(
cdlLoc: String,
uri: String? = null,
context: ModelContext? = null,
alias: AliasDefinition? = null,
downloadUrl: String? = null
): BinaryArray {
val file = writeToNetCdf(cdlLoc)
return NetCdfBinaryArray.create(file.absolutePath, uri, context, alias)
return NetCdfBinaryArray.create(file.absolutePath, uri, context, alias, downloadUrl)
}

/**
Expand All @@ -47,6 +54,24 @@ class NetCdfBinaryArrayTest {
assertEquals(expectedUri, ba.uri)
}

@Test
fun distribution_withDownloadUrl_returnsDistribution() {
val downloadUrl = "http://test.binary-array-ld.net/download/identity.nc"
val ba = fromCdl("/netcdf/identity.cdl", "http://test.binary-array-ld.net/identity.nc", downloadUrl = downloadUrl)
val distribution = ba.distribution
assertEquals(downloadUrl, distribution?.downloadUrl?.uri)
assertEquals("application/x-netcdf", distribution?.mediaType)
}

@Test
fun distribution_withoutDownloadUrl_returnsEmptyDistribution() {
val ba = fromCdl("/netcdf/identity.cdl", "http://test.binary-array-ld.net/identity.nc")
val distribution = ba.distribution
assertNull(distribution?.downloadUrl?.uri)
assertEquals("application/x-netcdf", distribution?.mediaType)
}


/**
* Requirements class A-2
*/
Expand Down
2 changes: 1 addition & 1 deletion docs/alias.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ and an alias definition to create a `BinaryArray` with both.
```java
Model aliasModel = ModelFactory.createDefaultModel().read("/path/to/alias.ttl", "ttl");
AliasDefinition alias = ModelAliasDefinition.create(aliasModel);
BinaryArray ba = NetCdfBinaryArray.create("/path/to/input.nc", "http://test.binary-array-ld.net/example", null, alias);
BinaryArray ba = NetCdfBinaryArray.create("/path/to/input.nc", "http://test.binary-array-ld.net/example", null, alias, null);
Model model = ModelBinaryArrayConverter.convert(ba);

try (OutputStream output = new FileOutputStream("/path/to/output.ttl")) {
Expand Down
7 changes: 6 additions & 1 deletion docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ You can find the documentation for this feature [here](context.md#cli).
The CLI supports [aliases](alias.md).
You can find the documentation for this feature [here](alias.md#cli).

### Download URL

The CLI supports [download URLs](download.md).

### Quick Reference

You can supply command line options in long form with the `--` prefix or short form with `-`,
Expand All @@ -57,4 +61,5 @@ followed by their value.
| --uri | -u | The URI which identifies the dataset. | Input file URI |
| --output | -o | Output format, eg. ttl, json-ld, rdfxml. | ttl |
| --context | -c | Comma-delimited list of JSON-LD context files. ||
| --alias | -a | Comma-delimited list of RDF alias files. ||
| --alias | -a | Comma-delimited list of RDF alias files. ||
| --download | -d | The URL from which the original file can be downloaded, if available. ||
2 changes: 1 addition & 1 deletion docs/context.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ to create a `BinaryArray` with both.
```java
PrefixMapping prefix = ModelFactory.createDefaultModel().read("/path/to/context.json", "json-ld");
ModelContext context = ModelContext.create(prefix);
BinaryArray ba = NetCdfBinaryArray.create("/path/to/input.nc", "http://test.binary-array-ld.net/example", context, null);
BinaryArray ba = NetCdfBinaryArray.create("/path/to/input.nc", "http://test.binary-array-ld.net/example", context, null, null);
Model model = ModelBinaryArrayConverter.convert(ba);

try (OutputStream output = new FileOutputStream("/path/to/output.ttl")) {
Expand Down
32 changes: 32 additions & 0 deletions docs/download.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Download URL

The BALD CLI and library allow you to specify a download URL for the given NetCDF file,
as described in the [draft specification](http://docs.opengeospatial.org/DRAFTS/19-002.html#_download_url).

If you don't specify a download URL, but the given location of the NetCDF file is a remote URL (ie. it has `http` or `https` scheme),
then the download URL will be inferred to be the same.

## CLI

You can optionally provide the download URL as a command line argument.
Use the `--download` or `-d` option to specify the download URL for the NetCDF file.

#### Example
```
java -jar bald-cli.jar --download http://test.binary-array-ld.net/download/netcdf.nc /path/to/netcdf.nc /path/to/graph.ttl
```

## Library

You can optionally provide the download URL as a parameter to the `NetCdfBinaryArray.create` method.
Otherwise, you can simply pass in a null value.

#### Example
```java
BinaryArray ba = NetCdfBinaryArray.create("/path/to/input.ttl", "http://test.binary-array-ld.net/example", null, null, "http://test.binary-array-ld.net/download/netcdf.nc");
Model model = ModelBinaryArrayConverter.convert(ba);

try (OutputStream output = new FileOutputStream("/path/to/output.ttl")) {
model.write(output, "ttl");
}
```
Loading