catching up fully with Alex Bertails changes. Added also a bit of mime type guessing in the FileSystem class' get method
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/log4j.properties Sun Oct 16 22:47:37 2011 +0200
@@ -0,0 +1,9 @@
+// Appenders
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.layout=org.apache.log4j.PatternLayout
+// Pattern not for use in production ( %C
+log4j.appender.Console.layout.ConversionPattern=%-5p (%F:%L) : %m%n
+
+// Loggers
+log4j.rootLogger=info, Console
+log4j.logger.org.w3.readwriteweb=debug
--- a/src/main/scala/Authoritative.scala Sun Oct 16 21:38:18 2011 +0200
+++ b/src/main/scala/Authoritative.scala Sun Oct 16 22:47:37 2011 +0200
@@ -1,58 +1,31 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
package org.w3.readwriteweb
import unfiltered.request._
import java.net.URL
-sealed trait Representation
-
-object Representation {
-
- def fromSuffix(suffix: String): Representation = {
- suffix match {
- case "n3" => RDFRepr(N3)
- case "turtle" | "ttl" => RDFRepr(TURTLE)
- case "rdf" => RDFRepr(RDFXML)
- case "htm" | "html" | "xhtml" => HTMLRepr
- case _ => UnknownRepr
- }
- }
-
- val htmlCharsets = Set("text/html", "application/xhtml+xml")
-
- def acceptsHTML(ct: Iterable[String]) =
- ! (htmlCharsets & ct.toSet).isEmpty
-
- def fromAcceptedContentTypes(ct: Iterable[String]): Representation = {
- Lang(ct) map RDFRepr.apply getOrElse {
- if (acceptsHTML(ct))
- HTMLRepr
- else
- UnknownRepr
- }
- }
-
- /** implements http://www.w3.org/2001/tag/doc/metaDataInURI-31 and http://www.w3.org/2001/tag/doc/mime-respect
- *
- * if there is no known suffix (eg. the URI was already the authoritative one),
- * inspects the given accepted content types
- *
- * This knows only about the RDF and HTML charsets
- */
- def apply(
- suffixOpt: Option[String],
- ct: Iterable[String]): Representation = {
- suffixOpt map fromSuffix match {
- case None | Some(UnknownRepr) => fromAcceptedContentTypes(ct)
- case Some(repr) => repr
- }
- }
-}
-
-case class RDFRepr(lang: Lang) extends Representation
-case object HTMLRepr extends Representation
-case object UnknownRepr extends Representation
-case object NoRepr extends Representation
-
object Authoritative {
val r = """^(.*)\.(\w{0,4})$""".r
@@ -61,8 +34,10 @@
val uri = req.underlying.getRequestURL.toString
val suffixOpt = uri match {
case r(_, suffix) => Some(suffix)
+ case _ if uri endsWith "/" => Some("/")
case _ => None
}
Some((new URL(uri), Representation(suffixOpt, Accept(req))))
}
+
}
--- a/src/main/scala/Filesystem.scala Sun Oct 16 21:38:18 2011 +0200
+++ b/src/main/scala/Filesystem.scala Sun Oct 16 22:47:37 2011 +0200
@@ -7,40 +7,58 @@
import org.slf4j.{Logger, LoggerFactory}
import com.hp.hpl.jena.rdf.model._
import com.hp.hpl.jena.shared.JenaException
-import sys.error
-import scalaz._
+
+import scalaz.{sys => _, _}
import Scalaz._
class Filesystem(
baseDirectory: File,
val basePath: String,
- val lang: String = "RDF/XML-ABBREV")(mode: RWWMode) extends ResourceManager {
+ val lang: Lang)(mode: RWWMode) extends ResourceManager {
- val logger:Logger = LoggerFactory.getLogger(this.getClass)
-
- def sanityCheck():Boolean = baseDirectory.exists
-
- def resource(url:URL):Resource = new Resource {
- val relativePath:String = url.getPath.replaceAll("^"+basePath.toString+"/?", "")
+ val logger: Logger = LoggerFactory.getLogger(this.getClass)
+
+ def sanityCheck(): Boolean =
+ baseDirectory.exists && baseDirectory.isDirectory
+
+ def resource(url: URL): Resource = new Resource {
+ val relativePath: String = url.getPath.replaceAll("^"+basePath.toString+"/?", "")
val fileOnDisk = new File(baseDirectory, relativePath)
-
- private def createFileOnDisk():Unit = {
- // create parent directory if needed
+
+ private def parentMustExist(): Unit = {
val parent = fileOnDisk.getParentFile
- if (! parent.exists) println(parent.mkdirs)
+ if (! parent.exists) sys.error("Parent directory %s does not exist" format parent.getAbsolutePath)
+ if (! parent.isDirectory) sys.error("Parent %s is not a directory" format parent.getAbsolutePath)
+ }
+
+ private def createDirectoryOnDisk(): Unit = {
+ parentMustExist()
+ val r = fileOnDisk.mkdir()
+ if (!r) sys.error("Could not create %s" format fileOnDisk.getAbsolutePath)
+ logger.debug("%s successfully created: %s" format (fileOnDisk.getAbsolutePath, r.toString))
+ }
+
+ private def createFileOnDisk(): Unit = {
+ parentMustExist()
val r = fileOnDisk.createNewFile()
- logger.debug("Create file %s with success: %s" format (fileOnDisk.getAbsolutePath, r.toString))
+ logger.debug("%s successfully created: %s" format (fileOnDisk.getAbsolutePath, r.toString))
}
-
+
def get(): Validation[Throwable, Model] = {
val model = ModelFactory.createDefaultModel()
+ val guessLang = fileOnDisk.getName match {
+ case Authoritative.r(_,suffix) => Representation.fromSuffix(suffix) match {
+ case RDFRepr(rdfLang) => rdfLang
+ case _ => lang
+ }
+ }
if (fileOnDisk.exists()) {
val fis = new FileInputStream(fileOnDisk)
try {
- val reader = model.getReader(lang)
+ val reader = model.getReader(guessLang.jenaLang)
reader.read(model, fis, url.toString)
} catch {
- case je:JenaException => error(je.toString)
+ case je: JenaException => throw je
}
fis.close()
model.success
@@ -51,18 +69,29 @@
}
}
}
-
- def save(model:Model):Validation[Throwable, Unit] =
+
+ def save(model: Model): Validation[Throwable, Unit] =
try {
createFileOnDisk()
val fos = new FileOutputStream(fileOnDisk)
- val writer = model.getWriter(lang)
+ val writer = model.getWriter(lang.jenaLang)
writer.write(model, fos, url.toString)
fos.close().success
} catch {
case t => t.fail
}
+ def createDirectory(model: Model): Validation[Throwable, Unit] =
+ try {
+ createDirectoryOnDisk().success
+// val fos = new FileOutputStream(fileOnDisk)
+// val writer = model.getWriter(lang.contentType)
+// writer.write(model, fos, url.toString)
+// fos.close().success
+ } catch {
+ case t => t.fail
+ }
+
}
}
--- a/src/main/scala/Lang.scala Sun Oct 16 21:38:18 2011 +0200
+++ b/src/main/scala/Lang.scala Sun Oct 16 22:47:37 2011 +0200
@@ -38,7 +38,7 @@
case TURTLE => "TURTLE"
case N3 => "N3"
}
-
+
}
object Lang {
@@ -55,7 +55,7 @@
case "text/turtle" => Some(TURTLE)
case "application/rdf+xml" => Some(RDFXML)
case _ => None
- }
+ }
def apply(cts: Iterable[String]): Option[Lang] =
cts map Lang.apply collectFirst { case Some(lang) => lang }
--- a/src/main/scala/ReadWriteWebMain.scala Sun Oct 16 21:38:18 2011 +0200
+++ b/src/main/scala/ReadWriteWebMain.scala Sun Oct 16 22:47:37 2011 +0200
@@ -12,7 +12,7 @@
import ArgotConverters._
object ReadWriteWebMain {
- val logger:Logger = LoggerFactory.getLogger(this.getClass)
+ val logger: Logger = LoggerFactory.getLogger(this.getClass)
val postUsageMsg= Some("""
|PROPERTIES
@@ -31,56 +31,56 @@
val parser = new ArgotParser("read-write-web",postUsage=postUsageMsg)
val mode = parser.option[RWWMode](List("mode"), "m", "wiki mode: wiki or strict") {
- (sValue, opt) =>
- sValue match {
- case "wiki" => AllResourcesAlreadyExist
- case "strict" => ResourcesDontExistByDefault
- case _ => throw new ArgotConversionException("Option %s: must be either wiki or strict" format (opt.name, sValue))
- }
+ (sValue, opt) =>
+ sValue match {
+ case "wiki" => AllResourcesAlreadyExist
+ case "strict" => ResourcesDontExistByDefault
+ case _ => throw new ArgotConversionException("Option %s: must be either wiki or strict" format (opt.name, sValue))
}
+ }
- val rdfLanguage = parser.option[String](List("language"), "l", "RDF language: n3, turtle, or rdfxml") {
- (sValue, opt) =>
- sValue match {
- case "n3" => "N3"
- case "turtle" => "N3"
- case "rdfxml" => "RDF/XML-ABBREV"
- case _ => throw new ArgotConversionException("Option %s: must be either n3, turtle or rdfxml" format (opt.name, sValue))
+ val rdfLanguage = parser.option[Lang](List("language"), "l", "RDF language") {
+ (sValue, opt) =>
+ sValue match {
+ case "n3" => N3
+ case "turtle" => TURTLE
+ case "rdfxml" => RDFXML
+ case _ => throw new ArgotConversionException("Option %s: must be either n3, turtle or rdfxml" format (opt.name, sValue))
}
}
val httpPort = parser.option[Int]("http", "Port","start the http server on port")
val httpsPort = parser.option[Int]("https","port","start the https server on port")
- val rootDirectory = parser.parameter[File]("rootDirectory", "root directory", false) {
- (sValue, opt) => {
- val file = new File(sValue)
- if (! file.exists)
- throw new ArgotConversionException("Option %s: %s must be a valid path" format (opt.name, sValue))
- else
- file
+ val rootDirectory = parser.parameter[File]("rootDirectory", "root directory", false) {
+ (sValue, opt) => {
+ val file = new File(sValue)
+ if (! file.exists)
+ throw new ArgotConversionException("Option %s: %s must be a valid path" format (opt.name, sValue))
+ else
+ file
}
- }
+ }
implicit val webCache = new WebCache()
- val baseURL = parser.parameter[String]("baseURL", "base URL", false)
+ val baseURL = parser.parameter[String]("baseURL", "base URL", false)
// regular Java main
def main(args: Array[String]) {
try {
- parser.parse(args)
- } catch {
+ parser.parse(args)
+ } catch {
case e: ArgotUsageException => err.println(e.message); sys.exit(1)
}
val filesystem =
- new Filesystem(
- rootDirectory.value.get,
- baseURL.value.get,
- lang=rdfLanguage.value getOrElse "N3")(mode.value getOrElse ResourcesDontExistByDefault)
-
+ new Filesystem(
+ rootDirectory.value.get,
+ baseURL.value.get,
+ lang=rdfLanguage.value getOrElse RDFXML)(mode.value getOrElse ResourcesDontExistByDefault)
+
val app = new ReadWriteWeb(filesystem, new RDFAuthZ(webCache,filesystem))
//this is incomplete: we should be able to start both ports.... not sure how to do this yet.
@@ -92,11 +92,11 @@
// configures and launches a Jetty server
service.filter(new FilterLogger(logger)).
context("/public"){ ctx:ContextBuilder =>
- ctx.resources(ClasspathUtils.fromClasspath("public/").toURI.toURL)
+ ctx.resources(ClasspathUtils.fromClasspath("public/").toURI.toURL)
}.
filter(app.plan).
filter(new X509view().plan).run()
-
+
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/Representation.scala Sun Oct 16 22:47:37 2011 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb
+
+import unfiltered.request._
+import java.net.URL
+
+sealed trait Representation
+
+object Representation {
+
+ def fromSuffix(suffix: String): Representation = {
+ suffix match {
+ case "n3" => RDFRepr(N3)
+ case "turtle" | "ttl" => RDFRepr(TURTLE)
+ case "rdf" => RDFRepr(RDFXML)
+ case "htm" | "html" | "xhtml" => HTMLRepr
+ case "/" => DirectoryRepr
+ case _ => UnknownRepr
+ }
+ }
+
+
+ val htmlContentTypes = Set("text/html", "application/xhtml+xml")
+
+ def acceptsHTML(ct: Iterable[String]) =
+ ! (htmlContentTypes & ct.toSet).isEmpty
+
+ def fromAcceptedContentTypes(ct: Iterable[String]): Representation = {
+ Lang(ct) map RDFRepr.apply getOrElse {
+ if (acceptsHTML(ct))
+ HTMLRepr
+ else
+ UnknownRepr
+ }
+ }
+
+ /** implements http://www.w3.org/2001/tag/doc/metaDataInURI-31 and http://www.w3.org/2001/tag/doc/mime-respect
+ *
+ * if there is no known suffix (eg. the URI was already the authoritative one),
+ * inspects the given accepted content types
+ *
+ * This knows only about the RDF and HTML charsets
+ */
+ def apply(
+ suffixOpt: Option[String],
+ ct: Iterable[String]): Representation = {
+ suffixOpt map fromSuffix match {
+ case None | Some(UnknownRepr) => fromAcceptedContentTypes(ct)
+ case Some(repr) => repr
+ }
+ }
+}
+
+case class RDFRepr(lang: Lang) extends Representation
+case object HTMLRepr extends Representation
+case object DirectoryRepr extends Representation
+case object UnknownRepr extends Representation
--- a/src/main/scala/RequestLang.scala Sun Oct 16 21:38:18 2011 +0200
+++ b/src/main/scala/RequestLang.scala Sun Oct 16 22:47:37 2011 +0200
@@ -1,3 +1,26 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
package org.w3.readwriteweb
import unfiltered.request._
--- a/src/main/scala/Resource.scala Sun Oct 16 21:38:18 2011 +0200
+++ b/src/main/scala/Resource.scala Sun Oct 16 22:47:37 2011 +0200
@@ -16,5 +16,6 @@
trait Resource {
def get(): Validation[Throwable, Model]
def save(model: Model): Validation[Throwable, Unit]
+ def createDirectory(model: Model): Validation[Throwable, Unit]
}
--- a/src/main/scala/WebCache.scala Sun Oct 16 21:38:18 2011 +0200
+++ b/src/main/scala/WebCache.scala Sun Oct 16 22:47:37 2011 +0200
@@ -74,6 +74,10 @@
}
- def save(model: Model) = { throw new MethodNotSupportedException("not implemented"); null }
+ // when fetching information from the web creating directories does not make sense
+ //perhaps the resource manager should be split into read/write sections?
+ def save(model: Model) = throw new MethodNotSupportedException("not implemented")
+
+ def createDirectory(model: Model) = throw new MethodNotSupportedException("not implemented")
}
}
--- a/src/main/scala/plan.scala Sun Oct 16 21:38:18 2011 +0200
+++ b/src/main/scala/plan.scala Sun Oct 16 22:47:37 2011 +0200
@@ -21,15 +21,18 @@
import scalaz._
-class ReadWriteWeb(rm: ResourceManager, implicit val authz: AuthZ = NullAuthZ) {
+//object ReadWriteWeb {
+//
+// val defaultHandler: PartialFunction[Throwable, HttpResponse[_]] = {
+// case t => InternalServerError ~> ResponseString(t.getStackTraceString)
+// }
+//
+//}
+
+class ReadWriteWeb(rm: ResourceManager, implicit val authz: AuthZ = NullAuthZ) {
val logger: Logger = LoggerFactory.getLogger(this.getClass)
- def isHTML(accepts: List[String]): Boolean = {
- val accept = accepts.headOption
- accept == Some("text/html") || accept == Some("application/xhtml+xml")
- }
-
/** I believe some documentation is needed here, as many different tricks
* are used to make this code easy to read and still type-safe
*
@@ -58,7 +61,7 @@
val Authoritative(uri, representation) = req
val r: Resource = rm.resource(uri)
req match {
- case GET(_) & Accept(accepts) if isHTML(accepts) => {
+ case GET(_) if representation == HTMLRepr => {
val source = Source.fromFile("src/main/resources/skin.html")("UTF-8")
val body = source.getLines.mkString("\n")
Ok ~> ViaSPARQL ~> ContentType("text/html") ~> ResponseString(body)
@@ -76,6 +79,12 @@
case HEAD(_) => Ok ~> ViaSPARQL ~> ContentType(lang.contentType)
}
}
+ case PUT(_) & RequestLang(lang) if representation == DirectoryRepr => {
+ for {
+ bodyModel <- modelFromInputStream(Body.stream(req), uri, lang) failMap { t => BadRequest ~> ResponseString(t.getStackTraceString) }
+ _ <- r.createDirectory(bodyModel) failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString) }
+ } yield Created
+ }
case PUT(_) & RequestLang(lang) =>
for {
bodyModel <- modelFromInputStream(Body.stream(req), uri, lang) failMap { t => BadRequest ~> ResponseString(t.getStackTraceString) }
--- a/src/test/scala/CreateContentSpecs.scala Sun Oct 16 21:38:18 2011 +0200
+++ b/src/test/scala/CreateContentSpecs.scala Sun Oct 16 22:47:37 2011 +0200
@@ -5,7 +5,7 @@
import dispatch._
-object PutRDFXMLSpec extends FilesystemBased with SomeRDF with SomeURI {
+object PutRDFXMLSpec extends SomePeopleDirectory {
"PUTing an RDF document on Joe's URI (which does not exist yet)" should {
"return a 201" in {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/scala/CreateDirectorySpec.scala Sun Oct 16 22:47:37 2011 +0200
@@ -0,0 +1,20 @@
+package org.w3.readwriteweb
+
+import org.w3.readwriteweb.util._
+import org.w3.readwriteweb.utiltest._
+
+import dispatch._
+
+object CreateDirSpec extends FilesystemBased with SomeRDF with SomeURI {
+
+ "PUTing an RDF document on /people/" should {
+ "return a 201" in {
+ val httpCode = Http(dirUri.put(RDFXML, rdfxml) get_statusCode)
+ httpCode must_== 201
+ }
+ "create a directory on disk" in {
+ directory must be directory
+ }
+ }
+
+}
--- a/src/test/scala/ReadWriteWebSpecs.scala Sun Oct 16 21:38:18 2011 +0200
+++ b/src/test/scala/ReadWriteWebSpecs.scala Sun Oct 16 22:47:37 2011 +0200
@@ -7,6 +7,8 @@
// access content
GetStrictModeSpec, GetWikiModeSpec,
ContentNegociationSpec,
+ // create directory
+ CreateDirSpec,
// create content
PutRDFXMLSpec, PostRDFSpec,
PutInvalidRDFXMLSpec, PostOnNonExistingResourceSpec,
--- a/src/test/scala/util/specs.scala Sun Oct 16 21:38:18 2011 +0200
+++ b/src/test/scala/util/specs.scala Sun Oct 16 22:47:37 2011 +0200
@@ -31,13 +31,13 @@
lazy val mode: RWWMode = ResourcesDontExistByDefault
- lazy val language = "RDF/XML-ABBREV"
+ lazy val lang = RDFXML
- lazy val baseURL = "/2007/wiki"
+ lazy val baseURL = "/wiki"
lazy val root = new File(new File(System.getProperty("java.io.tmpdir")), "readwriteweb")
- lazy val resourceManager = new Filesystem(root, baseURL, language)(mode)
+ lazy val resourceManager = new Filesystem(root, baseURL, lang)(mode)
doBeforeSpec {
if (root.exists) root.deleteRecursively()
@@ -70,15 +70,28 @@
val emptyModel = com.hp.hpl.jena.rdf.model.ModelFactory.createDefaultModel()
- lazy val uri = host / "2007/wiki/people/JoeLambda"
+ lazy val dirUri = host / "wiki/people/"
+
+ lazy val uri = host / "wiki/people/JoeLambda"
lazy val uriBase = baseURI(uri)
+ lazy val directory = new File(root, "people")
+
lazy val resourceOnDisk = new File(root, "people/JoeLambda")
}
-trait SomeDataInStore extends FilesystemBased with SomeRDF with SomeURI {
+trait SomePeopleDirectory extends SomeRDF with SomeURI {
+
+ doBeforeSpec {
+ val httpCode = Http(dirUri.put(RDFXML, rdfxml) get_statusCode)
+ httpCode must_== 201
+ }
+
+}
+
+trait SomeDataInStore extends SomePeopleDirectory {
doBeforeSpec {
val httpCode = Http(uri.put(RDFXML, rdfxml) get_statusCode)