Skip to content

Commit

Permalink
Add AbstractHeadHandler and Refactor [Xml/Json]/Head.kt (#662)
Browse files Browse the repository at this point in the history
  • Loading branch information
redwanulsourav authored Sep 20, 2023
1 parent 62d22e9 commit 45b12fe
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 147 deletions.
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)
}
}

0 comments on commit 45b12fe

Please sign in to comment.