Skip to content

Commit 9c4d7ad

Browse files
Aliases (#23)
* Add vocab reference object * Add classes for composing RDF model * Add RDF model test utils and tests * Add binary array to model conversion API impl * Add NetCDF binary array factory method impl, tests * Add CLI impl, test, docs * Fix Java version in maven compiler plugin * Add prefix mapping concept on binary array * Add prefix mapping to model composition, tests * Add NetCDF impl of prefix mapping concept * Add tests, upgrade test format to NetCDF4 to support prefix group. * Add logback config on CLI to suppress debug logs * NetCDF4 considerations in tests * Add option to supply external prefixes for NetCDF to model conversion * Add external prefix / context parameter to CLI, add test * Update Java example with external prefixes. * Rename var * Improve error message wording * Add file container, refactor * Add file container to tests * Fix tests * Add NetCDF URI parser class * Replace BALD PrefixMapping concept with standard Jena PrefixMapping * Add attribute, attribute source concepts * Add NetCDF implementation of attribute concepts * Add root group and variable attributes to RDF model composition * Add attribute tests * Add separate class for handling NetCDF attributes, hide reserved attributes. * Fix existing tests * Add attributes CLI test * Changed test data to CDL format * Fix test * Remove NCML references * Fix Java version on demo * ADD name and subgroups to container concept * Enhance binary array converter to describe subgroups * Fix test consistency * Add prefix var support * Remove prefix group / var from graph * Replace BALD prefix mapping concept with Jena prefix mapping * Add alias definition concept and model impl * Add binary array alias decorators * Add Closeable to BinaryArray interface * Add alias support on CLI * Separate Java example by features * Add extension function for common URI composition * Fix tests * Fix merge issue * Use common test method * Add prefix mapping validation * Refactor the RDF context impl as a decorator * Add prefix conflict validation * Fix reduce on empty list * Restore closeable interface * Add extension function for URI composition * Fix tests * Tidy up * Alias definition interface change * Support multiple alias graphs * Reference requirements in tests * Requirements refs
1 parent 05f4669 commit 9c4d7ad

File tree

25 files changed

+730
-72
lines changed

25 files changed

+730
-72
lines changed

binary-array-ld-cli/src/main/kotlin/net/bald/BinaryArrayConvertCli.kt

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package net.bald
22

3+
import net.bald.alias.AliasBinaryArray
34
import net.bald.context.ContextBinaryArray
5+
import net.bald.model.ModelAliasDefinition
46
import net.bald.model.ModelBinaryArrayConverter
57
import net.bald.netcdf.NetCdfBinaryArray
68
import org.apache.commons.cli.DefaultParser
79
import org.apache.commons.cli.HelpFormatter
810
import org.apache.commons.cli.Options
9-
import org.apache.jena.rdf.model.Model
1011
import org.apache.jena.rdf.model.ModelFactory
1112
import java.io.File
1213
import java.io.OutputStream
@@ -17,9 +18,10 @@ import kotlin.system.exitProcess
1718
*/
1819
class BinaryArrayConvertCli {
1920
private val opts = Options().apply {
20-
this.addOption("u", "uri", true, "The URI which identifies the dataset.")
21-
this.addOption("c", "context", true, "Comma-delimited list of JSON-LD context files.")
22-
this.addOption("h", "help", false, "Show help.")
21+
addOption("u", "uri", true, "The URI which identifies the dataset.")
22+
addOption("a", "alias", true, "Comma-delimited list of RDF alias files.")
23+
addOption("c", "context", true, "Comma-delimited list of JSON-LD context files.")
24+
addOption("h", "help", false, "Show help.")
2325
}
2426

2527
fun run(vararg args: String) {
@@ -38,7 +40,9 @@ class BinaryArrayConvertCli {
3840

3941
private fun doRun(opts: CommandLineOptions) {
4042
val inputLoc = opts.inputLoc ?: throw IllegalArgumentException("First argument is required: NetCDF file to convert.")
41-
val ba = NetCdfBinaryArray.create(inputLoc, opts.uri).withContext(opts.contextLocs)
43+
val ba = NetCdfBinaryArray.create(inputLoc, opts.uri)
44+
.withContext(opts.contextLocs)
45+
.withAlias(opts.aliasLocs)
4246
val model = ba.use(ModelBinaryArrayConverter::convert)
4347

4448
modelOutput(opts.outputLoc).use { output ->
@@ -53,6 +57,17 @@ class BinaryArrayConvertCli {
5357
return ContextBinaryArray.create(this, contexts)
5458
}
5559

60+
private fun BinaryArray.withAlias(aliasLocs: List<String>): BinaryArray {
61+
return if (aliasLocs.isEmpty()) {
62+
this
63+
} else {
64+
val alias = ModelFactory.createDefaultModel().apply {
65+
aliasLocs.forEach(::read)
66+
}.let(ModelAliasDefinition::create)
67+
AliasBinaryArray.create(this, alias)
68+
}
69+
}
70+
5671
private fun options(opts: Options, vararg args: String): CommandLineOptions {
5772
return DefaultParser().parse(opts, args).let(::CommandLineOptions)
5873
}

binary-array-ld-cli/src/main/kotlin/net/bald/CommandLineOptions.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class CommandLineOptions(
1010
}
1111
val outputLoc: String? get() = cmd.args.getOrNull(1)
1212
val uri: String? get() = cmd.getOptionValue("uri")
13+
val aliasLocs: List<String> get() = cmd.getOptionValue("alias")?.split(",") ?: emptyList()
1314
val contextLocs: List<String> get() = cmd.getOptionValue("context")?.split(",") ?: emptyList()
1415
val help: Boolean get() = cmd.hasOption("help")
1516
}

binary-array-ld-cli/src/test/kotlin/net/bald/BinaryArrayConvertCliTest.kt

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package net.bald
22

3-
import bald.jsonld.ContextReader
3+
import bald.jsonld.ResourceFileConverter
44
import bald.model.ModelVerifier
55
import bald.netcdf.CdlConverter.writeToNetCdf
66
import net.bald.vocab.BALD
@@ -36,6 +36,9 @@ class BinaryArrayConvertCliTest {
3636
run("-h")
3737
}
3838

39+
/**
40+
* Requirements class A
41+
*/
3942
@Test
4043
fun run_withoutUri_outputsToFileWithInputFileUri() {
4144
val inputFile = writeToNetCdf("/netcdf/identity.cdl")
@@ -47,8 +50,10 @@ class BinaryArrayConvertCliTest {
4750
ModelVerifier(model).apply {
4851
resource(inputFileUri) {
4952
statement(RDF.type, BALD.Container)
53+
// A-1
5054
statement(BALD.contains, model.createResource("$inputFileUri/")) {
5155
statement(RDF.type, BALD.Container)
56+
// A-2
5257
statement(BALD.contains, model.createResource("$inputFileUri/var0")) {
5358
statement(RDF.type, BALD.Resource)
5459
}
@@ -60,6 +65,9 @@ class BinaryArrayConvertCliTest {
6065
}
6166
}
6267

68+
/**
69+
* Requirements class A
70+
*/
6371
@Test
6472
fun run_withUri_withOutputFile_outputsToFile() {
6573
val inputFile = writeToNetCdf("/netcdf/identity.cdl")
@@ -68,13 +76,18 @@ class BinaryArrayConvertCliTest {
6876

6977
val model = createDefaultModel().read(outputFile.toURI().toString(), "ttl")
7078
ModelVerifier(model).apply {
71-
resource("http://test.binary-array-ld.net/example/") {
79+
// A-1
80+
resource("http://test.binary-array-ld.net/example") {
7281
statement(RDF.type, BALD.Container)
73-
statement(BALD.contains, model.createResource("http://test.binary-array-ld.net/example/var0")) {
74-
statement(RDF.type, BALD.Resource)
75-
}
76-
statement(BALD.contains, model.createResource("http://test.binary-array-ld.net/example/var1")) {
77-
statement(RDF.type, BALD.Resource)
82+
statement(BALD.contains, model.createResource("http://test.binary-array-ld.net/example/")) {
83+
statement(RDF.type, BALD.Container)
84+
// A-2
85+
statement(BALD.contains, model.createResource("http://test.binary-array-ld.net/example/var0")) {
86+
statement(RDF.type, BALD.Resource)
87+
}
88+
statement(BALD.contains, model.createResource("http://test.binary-array-ld.net/example/var1")) {
89+
statement(RDF.type, BALD.Resource)
90+
}
7891
}
7992
}
8093
}
@@ -105,16 +118,25 @@ class BinaryArrayConvertCliTest {
105118
}
106119
}
107120

121+
/**
122+
* Requirements class B-1
123+
*/
108124
@Test
109125
fun run_withPrefixMappingGroup_outputsPrefixMapping() {
110126
run_withPrefixMapping_outputsPrefixMapping("/netcdf/prefix.cdl")
111127
}
112128

129+
/**
130+
* Requirements class B-1
131+
*/
113132
@Test
114133
fun run_withPrefixMappingVar_outputsPrefixMapping() {
115134
run_withPrefixMapping_outputsPrefixMapping("/netcdf/prefix-var.cdl")
116135
}
117136

137+
/**
138+
* Requirements class A-2
139+
*/
118140
@Test
119141
fun run_withSubgroups_outputsWithSubgroups() {
120142
val inputFile = writeToNetCdf("/netcdf/identity-subgroups.cdl")
@@ -156,11 +178,17 @@ class BinaryArrayConvertCliTest {
156178
}
157179
}
158180

181+
/**
182+
* Requirements class B-4
183+
*/
159184
@Test
160185
fun run_withExternalPrefixMapping_outputsPrefixMapping() {
161186
val inputFile = writeToNetCdf("/netcdf/prefix.cdl")
162187
val outputFile = createTempFile()
163-
val contextFiles = listOf(ContextReader.toFile("/jsonld/context.json"), ContextReader.toFile("/jsonld/context2.json"))
188+
val contextFiles = listOf(
189+
ResourceFileConverter.toFile("/jsonld/context.json"),
190+
ResourceFileConverter.toFile("/jsonld/context2.json")
191+
)
164192

165193
run(
166194
"--uri", "http://test.binary-array-ld.net/example",
@@ -172,6 +200,7 @@ class BinaryArrayConvertCliTest {
172200
val model = createDefaultModel().read(outputFile.toURI().toString(), "ttl")
173201
ModelVerifier(model).apply {
174202
prefix("bald", BALD.prefix)
203+
// B-8
175204
prefix("skos", SKOS.uri)
176205
prefix("dct", DCTerms.NS)
177206
prefix("xsd", XSD.NS)
@@ -188,11 +217,14 @@ class BinaryArrayConvertCliTest {
188217
}
189218
}
190219

220+
/**
221+
* Requirements class D
222+
*/
191223
@Test
192224
fun run_withAttributes_outputsAttributes() {
193225
val inputFile = writeToNetCdf("/netcdf/attributes.cdl")
194226
val outputFile = createTempFile()
195-
val contextFile = ContextReader.toFile("/jsonld/context.json")
227+
val contextFile = ResourceFileConverter.toFile("/jsonld/context.json")
196228

197229
run(
198230
"--uri", "http://test.binary-array-ld.net/example",
@@ -208,8 +240,10 @@ class BinaryArrayConvertCliTest {
208240
prefix("dct", DCTerms.NS)
209241
resource("http://test.binary-array-ld.net/example/") {
210242
statement(DCTerms.publisher, createResource("${BALD.prefix}Organisation"))
243+
// D-4
211244
statement(createProperty("http://test.binary-array-ld.net/example/date"), createPlainLiteral("2020-10-29"))
212245
statement(RDF.type, BALD.Container)
246+
// D-2
213247
statement(SKOS.prefLabel, createPlainLiteral("Attributes metadata example"))
214248
statement(BALD.contains, model.createResource("http://test.binary-array-ld.net/example/var0")) {
215249
statement(RDF.type, BALD.Array)
@@ -223,4 +257,47 @@ class BinaryArrayConvertCliTest {
223257
}
224258
}
225259
}
260+
261+
/**
262+
* Requirements class C, D
263+
*/
264+
@Test
265+
fun run_withAliases_outputsAliasedAttributes() {
266+
val inputFile = writeToNetCdf("/netcdf/alias.cdl")
267+
val outputFile = createTempFile()
268+
val contextFile = ResourceFileConverter.toFile("/jsonld/context.json")
269+
val aliasFile = ResourceFileConverter.toFile("/turtle/alias.ttl", "ttl")
270+
271+
run(
272+
"--uri", "http://test.binary-array-ld.net/example",
273+
"--context", contextFile.absolutePath,
274+
"--alias", aliasFile.absolutePath,
275+
inputFile.absolutePath,
276+
outputFile.absolutePath
277+
)
278+
279+
val model = createDefaultModel().read(outputFile.toURI().toString(), "ttl")
280+
ModelVerifier(model).apply {
281+
prefix("bald", BALD.prefix)
282+
prefix("skos", SKOS.uri)
283+
prefix("dct", DCTerms.NS)
284+
resource("http://test.binary-array-ld.net/example/") {
285+
// D-3
286+
statement(DCTerms.publisher, createResource("${BALD.prefix}Organisation"))
287+
statement(createProperty("http://test.binary-array-ld.net/example/date"), createPlainLiteral("2020-10-29"))
288+
statement(RDF.type, BALD.Container)
289+
statement(SKOS.prefLabel, createPlainLiteral("Alias metadata example"))
290+
statement(BALD.contains, model.createResource("http://test.binary-array-ld.net/example/var0")) {
291+
statement(RDF.type, BALD.Array)
292+
statement(RDF.type, BALD.Resource)
293+
statement(RDFS.label, createPlainLiteral("var-0"))
294+
statement(SKOS.prefLabel, createPlainLiteral("Variable 0"))
295+
}
296+
statement(BALD.contains, model.createResource("http://test.binary-array-ld.net/example/var1")) {
297+
statement(RDF.type, BALD.Resource)
298+
}
299+
statement(BALD.isPrefixedBy, createPlainLiteral("prefix_list"))
300+
}
301+
}
302+
}
226303
}

binary-array-ld-demo/src/main/java/net/bald/NetCdfConvertJava.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package net.bald;
22

3+
import net.bald.alias.AliasBinaryArray;
4+
import net.bald.alias.AliasDefinition;
5+
import net.bald.model.ModelAliasDefinition;
36
import net.bald.context.ContextBinaryArray;
47
import net.bald.model.ModelBinaryArrayConverter;
58
import net.bald.netcdf.NetCdfBinaryArray;
69
import org.apache.jena.rdf.model.Model;
710
import org.apache.jena.rdf.model.ModelFactory;
811
import org.apache.jena.shared.PrefixMapping;
9-
1012
import java.io.FileOutputStream;
1113
import java.io.OutputStream;
1214

@@ -33,4 +35,17 @@ public static void convertWithExternalPrefixes() throws Exception {
3335
model.write(output, "ttl");
3436
}
3537
}
38+
39+
public static void convertWithAliases() throws Exception {
40+
BinaryArray ba = NetCdfBinaryArray.create("/path/to/input.nc", "http://test.binary-array-ld.net/example");
41+
Model aliasModel = ModelFactory.createDefaultModel().read("/path/to/alias.ttl", "ttl");
42+
AliasDefinition alias = ModelAliasDefinition.create(aliasModel);
43+
BinaryArray aliasBa = AliasBinaryArray.create(ba, alias);
44+
45+
Model model = ModelBinaryArrayConverter.convert(aliasBa);
46+
47+
try (OutputStream output = new FileOutputStream("/path/to/output.ttl")) {
48+
model.write(output, "ttl");
49+
}
50+
}
3651
}

binary-array-ld-lib/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,10 @@
3535
<artifactId>mockito-kotlin</artifactId>
3636
<version>${mockito.kt.version}</version>
3737
</dependency>
38+
<dependency>
39+
<groupId>org.apache.jena</groupId>
40+
<artifactId>jena-arq</artifactId>
41+
<version>${jena.version}</version>
42+
</dependency>
3843
</dependencies>
3944
</project>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package net.bald.alias
2+
3+
import net.bald.Attribute
4+
import org.apache.jena.rdf.model.RDFNode
5+
import org.apache.jena.rdf.model.ResourceFactory
6+
7+
/**
8+
* Decorator for [Attribute] which supports attribute aliasing.
9+
*/
10+
class AliasAttribute(
11+
private val attr: Attribute,
12+
private val alias: AliasDefinition
13+
): Attribute {
14+
override val uri: String? get() = attr.uri ?: alias.property(attr.name)?.uri
15+
override val name: String get() = attr.name
16+
17+
override val values: List<RDFNode> get() {
18+
return attr.values.map { value ->
19+
if (value.isLiteral) {
20+
val raw = value.asLiteral().lexicalForm
21+
alias.resource(raw) ?: value
22+
} else {
23+
value
24+
}
25+
}
26+
}
27+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package net.bald.alias
2+
3+
import net.bald.*
4+
import org.apache.jena.shared.PrefixMapping
5+
6+
/**
7+
* Decorator for [AttributeSource] which supports attribute aliasing.
8+
*/
9+
open class AliasAttributeSource(
10+
private val source: AttributeSource,
11+
private val alias: AliasDefinition
12+
): AttributeSource {
13+
override fun attributes(prefixMapping: PrefixMapping): List<Attribute> {
14+
return source.attributes(prefixMapping).map { attr ->
15+
AliasAttribute(attr, alias)
16+
}
17+
}
18+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package net.bald.alias
2+
3+
import net.bald.BinaryArray
4+
import net.bald.Container
5+
import org.apache.jena.shared.PrefixMapping
6+
7+
/**
8+
* Decorator for [BinaryArray] which supports attribute aliasing.
9+
*/
10+
class AliasBinaryArray(
11+
private val ba: BinaryArray,
12+
private val alias: AliasDefinition
13+
): BinaryArray {
14+
override val uri: String get() = ba.uri
15+
override val prefixMapping: PrefixMapping get() = ba.prefixMapping
16+
override val root: Container get() = AliasContainer(ba.root, alias)
17+
18+
override fun close() {
19+
ba.close()
20+
}
21+
22+
companion object {
23+
/**
24+
* Decorate the given [BinaryArray] with the given [AliasDefinition] to support attribute aliasing.
25+
* @param ba The original binary array.
26+
* @param alias The alias definition to apply.
27+
* @return An aliased [BinaryArray].
28+
*/
29+
@JvmStatic
30+
fun create(ba: BinaryArray, alias: AliasDefinition): BinaryArray {
31+
return AliasBinaryArray(ba, alias)
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)