--- a/src/main/scala/Main.scala Fri Aug 26 00:05:16 2011 -0400
+++ b/src/main/scala/Main.scala Fri Aug 26 13:52:51 2011 -0400
@@ -14,6 +14,10 @@
import com.hp.hpl.jena.rdf.model._
import com.hp.hpl.jena.query._
import com.hp.hpl.jena.update._
+import com.hp.hpl.jena.shared.JenaException
+
+class MSAuthorVia(value:String) extends ResponseHeader("MS-Author-Via", List(value))
+object ViaSPARQL extends MSAuthorVia("SPARQL")
// holds some Unfiltered plans
class ReadWriteWeb(base:File) {
@@ -23,32 +27,75 @@
val echo = unfiltered.filter.Planify {
case Path(Seg("echo" :: p :: Nil)) => ResponseString(p)
}
-
+
val read = unfiltered.filter.Planify {
case req @ Path(path) => {
- val fis = new FileInputStream(new File(base, path))
- /* http://jena.sourceforge.net/tutorial/RDF_API/index.html#ch-Reading%20RDF */
- val model:Model = ModelFactory.createDefaultModel()
- model.read(fis, "http://www.w3.org/People/Berners-Lee/")
+ val baseURI = req.underlying.getRequestURL.toString
+ val fileOnDisk = new File(base, path)
+
+
+ def foo():(OutputStream, Model) = {
+ // get empty model if file not on disk
+ val model = ModelFactory.createDefaultModel()
+ if (fileOnDisk exists) {
+ val fis = new FileInputStream(fileOnDisk)
+ model.read(fis, baseURI)
+ fis.close()
+ }
+ // if file does not exist, create it
+ if (! fileOnDisk.exists) {
+ // create parent directory if needed
+ val parent = fileOnDisk.getParentFile
+ if (! parent.exists) println(parent.mkdirs)
+ val r = fileOnDisk.createNewFile()
+ logger.debug("Create file %s with success: %s" format (fileOnDisk.getAbsolutePath, r.toString))
+ }
+ val fos = new FileOutputStream(fileOnDisk)
+ (fos, model)
+ }
+ def loadModel(file:File):Model = {
+ val fis = new FileInputStream(fileOnDisk)
+ val m = ModelFactory.createDefaultModel()
+ try {
+ m.read(fis, baseURI)
+ } catch {
+ case je:JenaException => logger.error("File %s was eitheir empty or corrupted: considered as empty graph" format fileOnDisk.getAbsolutePath)
+ }
+ fis.close()
+ m
+ }
req match {
case GET(_) => {
- Ok ~> new ResponseStreamer {
+ val model:Model = loadModel(fileOnDisk)
+ Ok ~> ViaSPARQL ~> new ResponseStreamer {
def stream(os:OutputStream):Unit = {
- /* http://jena.sourceforge.net/tutorial/RDF_API/index.html#ch-Writing%20RDF */
- // val lang = "RDF/XML-ABBREV"
- val lang = "TURTLE"
- model.write(os, lang)
+ val lang = "RDF/XML-ABBREV" // "TURTLE"
+ model.write(os, lang, baseURI)
}
}
}
+ case PUT(_) => {
+ val bodyModel = {
+ val m = ModelFactory.createDefaultModel()
+ m.read(Body.stream(req), baseURI)
+ m
+ }
+ val (fos, _) = foo()
+ bodyModel.write(fos, "RDF/XML-ABBREV", baseURI)
+ fos.close()
+ Ok ~> ResponseString("don't know what to return")
+ }
case POST(_) => {
- val bodyStream = Body.stream(req)
/* http://openjena.org/ARQ/javadoc/com/hp/hpl/jena/update/UpdateFactory.html */
- val update:UpdateRequest = UpdateFactory.read(bodyStream)
+ val update:UpdateRequest = UpdateFactory.read(Body.stream(req))
+ val (fos, model) = foo()
UpdateAction.execute(update, model)
+ model.write(fos)
+ fos.close()
+ // give back the modified model
Ok ~> new ResponseStreamer {
def stream(os:OutputStream):Unit = {
- val lang = "TURTLE"
+ val lang = "RDF/XML-ABBREV"
model.write(os, lang)
}
}
--- a/src/test/scala/Test.scala Fri Aug 26 00:05:16 2011 -0400
+++ b/src/test/scala/Test.scala Fri Aug 26 13:52:51 2011 -0400
@@ -5,15 +5,26 @@
import unfiltered.response._
import unfiltered.request._
import dispatch._
-import java.io.File
+import java.io._
+
+import com.hp.hpl.jena.rdf.model._
+import com.hp.hpl.jena.query._
+import com.hp.hpl.jena.update._
+
+// a Handler that returns the http code
+object HttpCode {
+ def apply(req:Request):Handler[Int] = new Handler(req, (c, r, e) => c, null)
+}
object ReadWriteWebSpec extends Specification with unfiltered.spec.jetty.Served {
+ val base = new File("src/main/resources")
+
def post(req:Request, body:String) = (req <<< body).copy(method="POST")
- def setup = { _.filter(new ReadWriteWeb(new File("src/main/resources")).read) }
+ def setup = { _.filter(new ReadWriteWeb(base).read) }
- val timBL = host / "/People/Berners-Lee/card#i"
+ val timBL = host / "People/Berners-Lee/card#i"
"GET on TimBL's FOAF profile" should {
"return something" in {
@@ -22,25 +33,33 @@
}
}
- val update = host / "People/Berners-Lee/card#i"
+ val joe = host / "2007/wiki/people/JoeLambda"
+ val joeOnDisk = new File(base, "2007/wiki/people/JoeLambda")
+ if (joeOnDisk.exists) joeOnDisk.delete()
- val sparqlAdd =
+ val insert =
"""
-PREFIX dc: <http://purl.org/dc/elements/1.1/>
-INSERT DATA
-{
- <http://example/book1> dc:title "A new book" ;
- dc:creator "A.N.Other" .
-}
+INSERT DATA { <http://dig.csail.xvm.mit.edu/2007/wiki/people/JoeLambda#JL> <http://xmlns.com/foaf/0.1/age> 66 }
"""
-
- "SPARQL UPDATE on TimBL's FOAF profile" should {
- "return something new" in {
- val body:String = Http(post(timBL, sparqlAdd) as_str)
- // println(body)
- body must be matching ".*A new book.*"
-// println("here")
+
+ "INSERT query on Joe's URI" should {
+ "return a 200" in {
+ val httpCode:Int = Http(HttpCode(post(joe, insert)))
+ httpCode must_== 200
+ }
+ "create the corresponding file on disk" in {
+ joeOnDisk must exist
+ }
+ "create a valid rdf document with exactly one triple" in {
+ val model = Http(joe >> { is => {
+ val m = ModelFactory.createDefaultModel()
+ m.read(is, joe.path)
+ m
+ } } )
+ model.size must_== 1
}
}
+
+ if (joeOnDisk.exists) joeOnDisk.delete()
}