+ hacked a Scalatra-based servlet for the RDFValidator. It's a thin layer on top of FeDeRate/RDFXML default tip
authorAlexandre Bertails <bertails@w3.org>
Thu, 02 Dec 2010 16:53:45 -0500
changeset 3 70655aa764e5
parent 2 4e247348732f
+ hacked a Scalatra-based servlet for the RDFValidator. It's a thin layer on top of FeDeRate/RDFXML
project/build/Project.scala
src/main/scala/RDFValidator.scala
src/main/webapp/WEB-INF/web.xml
src/test/scala/RDFValidatorTest.scala
--- a/project/build/Project.scala	Thu Dec 02 16:51:59 2010 -0500
+++ b/project/build/Project.scala	Thu Dec 02 16:53:45 2010 -0500
@@ -1,15 +1,13 @@
 import sbt._
 
-trait Common extends BasicScalaProject {
-  val scalatools = "scala-tools" at "http://scala-tools.org/repo-snapshots"
-  val scalatest = "org.scalatest" % "scalatest" % "1.2-for-scala-2.8.0.final-SNAPSHOT" % "test"
-}
-
 class RDFValidator(info: ProjectInfo) extends DefaultWebProject(info) {
 
   override def compileOptions = super.compileOptions ++ Seq(Unchecked, Deprecation, ExplainTypes)
   override def defaultExcludes = super.defaultExcludes || "*~"
 
+  // val scalatools = "scala-tools" at "http://scala-tools.org/repo-snapshots"
+  // val scalatest = "org.scalatest" % "scalatest" % "1.2-for-scala-2.8.0.final-SNAPSHOT" % "test"
+
   val jettyConf = config("jetty")
   val jettyDep = "org.eclipse.jetty" % "jetty-webapp" % "7.0.2.v20100331" % "compile,jetty"
   override def jettyClasspath = managedClasspath(jettyConf)
@@ -18,4 +16,27 @@
   val jena = "com.hp.hpl.jena" % "jena" % "2.6.3"
   val jenaIri = "com.hp.hpl.jena" % "iri" % "0.8" from "http://openjena.org/repo/com/hp/hpl/jena/iri/0.8/iri-0.8.jar"
 
+  val scalatraVersion = "2.0.0-SNAPSHOT"
+  val scalatra = "org.scalatra" %% "scalatra" % scalatraVersion
+  val scalate = "org.scalatra" %% "scalatra-scalate" % scalatraVersion
+  val servletApi = "org.mortbay.jetty" % "servlet-api" % "2.5-20081211" % "provided"
+
+  val scalatest = "org.scalatra" %% "scalatra-scalatest" % scalatraVersion % "test"
+  val slf4jBinding = "ch.qos.logback" % "logback-classic" % "0.9.26" % "runtime"
+
+  // http://groups.google.com/group/simple-build-tool/msg/1f17b43807d06cda
+  override def testClasspath = super.testClasspath +++ buildCompilerJar
+
+  val sonatypeNexusSnapshots = "Sonatype Nexus Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
+  // For Scalate
+  val fuseSourceSnapshots = "FuseSource Snapshot Repository" at "http://repo.fusesource.com/nexus/content/repositories/snapshots"
+
+//  val turtle = "w3c" %% "turtle" % "1.0"
+  val rdfxml = "w3c" %% "rdfxml" % "1.0" intransitive()
+  val rdf = "w3c" %% "rdf" % "1.0" intransitive()
+
+  val databinder_net = "databinder.net repository" at "http://databinder.net/repo"
+  val dispatch = "net.databinder" %% "dispatch-http" % "0.7.7"
+
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/RDFValidator.scala	Thu Dec 02 16:53:45 2010 -0500
@@ -0,0 +1,129 @@
+package org.w3.rdfvalidator
+
+import org.scalatra._
+import java.net.URL
+import javax.servlet.http._
+
+import dispatch._
+import Http._
+import scala.xml.{NodeSeq, Comment, Elem}
+
+import org.w3.sw.rdf._
+import org.w3.sw.rdfxml._
+
+object RDFValidator {
+  val rdfxmlParser = new org.w3.sw.rdfxml.RDFXML
+
+  def toString(t:Triple):Elem = <li><span>{ toString(t.s) }</span> <span>{ toString(t.p) }</span> <span>{ toString(t.o) }</span></li>
+  def toString(s:Subject):String = {
+    val SubjectNode(n) = s
+    toString(n)
+  }
+  def toString(p:Predicate):String = {
+    val PredicateIRI(iri) = p
+    toString(iri)
+  }
+  def toString(iri:IRI):String = {
+    val IRI(i) = iri
+    "<"+i+">"
+  }
+  def toString(bnode:BNode):String = {
+    val BNode(label) = bnode
+    "_:"+label
+  }
+  def toString(n:Node):String = {
+    n match {
+      case NodeIRI(iri)     => toString(iri)
+      case NodeBNode(bnode) => toString(bnode)
+    }
+  }
+  def toString(o:Object):String = o match {
+    case ObjectNode(n) => toString(n)
+    case ObjectLiteral(l) => toString(l)
+  }
+  def toString(l:Literal):String = l match {
+    case PlainLiteral(lexicalForm, langtag) => "\"" + lexicalForm + "\"" + { if (langtag.isDefined) ("@"+langtag.get) else "" }
+    case TypedLiteral(lexicalForm, datatype) => "\"" + lexicalForm + "\"^^" + toString(datatype)
+  }
+
+  def message(title:String, description:String):NodeSeq =
+    <message type="info"> 
+      <title>{ title }</title> 
+      <description>{ description }</description> 
+    </message> 
+
+  def renderMessage(graph:Graph) =
+    if (graph.nonEmpty)
+      <message type="info"> 
+        <title>Parsed triples</title> 
+        <description>{ <ol>{ graph map { toString(_) } }</ol> }</description> 
+      </message>
+    else
+      Comment(" no parsed triple ")
+
+  def renderMessage(e:ParseError) = {
+    val title = e.errorType match {
+      case RDFParseError => "RDF issue"
+      case XMLParseError => "XML issue"
+    }
+    val errorType = e.level match {
+      case Warning            => "warning"
+      case FatalError | Error => "error"
+    }
+    <message type={ errorType }> 
+      <title>{ title }</title> 
+      <description>{ e.message }</description> 
+    </message> 
+  }
+
+}
+
+
+
+class RDFValidator extends ScalatraServlet {
+
+  import RDFValidator._
+
+  get("/*", request.getParameter("uri") != null) {
+    contentType = "text/xml"
+    val uri = request.getParameter("uri")
+    val http = new Http
+    try {
+      http(uri >> { in => {
+        val (graph, parseErrors) = rdfxmlParser.toGraph(in)
+        val statusValue =
+          if (parseErrors exists { e => e.level == FatalError || e.level == Error })
+            "failed"
+          else
+            "passed"
+        <observationresponse xmlns="http://www.w3.org/2009/10/unicorn/observationresponse" xml:lang="en" ref={ uri }>
+          <status value={ statusValue }/>
+          { renderMessage(graph) }
+          { parseErrors map { renderMessage(_) } }
+        </observationresponse>
+      }})
+    } catch {
+      case StatusCode(code, contents) => {
+        <observationresponse xmlns="http://www.w3.org/2009/10/unicorn/observationresponse" xml:lang="en" ref={ uri }>
+          <status value="failed"/>
+          { message("HTTP "+code, contents) }
+        </observationresponse>
+      }
+      case e:Exception => {
+        e.printStackTrace
+        <observationresponse xmlns="http://www.w3.org/2009/10/unicorn/observationresponse" xml:lang="en" ref={ uri }>
+          <status value="failed"/>
+          <message type="info"> 
+            <title>Something wrong happened</title> 
+            <description>{ e.getMessage }</description> 
+          </message> 
+        </observationresponse>
+      }
+    }
+  }
+
+  notFound {
+    "notFound"
+  }
+
+}
--- a/src/main/webapp/WEB-INF/web.xml	Thu Dec 02 16:51:59 2010 -0500
+++ b/src/main/webapp/WEB-INF/web.xml	Thu Dec 02 16:53:45 2010 -0500
@@ -5,34 +5,24 @@
     This is the friggin' RDF Validator
   </description>
 
+  <!-- <filter> -->
+  <!--   <filter-name>rdfvalidator</filter-name> -->
+  <!--   <filter-class>org.w3.rdfvalidator.RDFValidator</filter-class> -->
+  <!-- </filter> -->
+
+  <!-- <filter-mapping> -->
+  <!--   <filter-name>rdfvalidator</filter-name> -->
+  <!--   <url-pattern>/*</url-pattern> -->
+  <!-- </filter-mapping> -->
+
   <servlet>
-    <servlet-name>RDFValidatorServlet</servlet-name>
-    <servlet-class>org.w3c.rdfvalidator.ARPServlet</servlet-class>
-    <init-param>
-      <param-name>SERVLET_TMP_DIR</param-name>
-      <param-value>RDFValidator/ARPServlet.tmp</param-value>
-    </init-param>
-    <init-param>
-      <param-name>BITMAPPED_FONT</param-name>
-      <param-value>cyberbit</param-value> <!-- might try cyberbit, ariel, arialuni -->
-    </init-param>
-    <init-param>
-      <param-name>VECTOR_FONT</param-name>
-      <param-value>Courier</param-value> <!-- might try Courier, arialuni -->
-    </init-param>
-    <init-param>
-      <param-name>RENDER_DOT</param-name>
-      <param-value>RDFValidator/renderDot</param-value>
-    </init-param>
-    <init-param>
-      <param-name>LOG_A_LOT</param-name>
-      <param-value>1</param-value>
-    </init-param>
+    <servlet-name>rdfvalidator</servlet-name>
+    <servlet-class>org.w3.rdfvalidator.RDFValidator</servlet-class>
   </servlet>
 
   <servlet-mapping>
-    <servlet-name>RDFValidatorServlet</servlet-name>
-    <url-pattern>/rdfval</url-pattern>
+    <servlet-name>rdfvalidator</servlet-name>
+    <url-pattern>/*</url-pattern>
   </servlet-mapping>
 
 </web-app>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/scala/RDFValidatorTest.scala	Thu Dec 02 16:53:45 2010 -0500
@@ -0,0 +1,30 @@
+package org.w3.rdfvalidator
+
+import org.scalatra.test.scalatest._
+import org.scalatest.matchers._
+
+class RDFValidatorTest extends ScalatraFunSuite with ShouldMatchers {
+
+  addServlet(classOf[RDFValidator], "/*")
+
+  def validate(uri:String, expectedUnicornStatus:String, contains:String) =
+    test(uri) {
+      get("/rdfvalidator?uri="+uri) {
+        status should equal (200)
+        val unicornStatus = (scala.xml.XML.loadString(body) \ "status" \ "@value").head.asInstanceOf[scala.xml.Text].toString
+        unicornStatus should equal (expectedUnicornStatus)
+        body should include (contains)
+      }
+    }
+
+  def failed(uri:String, contains:String) =
+    validate(uri, "failed", contains)
+
+  def passed(uri:String, contains:String) =
+    validate(uri, "passed", contains)
+
+  failed("http://www.w3.org/2000/10/rdf-tests/rdfcore/rdf-containers-syntax-vs-schema/error001.rdf", "E206")
+  failed("http://www.w3.org/2000/10/rdf-tests/rdfcore/rdf-containers-syntax-vs-schema/error002.rdf", "E204")
+  passed("http://www.w3.org/People/Berners-Lee/card.rdf", "")
+
+}