Skip to content

Commit

Permalink
better response message with the warnings of RDF parser #35
Browse files Browse the repository at this point in the history
  • Loading branch information
manonthegithub committed Jan 10, 2024
1 parent 4fd85fb commit 3f2bca6
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 20 deletions.
23 changes: 18 additions & 5 deletions src/main/scala/org/dbpedia/databus/ApiImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ApiImpl(config: Config) extends DatabusApi {
contextUrl(body.getBytes, defaultLang)
.map(jenaJsonLdContextWithFallbackForLocalhost(_, request.getRemoteHost).get)
)
.flatMap(m => Tractate.extract(m.getGraph, TractateV1.Version))
.flatMap(m => Tractate.extract(m._1.getGraph, TractateV1.Version))
.map(_.stringForSigning)

override def deleteFile(username: String, path: String, prefix: Option[String])(request: HttpServletRequest): Try[OperationSuccess] = {
Expand Down Expand Up @@ -72,12 +72,21 @@ class ApiImpl(config: Config) extends DatabusApi {
val ctx = ctxU.map(cu => jenaJsonLdContextWithFallbackForLocalhost(cu, request.getRemoteHost).get)
readModel(body.getBytes, lang, ctx)
.flatMap(model => {
saveToVirtuoso(model, graphId)({
graphToBytes(model.getGraph, defaultLang, ctxU)
saveToVirtuoso(model._1, graphId)({
graphToBytes(model._1.getGraph, defaultLang, ctxU)
.flatMap(a => saveFiles(username, Map(
pa -> a
)).map(hash => OperationSuccess(graphId, hash)))
})
}).transform(Success(_), e =>
if (model._2.isEmpty) {
Failure(e)
} else {
val ee = new RuntimeException(
s"Error saving data, potentially caused by: ${model._2.map(_.message).fold("")((l, r) => l + '\n' + r)}",
e)
ee.setStackTrace(Array.empty)
Failure(ee)
})
})
}

Expand Down Expand Up @@ -116,6 +125,10 @@ class ApiImpl(config: Config) extends DatabusApi {
override def saveFileMapException400(e: Throwable)(request: HttpServletRequest): Option[OperationFailure] = e match {
case _: JenaException => Some(OperationFailure(e.getMessage))
case _: VirtuosoException if e.getMessage.contains("SQ200") => Some(OperationFailure(s"Wrong value for type. ${e.getMessage}"))
case _: RuntimeException if e.getCause.isInstanceOf[VirtuosoException] && e.getMessage.contains("SQ200") =>
Some(OperationFailure(s"Wrong value for type. ${e.getMessage}"))
case _: RuntimeException if e.getCause.isInstanceOf[VirtuosoException] && e.getMessage.contains("SQ074") =>
Some(OperationFailure(s"Wrong input data. ${e.getMessage}"))
case _ => None
}

Expand All @@ -142,7 +155,7 @@ class ApiImpl(config: Config) extends DatabusApi {
.map(jenaJsonLdContextWithFallbackForLocalhost(_, request.getRemoteHost).get)
)
.flatMap(m =>
graphToBytes(m.getGraph, lang, ctxUri)
graphToBytes(m._1.getGraph, lang, ctxUri)
)
})
.map(new String(_))
Expand Down
40 changes: 34 additions & 6 deletions src/main/scala/org/dbpedia/databus/SparqlClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.apache.jena.atlas.json.JsonString
import org.apache.jena.graph.{Graph, Node}
import org.apache.jena.rdf.model.{Model, ModelFactory}
import org.apache.jena.riot.lang.JsonLDReader
import org.apache.jena.riot.system.StreamRDFLib
import org.apache.jena.riot.system.{ErrorHandler, ErrorHandlerFactory, StreamRDFLib}
import org.apache.jena.riot.writer.JsonLDWriter
import org.apache.jena.riot.{Lang, RDFDataMgr, RDFFormat, RDFLanguages, RDFParserBuilder, RDFWriter, RIOT}
import org.apache.jena.shacl.{ShaclValidator, Shapes, ValidationReport}
Expand Down Expand Up @@ -159,7 +159,7 @@ object RdfConversions {

val DefaultShaclLang = Lang.TTL

def readModel(data: Array[Byte], lang: Lang, context: Option[util.Context]): Try[Model] = Try {
def readModel(data: Array[Byte], lang: Lang, context: Option[util.Context]): Try[(Model, List[Warning])] = Try {
val model = ModelFactory.createDefaultModel()
val dataStream = new ByteArrayInputStream(data)
val dest = StreamRDFLib.graph(model.getGraph)
Expand All @@ -168,11 +168,14 @@ object RdfConversions {
.base(null)
.lang(lang)

val eh = newErrorHandlerWithWarnings
parser.errorHandler(eh)

context.foreach(cs =>
parser.context(cs))

parser.parse(dest)
model
(model, eh.warningsList)
}

def graphToBytes(model: Graph, outputLang: Lang, context: Option[URL]): Try[Array[Byte]] = Try {
Expand Down Expand Up @@ -200,15 +203,15 @@ object RdfConversions {

def validateWithShacl(file: Array[Byte], shaclData: Array[Byte], fileCtx: Option[util.Context], shaclCtx: Option[util.Context], modelLang: Lang): Try[ValidationReport] =
for {
shaclGra <- readModel(shaclData, DefaultShaclLang, shaclCtx)
model <- readModel(file, modelLang, fileCtx)
(shaclGra, _) <- readModel(shaclData, DefaultShaclLang, shaclCtx)
(model, _) <- readModel(file, modelLang, fileCtx)
re <- validateWithShacl(model, shaclGra.getGraph)
} yield re

def validateWithShacl(file: Array[Byte], fileCtx: Option[util.Context], shaclUri: String, modelLang: Lang): Try[ValidationReport] =
for {
shaclGra <- Try(RDFDataMgr.loadGraph(shaclUri))
model <- readModel(file, modelLang, fileCtx)
(model, _) <- readModel(file, modelLang, fileCtx)
re <- validateWithShacl(model, shaclGra)
} yield re

Expand Down Expand Up @@ -414,6 +417,31 @@ object RdfConversions {
sb.toString()
}

case class Warning(message: String)
private class ErrorHandlerWithWarnings extends ErrorHandler {
private val defaultEH = ErrorHandlerFactory.getDefaultErrorHandler

private var warnings: List[Warning] = List.empty

import org.apache.jena.riot.SysRIOT.fmtMessage

override def warning(message: String, line: Long, col: Long): Unit = {
warnings = warnings :+ Warning(fmtMessage(message, line, col))
defaultEH.warning(message, line, col)
}

override def error(message: String, line: Long, col: Long): Unit =
defaultEH.error(message, line, col)

override def fatal(message: String, line: Long, col: Long): Unit =
defaultEH.fatal(message, line, col)

def warningsList: List[Warning] = warnings
}

private def newErrorHandlerWithWarnings: ErrorHandlerWithWarnings =
new ErrorHandlerWithWarnings

}


39 changes: 39 additions & 0 deletions src/test/resources/report_syntax_err.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"@context": "https://raw.githubusercontent.com/dbpedia/databus/master/server/app/common/res/context.jsonld",
"@graph": [
{
"@id": "https://databus.coypu.org/narndt/coypu",
"@type": "Group",
"title": "CoyPu"
},
{
"@id": "https://databus.coypu.org/narndt/coypu/countries",
"@type": "Artifact",
"title": "Raise VirtuosoException",
"abstract": "Counties and regions",
"description": "Counties and regions"
},
{
"@type": [
"Version",
"Dataset"
],
"@id": "https://databus.coypu.org/narndt/coypu/countries/2023-09-18T122214Z",
"hasVersion": "2023-09-18T122214Z",
"title": "Countries",
"abstract": "Countries\n2023-09-18T12:22:14Z",
"description": "Countries\n2023-09-18T12:22:14Z",
"license": "https://dalicc.net/licenselibrary/Cc010Universal",
"wasDerivedFrom": "https://metadata.coypu.org/dataset/wikidata-distribution\nWikidata Query Service\nhttps://query.wikidata.org/",
"distribution": [
{
"@type": "Part",
"formatExtension": "ttl",
"compression": "none",
"downloadURL": "https://databus.coypu.org/dav/narndt/coypu/countries/2023-09-18T122214Z/countries_freqency=static.ttl",
"dcv:frequency": "static"
}
]
}
]
}
13 changes: 13 additions & 0 deletions src/test/scala/org/dbpedia/databus/DatabusScalatraTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,19 @@ class DatabusScalatraTest extends ScalatraFlatSpec with BeforeAndAfter {

}

"File save" should "report problems in input" in {


val file = "report_syntax_err.jsonld"
val bytes = Files.readAllBytes(Paths.get(getClass.getClassLoader.getResource(file).getFile))

post("/databus/graph/save?repo=kuckuck&path=pa/syntax_err.jsonld", bytes) {
(status >= 400) should equal(true)
response.body.contains("Spaces are not legal in URIs/IRIs") should equal(true)
}

}

"File read" should "return 404" in {

get("/databus/graph/read?repo=kuckuck&path=pa/not_existing.jsonld") {
Expand Down
21 changes: 12 additions & 9 deletions src/test/scala/org/dbpedia/databus/ExternalApiEmul.scala
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
package org.dbpedia.databus

import org.scalatra.{Ok, ScalatraServlet}
import org.scalatra.{BadRequest, Ok, ScalatraServlet}

class ExternalApiEmul extends ScalatraServlet {

post("/oauth/*"){
post("/oauth/*") {
Ok(
"""
|{"access_token": "token"}
|""".stripMargin)
}

get("/api/v4/*"){
get("/api/v4/*") {
Ok(
"""
|{"id": "commit id?"}
|""".stripMargin)
}

get("/api/v4/projects"){
get("/api/v4/projects") {
Ok(
"""
|[{
Expand All @@ -28,21 +28,24 @@ class ExternalApiEmul extends ScalatraServlet {
|""".stripMargin)
}

post("/api/v4/*"){
post("/api/v4/*") {
Ok(
"""
|{"id": "random id"}
|""".stripMargin)
}



get("/virtu/*"){
get("/virtu/*") {
Ok("Virtuoso emul")
}

post("/virtu/*"){
Ok("Virtuoso emul")
post("/virtu/*") {
if (request.multiParameters.get("query").get.exists(_.contains("Raise VirtuosoException"))) {
BadRequest("virtuoso.jdbc4.VirtuosoException: SQ074: Line 38: SP030: SPARQL compiler, line 5: syntax error")
} else {
Ok("Virtuoso emul")
}
}

}

0 comments on commit 3f2bca6

Please sign in to comment.