Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AbstractHeadHandler and Refactor [Xml/Json]/Head.kt #662

Merged
merged 1 commit into from
Sep 20, 2023
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package io.sirix.rest.crud

import io.sirix.access.Databases
import io.sirix.access.trx.node.HashType
import io.sirix.api.Database
import io.sirix.api.NodeCursor
import io.sirix.api.NodeReadOnlyTrx
import io.sirix.api.ResourceSession
import io.sirix.api.json.JsonResourceSession
import io.vertx.core.http.HttpHeaders
import io.vertx.ext.web.Route
import io.vertx.ext.web.RoutingContext
import io.vertx.kotlin.coroutines.await
import java.nio.file.Path
import java.time.LocalDateTime
import java.time.ZoneId

abstract class AbstractHeadHandler< T : ResourceSession<*, *>> (
private val location: Path){
suspend fun handle(ctx: RoutingContext): Route {
val databaseName = ctx.pathParam("database")
val resource = ctx.pathParam("resource")

if (databaseName == null || resource == null) {
throw IllegalStateException("Database name and resource name must be given.")
}

ctx.vertx().executeBlocking<Unit> {
head(databaseName, ctx, resource)
}.await()

return ctx.currentRoute()
}
fun head(databaseName: String, ctx: RoutingContext, resource: String) {
val revision = ctx.queryParam("revision").getOrNull(0)
val revisionTimestamp = ctx.queryParam("revision-timestamp").getOrNull(0)

val nodeId = ctx.queryParam("nodeId").getOrNull(0)

val database = openDatabase(location.resolve(databaseName))

database.use {
val manager = database.beginResourceSession(resource)

manager.use {
if (manager.resourceConfig.hashType == HashType.NONE) {
ctx.response().putHeader(HttpHeaders.ETAG, "")
} else {
val revisionNumber = getRevisionNumber(revision, revisionTimestamp, manager)

val rtx = manager.beginNodeReadOnlyTrx(revisionNumber)

rtx.use {
if (nodeId != null) {
if (!rtx.moveTo(nodeId.toLong())) {
throw IllegalStateException("Node with ID $nodeId doesn't exist.")
}
} else if (rtx.isDocumentRoot) {
(rtx as NodeCursor).moveToFirstChild()
}

ctx.response().putHeader(HttpHeaders.ETAG, rtx.hash.toString())
}
}
}
}

ctx.response().end()
}
private fun getRevisionNumber(rev: String?, revTimestamp: String?, manager: T): Int {
return rev?.toInt()
?: if (revTimestamp != null) {
var revision = getRevisionNumber(manager, revTimestamp)
if (revision == 0) {
++revision
} else {
revision
}
} else {
manager.mostRecentRevisionNumber
}
}

private fun getRevisionNumber(manager: T, revision: String): Int {
val revisionDateTime = LocalDateTime.parse(revision)
val zdt = revisionDateTime.atZone(ZoneId.systemDefault())
return manager.getRevisionNumber(zdt.toInstant())
}
abstract fun openDatabase(dbFile: Path): Database<T>
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,81 +6,16 @@ import io.vertx.ext.web.RoutingContext
import io.vertx.kotlin.coroutines.await
import io.sirix.access.Databases
import io.sirix.access.trx.node.HashType
import io.sirix.api.Database
import io.sirix.api.json.JsonResourceSession
import io.sirix.api.xml.XmlResourceSession
import io.sirix.rest.crud.AbstractHeadHandler
import java.nio.file.Path
import java.time.LocalDateTime
import java.time.ZoneId

class JsonHead(private val location: Path) {
suspend fun handle(ctx: RoutingContext): Route {
val databaseName = ctx.pathParam("database")
val resource = ctx.pathParam("resource")

if (databaseName == null || resource == null) {
throw IllegalArgumentException("Database name and resource name must be given.")
}

ctx.vertx().executeBlocking<Unit> {
head(databaseName, ctx, resource)
}.await()

return ctx.currentRoute()
}

private fun head(databaseName: String, ctx: RoutingContext, resource: String) {
val revision = ctx.queryParam("revision").getOrNull(0)
val revisionTimestamp = ctx.queryParam("revision-timestamp").getOrNull(0)

val nodeId = ctx.queryParam("nodeId").getOrNull(0)

val database = Databases.openJsonDatabase(location.resolve(databaseName))

database.use {
val manager = database.beginResourceSession(resource)

manager.use {
if (manager.resourceConfig.hashType == HashType.NONE) {
ctx.response().putHeader(HttpHeaders.ETAG, "")
} else {
val revisionNumber = getRevisionNumber(revision, revisionTimestamp, manager)

val rtx = manager.beginNodeReadOnlyTrx(revisionNumber)

rtx.use {
if (nodeId != null) {
if (!rtx.moveTo(nodeId.toLong())) {
throw IllegalStateException("Node with ID $nodeId doesn't exist.")
}
} else if (rtx.isDocumentRoot) {
rtx.moveToFirstChild()
}

ctx.response().putHeader(HttpHeaders.ETAG, rtx.hash.toString())
}
}
}
}

ctx.response().end()
}

private fun getRevisionNumber(rev: String?, revTimestamp: String?, manager: JsonResourceSession): Int {
return rev?.toInt()
?: if (revTimestamp != null) {
var revision = getRevisionNumber(manager, revTimestamp)
if (revision == 0) {
++revision
} else {
revision
}
} else {
manager.mostRecentRevisionNumber
}
}

private fun getRevisionNumber(manager: JsonResourceSession, revision: String): Int {
val revisionDateTime = LocalDateTime.parse(revision)
val zdt = revisionDateTime.atZone(ZoneId.systemDefault())
return manager.getRevisionNumber(zdt.toInstant())
class JsonHead(private val location: Path): AbstractHeadHandler<JsonResourceSession>(location) {
override fun openDatabase(dbFile: Path): Database<JsonResourceSession> {
return Databases.openJsonDatabase(dbFile)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,87 +6,16 @@ import io.vertx.ext.web.RoutingContext
import io.vertx.kotlin.coroutines.await
import io.sirix.access.Databases
import io.sirix.access.trx.node.HashType
import io.sirix.api.Database
import io.sirix.api.xml.XmlNodeReadOnlyTrx
import io.sirix.api.xml.XmlResourceSession
import io.sirix.rest.crud.AbstractHeadHandler
import java.nio.file.Path
import java.time.LocalDateTime
import java.time.ZoneId

class XmlHead(private val location: Path) {
suspend fun handle(ctx: RoutingContext): Route {
val databaseName = ctx.pathParam("database")
val resource = ctx.pathParam("resource")

if (databaseName == null || resource == null) {
throw IllegalStateException("Database name and resource name must be given.")
}

ctx.vertx().executeBlocking<Unit> {
head(databaseName, ctx, resource)
}.await()

return ctx.currentRoute()
}

private fun head(databaseName: String, ctx: RoutingContext, resource: String) {
val revision: String? = ctx.queryParam("revision").getOrNull(0)
val revisionTimestamp: String? = ctx.queryParam("revision-timestamp").getOrNull(0)

val nodeId: String? = ctx.queryParam("nodeId").getOrNull(0)

val database = Databases.openXmlDatabase(location.resolve(databaseName))

database.use {
val manager = database.beginResourceSession(resource)

manager.use {
if (manager.resourceConfig.hashType == HashType.NONE) {
ctx.response().putHeader(HttpHeaders.ETAG, "")
} else {
val revisionNumber = getRevisionNumber(revision, revisionTimestamp, manager)

val rtx = manager.beginNodeReadOnlyTrx(revisionNumber)

rtx.use {
if (nodeId != null) {
if (!rtx.moveTo(nodeId.toLong())) {
throw IllegalStateException("Node with ID ${nodeId} doesn't exist.")
} else {
writeResponse(ctx, rtx)
}
} else if (rtx.isDocumentRoot) {
rtx.moveToFirstChild()
writeResponse(ctx, rtx)
}
}
}
}
}

ctx.response().end()
}

private fun writeResponse(ctx: RoutingContext, rtx: XmlNodeReadOnlyTrx) {
ctx.response().putHeader(HttpHeaders.ETAG, rtx.hash.toString())
}

private fun getRevisionNumber(rev: String?, revTimestamp: String?, manager: XmlResourceSession): Int {
return rev?.toInt()
?: if (revTimestamp != null) {
var revision = getRevisionNumber(manager, revTimestamp)
if (revision == 0) {
++revision
} else {
revision
}
} else {
manager.mostRecentRevisionNumber
}
}

private fun getRevisionNumber(manager: XmlResourceSession, revision: String): Int {
val revisionDateTime = LocalDateTime.parse(revision)
val zdt = revisionDateTime.atZone(ZoneId.systemDefault())
return manager.getRevisionNumber(zdt.toInstant())
class XmlHead(private val location: Path): AbstractHeadHandler<XmlResourceSession>(location) {
override fun openDatabase(dbFile: Path): Database<XmlResourceSession> {
return Databases.openXmlDatabase(dbFile)
}
}
Loading