Skip to content

Commit

Permalink
feat: file based processors in std
Browse files Browse the repository at this point in the history
  • Loading branch information
jenspots committed May 24, 2024
1 parent 14827b9 commit 79346d2
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/main/kotlin/logging/Log.kt
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,19 @@ class Log private constructor() {

fun fatal(message: String): Nothing {
print(message, "FATAL")
print(Throwable().stackTraceToString())
exitProcess(1)
}

fun fatal(exception: Exception): Nothing {
print(exception.message.toString(), "FATAL")
print(Throwable().stackTraceToString())
exitProcess(1)
}

fun fatal(message: String, exception: Exception) {
print("$message - ${exception.message}")
print(Throwable().stackTraceToString())
exitProcess(1)
}

Expand Down
4 changes: 4 additions & 0 deletions src/main/kotlin/runner/Processor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ abstract class Processor(
return result
}

fun <T> getNullableArgument(name: String): T? {
return arguments[name] as T?
}

fun <T> getOptionalArgument(name: String): Optional<T> {
val result = arguments[name] ?: log.fatal("Argument $name is missing")

Expand Down
19 changes: 19 additions & 0 deletions src/main/kotlin/std/FileReader.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package technology.idlab.std

import bridge.Writer
import java.io.File
import technology.idlab.runner.Processor

class FileReader(args: Map<String, Any>) : Processor(args) {
/** Arguments */
private val path: String = this.getArgument("path")
private val output: Writer = this.getArgument("output")

/** Read the file as a single byte array and push it down the pipeline. */
override fun exec() {
val file = File(path)
val bytes = file.readBytes()
output.pushSync(bytes)
output.close()
}
}
48 changes: 48 additions & 0 deletions src/main/kotlin/std/FileWriter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package technology.idlab.std

import bridge.Reader
import java.io.File
import technology.idlab.runner.Processor

class FileWriter(args: Map<String, Any>) : Processor(args) {
/** Processor default values. */
private val overwriteDefault = true
private val appendDefault = false

/** Arguments */
private val file = File(this.getArgument<String>("path"))
private val input: Reader = this.getArgument("input")
private val overwrite = this.getOptionalArgument<Boolean>("overwrite")
private val append = this.getOptionalArgument<Boolean>("append")

init {
// Sanity check.
if (overwrite.orElse(false) && append.orElse(false)) {
log.fatal("Cannot overwrite and append at the same time")
}

// Do not overwrite the file if it exists.
if (file.exists() && !overwrite.orElse(overwriteDefault)) {
log.fatal("File ${file.path} already exists")
}

// Overwrite file if not exists.
if (file.exists() && !append.orElse(appendDefault)) {
file.writeBytes(ByteArray(0))
}
}

/** All incoming values are parsed as byte and appended onto the file. */
override fun exec() {
while (true) {
// Read the next incoming value.
val result = input.readSync()
if (result.isClosed()) {
break
}

// Append it to the file.
file.appendBytes(result.value)
}
}
}
26 changes: 26 additions & 0 deletions src/main/resources/std/file_reader.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@prefix jvm: <https://w3id.org/conn/jvm#>.
@prefix owl: <http://www.w3.org/2002/07/owl#>.
@prefix sh: <http://www.w3.org/ns/shacl#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.

<> owl:imports <../pipeline.ttl>.

jvm:FileReader a jvm:Processor;
jvm:file <../../kotlin/std/FileReader.kt>;
jvm:language "Kotlin".

[] a sh:NodeShape;
sh:targetClass jvm:FileReader;
sh:property [
sh:path jvm:path;
sh:name "path";
sh:datatype xsd:string;
], [
sh:path jvm:output;
sh:name "output";
sh:class jvm:ChannelWriter;
sh:minCount 1;
sh:maxCount 1;
];
sh:closed true;
sh:ignoredProperties (rdf:type).
38 changes: 38 additions & 0 deletions src/main/resources/std/file_writer.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@prefix jvm: <https://w3id.org/conn/jvm#>.
@prefix owl: <http://www.w3.org/2002/07/owl#>.
@prefix sh: <http://www.w3.org/ns/shacl#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.

<> owl:imports <../pipeline.ttl>.

jvm:FileWriter a jvm:Processor;
jvm:file <../../kotlin/std/FileWriter.kt>;
jvm:language "Kotlin".

[] a sh:NodeShape;
sh:targetClass jvm:FileWriter;
sh:property [
sh:path jvm:path;
sh:name "path";
sh:datatype xsd:string;
], [
sh:path jvm:input;
sh:name "input";
sh:class jvm:ChannelReader;
sh:minCount 1;
sh:maxCount 1;
], [
sh:path jvm:overwrite;
sh:name "overwrite";
sh:datatype xsd:boolean;
sh:minCount 0;
sh:maxCount 1;
], [
sh:path jvm:append;
sh:name "append";
sh:datatype xsd:boolean;
sh:minCount 0;
sh:maxCount 1;
];
sh:closed true;
sh:ignoredProperties (rdf:type).
54 changes: 54 additions & 0 deletions src/test/kotlin/std/FileUtilities.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package std

import java.io.File
import java.util.*
import kotlin.concurrent.thread
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlinx.coroutines.channels.Channel
import technology.idlab.bridge.MemoryReader
import technology.idlab.bridge.MemoryWriter
import technology.idlab.std.FileReader
import technology.idlab.std.FileWriter

class FileUtilities {
@Test
fun e2e() {
val input = File.createTempFile("input", "txt")
val output = File.createTempFile("output", "txt")

// Write to the input file.
input.writeText("Hello, World!")

// Configure the FileReader processor.
val channel = Channel<ByteArray>(1)
val reader = MemoryReader()
val writer = MemoryWriter()

reader.setChannel(channel)
writer.setChannel(channel)

val fileReader =
FileReader(
mapOf(
"path" to input.path,
"output" to writer,
))

val fileWriter =
FileWriter(
mapOf(
"path" to output.path,
"input" to reader,
"overwrite" to Optional.of(true),
"append" to Optional.of(false),
))

// Execute the FileReader processor.
listOf(fileReader, fileWriter).map { thread { it.exec() } }.forEach { it.join() }

// Check if the output is correct.
val result = output.readText()
assertEquals("Hello, World!", result)
}
}

0 comments on commit 79346d2

Please sign in to comment.