--- a/project/build.scala Mon Apr 09 18:03:56 2012 +0200
+++ b/project/build.scala Tue Apr 10 15:50:51 2012 +0200
@@ -7,7 +7,7 @@
// val specs = "org.scala-tools.testing" %% "specs" % "1.6.9" % "test"
val specs2 = "org.specs2" %% "specs2" % "1.6.1"
val specs2_scalaz = "org.specs2" %% "specs2-scalaz-core" % "6.0.1" % "test"
- val dispatch_version = "0.8.6"
+ val dispatch_version = "0.8.8"
val dispatch_http = "net.databinder" %% "dispatch-http" % dispatch_version
val dispatch_nio = "net.databinder" %% "dispatch-nio" % dispatch_version
val unfiltered_version = "0.6.1"
--- a/src/main/scala/Filesystem.scala Mon Apr 09 18:03:56 2012 +0200
+++ b/src/main/scala/Filesystem.scala Tue Apr 10 15:50:51 2012 +0200
@@ -10,7 +10,7 @@
import Scalaz._
import scala.sys
-import java.nio.file.Files
+import java.nio.file.{StandardOpenOption, Files}
class Filesystem(
baseDirectory: File,
@@ -101,6 +101,21 @@
} catch {
case e: IOException => e.fail
}
+
+ def create(): Validation[Throwable, Resource] = {
+ if (!fileOnDisk.exists())
+ new Throwable("Must first create "+name()).fail
+ else if (!fileOnDisk.isDirectory)
+ new Throwable("Can only create a resource in a directory/collection which this is not "+name()).fail
+ else try {
+ val path = Files.createTempFile(fileOnDisk.toPath,"res",lang.suffix)
+ resource(new URL(name(),path.getFileName.toString)).success
+ } catch {
+ case ioe: IOException => ioe.fail
+ }
+ }
+
+
}
}
--- a/src/main/scala/GraphCache.scala Mon Apr 09 18:03:56 2012 +0200
+++ b/src/main/scala/GraphCache.scala Tue Apr 10 15:50:51 2012 +0200
@@ -116,6 +116,9 @@
def createDirectory(model: Model) = throw new MethodNotSupportedException("not implemented")
def delete = throw new MethodNotSupportedException("not implemented")
+
+ def create() = throw new MethodNotSupportedException("not implemented")
+
}
private def getUrl(u: URL) = {
--- a/src/main/scala/Lang.scala Mon Apr 09 18:03:56 2012 +0200
+++ b/src/main/scala/Lang.scala Tue Apr 10 15:50:51 2012 +0200
@@ -6,6 +6,14 @@
package org.w3.readwriteweb
sealed trait Lang {
+
+ def suffix = this match {
+ case RDFXML => ".rdf"
+ case TURTLE => ".ttl"
+ case N3 => ".n3"
+ case XHTML => ".xhtml"
+ case HTML => ".html"
+ }
def contentType = this match {
case RDFXML => "application/rdf+xml"
--- a/src/main/scala/ReadWriteWeb.scala Mon Apr 09 18:03:56 2012 +0200
+++ b/src/main/scala/ReadWriteWeb.scala Tue Apr 10 15:50:51 2012 +0200
@@ -15,7 +15,8 @@
QueryTypeConstruct => CONSTRUCT,
QueryTypeDescribe => DESCRIBE}
-import scalaz.{Resource => _}
+import scalaz.{Scalaz, Resource => _}
+import Scalaz._
import unfiltered.request._
import unfiltered.Cycle
import unfiltered.response._
@@ -111,6 +112,23 @@
} yield Created
case PUT(_) =>
BadRequest ~> ResponseString("Content-Type MUST be one of: " + Lang.supportedAsString)
+ case POST(_) & RequestContentType(ct) if representation == DirectoryRepr =>
+ r.create() failMap { t => NotFound ~> ResponseString(t.getStackTraceString)} flatMap { rNew =>
+ Post.parse(Body.stream(req), rNew.name, ct) match {
+ case PostRDF(model) => {
+ logger.info("RDF content:\n" + model.toString())
+ for {
+ model <- rNew.save(model) failMap {
+ t => InternalServerError ~> ResponseString(t.getStackTraceString)
+ }
+ } yield Created ~> ResponseHeader("Location",Seq(rNew.name.toString))
+ }
+ case _ => {
+ logger.info("Couldn't parse the request")
+ (BadRequest ~> ResponseString("You MUST provide valid content for given Content-Type: " + ct)).success
+ }
+ }
+ }
case POST(_) & RequestContentType(ct) if Post.supportContentTypes contains ct => {
Post.parse(Body.stream(req), uri, ct) match {
case PostUnknown => {
--- a/src/main/scala/Resource.scala Mon Apr 09 18:03:56 2012 +0200
+++ b/src/main/scala/Resource.scala Tue Apr 10 15:50:51 2012 +0200
@@ -22,6 +22,9 @@
def get(policy: CacheControl.Value = CacheControl.CacheFirst): Validation[Throwable, Model]
def delete: Validation[Throwable, Unit]
def save(model:Model):Validation[Throwable, Unit]
+
+ //These two methods only work when called on directories
def createDirectory(model: Model): Validation[Throwable, Unit]
+ def create(): Validation[Throwable, Resource]
}
--- a/src/test/scala/CreateContentSpecs.scala Mon Apr 09 18:03:56 2012 +0200
+++ b/src/test/scala/CreateContentSpecs.scala Tue Apr 10 15:50:51 2012 +0200
@@ -4,6 +4,8 @@
import org.w3.readwriteweb.utiltest._
import dispatch._
+import java.net.URL
+import java.io.File
object PutRDFXMLSpec extends SomePeopleDirectory {
@@ -68,6 +70,28 @@
model must beIsomorphicWith (expectedFinalModel)
}
}
+
+ "POSTing an RDF document to a Joe's directory/collection" should {
+ "succeed and create a resource on disk" in {
+ val handler = dirUri.post(diffRDF, RDFXML) >+ { req =>
+ val loc: Handler[String] = req.get_header("Location")
+ val status_code: Handler[Int] = req.get_statusCode
+ (status_code,loc)
+ }
+ val (code, head) = Http(handler)
+ System.out.println("code="+code)
+ System.out.println("head="+head)
+ code must_== 201
+ val headURI = new URL(head.trim)
+ System.out.println("root="+root)
+ val file = new File(root, headURI.getPath.substring(baseURL.size))
+ file must exist
+ }
+
+ "create a resource on disk" in {
+// joeProfileOnDisk must be file
+ }
+ }
}
--- a/src/test/scala/util/specs.scala Mon Apr 09 18:03:56 2012 +0200
+++ b/src/test/scala/util/specs.scala Tue Apr 10 15:50:51 2012 +0200
@@ -89,8 +89,10 @@
trait SomeURI extends FilesystemBased {
val emptyModel = com.hp.hpl.jena.rdf.model.ModelFactory.createDefaultModel()
-
- lazy val dirUri = host / "wiki/people/"
+
+ val peopleDirPath = "wiki/people/"
+
+ lazy val dirUri = host / peopleDirPath
lazy val uri = host / "wiki/people/JoeLambda"
--- a/src/test/scala/util/utiltest.scala Mon Apr 09 18:03:56 2012 +0200
+++ b/src/test/scala/util/utiltest.scala Tue Apr 10 15:50:51 2012 +0200
@@ -59,7 +59,7 @@
def get_statusCode: Handler[Int] = new Handler(req, (c, r, e) => c, { case t => () })
def get_header(header: String): Handler[String] = req >:> { _(header).head }
-
+
def get: Request = req.copy(method="GET")
def >++ [A, B, C] (block: Request => (Handler[A], Handler[B], Handler[C])) = {