~ refactoring + abstraction for asked resources, based on URI extension and Accept headers
--- a/src/main/scala/AcceptLang.scala Sat Oct 15 16:47:37 2011 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-package org.w3.readwriteweb
-
-import unfiltered.request._
-
-object AcceptLang {
-
- def unapply(req: HttpRequest[_]): Option[Lang] =
- Accept(req) map Lang.apply collectFirst { case Some(lang) => lang }
-
- def apply(req: HttpRequest[_]): Option[Lang] =
- unapply(req)
-
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/Authoritative.scala Sat Oct 15 18:28:35 2011 -0400
@@ -0,0 +1,68 @@
+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
+
+ def unapply(req: HttpRequest[javax.servlet.http.HttpServletRequest]): Option[(URL, Representation)] = {
+ val uri = req.underlying.getRequestURL.toString
+ val suffixOpt = uri match {
+ case r(_, suffix) => Some(suffix)
+ case _ => None
+ }
+ Some((new URL(uri), Representation(suffixOpt, Accept(req))))
+ }
+}
--- a/src/main/scala/Lang.scala Sat Oct 15 16:47:37 2011 -0400
+++ b/src/main/scala/Lang.scala Sat Oct 15 18:28:35 2011 -0400
@@ -34,14 +34,8 @@
case _ => None
}
- def unapply(contentType: String): Option[Lang] =
- apply(contentType)
-
- def apply(req: HttpRequest[_]): Option[Lang] =
- RequestContentType(req) flatMap Lang.apply
-
- def unapply(req: HttpRequest[_]): Option[Lang] =
- apply(req)
+ def apply(cts: Iterable[String]): Option[Lang] =
+ cts map Lang.apply collectFirst { case Some(lang) => lang }
}
--- a/src/main/scala/Post.scala Sat Oct 15 16:47:37 2011 -0400
+++ b/src/main/scala/Post.scala Sat Oct 15 18:28:35 2011 -0400
@@ -68,7 +68,7 @@
contentType match {
case SPARQL => postUpdate | (postQuery | PostUnknown)
- case Lang(lang) => postRDF(lang) | PostUnknown
+ case RequestLang(lang) => postRDF(lang) | PostUnknown
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/RequestLang.scala Sat Oct 15 18:28:35 2011 -0400
@@ -0,0 +1,16 @@
+package org.w3.readwriteweb
+
+import unfiltered.request._
+
+object RequestLang {
+
+ def apply(req: HttpRequest[_]): Option[Lang] =
+ Lang(RequestContentType(req))
+
+ def unapply(req: HttpRequest[_]): Option[Lang] =
+ apply(req)
+
+ def unapply(ct: String): Option[Lang] =
+ Lang(ct)
+
+}
--- a/src/main/scala/plan.scala Sat Oct 15 16:47:37 2011 -0400
+++ b/src/main/scala/plan.scala Sat Oct 15 18:28:35 2011 -0400
@@ -54,8 +54,8 @@
*/
val plan = unfiltered.filter.Planify {
case req @ Path(path) if path startsWith rm.basePath => {
- val Authoritative(baseURI, _) = req
- val r: Resource = rm.resource(baseURI)
+ val Authoritative(uri, representation) = req
+ val r: Resource = rm.resource(uri)
req match {
case GET(_) & Accept(accepts) if isHTML(accepts) => {
val source = Source.fromFile("src/main/resources/skin.html")("UTF-8")
@@ -65,22 +65,25 @@
case GET(_) | HEAD(_) =>
for {
model <- r.get() failMap { x => NotFound }
- lang = AcceptLang(req) getOrElse Lang.default
+ lang = representation match {
+ case RDFRepr(l) => l
+ case _ => Lang.default
+ }
} yield {
req match {
- case GET(_) => Ok ~> ViaSPARQL ~> ContentType(lang.contentType) ~> ResponseModel(model, baseURI, lang)
+ case GET(_) => Ok ~> ViaSPARQL ~> ContentType(lang.contentType) ~> ResponseModel(model, uri, lang)
case HEAD(_) => Ok ~> ViaSPARQL ~> ContentType(lang.contentType)
}
}
- case PUT(_) & Lang(lang) =>
+ case PUT(_) & RequestLang(lang) =>
for {
- bodyModel <- modelFromInputStream(Body.stream(req), baseURI, lang) failMap { t => BadRequest ~> ResponseString(t.getStackTraceString) }
+ bodyModel <- modelFromInputStream(Body.stream(req), uri, lang) failMap { t => BadRequest ~> ResponseString(t.getStackTraceString) }
_ <- r.save(bodyModel) failMap { t => InternalServerError ~> ResponseString(t.getStackTraceString) }
} yield Created
case PUT(_) =>
BadRequest ~> ResponseString("Content-Type MUST be one of: " + Lang.supportedAsString)
case POST(_) & RequestContentType(ct) if Post.supportContentTypes contains ct => {
- Post.parse(Body.stream(req), baseURI, ct) match {
+ Post.parse(Body.stream(req), uri, ct) match {
case PostUnknown => {
logger.info("Couldn't parse the request")
BadRequest ~> ResponseString("You MUST provide valid content for given Content-Type: " + ct)
@@ -105,7 +108,7 @@
}
case PostQuery(query) => {
logger.info("SPARQL Query:\n" + query.toString())
- lazy val lang = Lang(req) getOrElse Lang.default
+ lazy val lang = RequestLang(req) getOrElse Lang.default
for {
model <- r.get() failMap { t => NotFound }
} yield {
@@ -117,11 +120,11 @@
Ok ~> ContentType("application/sparql-results+xml") ~> ResponseResultSet(qe.execAsk())
case CONSTRUCT => {
val result: Model = qe.execConstruct()
- Ok ~> ContentType(lang.contentType) ~> ResponseModel(model, baseURI, lang)
+ Ok ~> ContentType(lang.contentType) ~> ResponseModel(model, uri, lang)
}
case DESCRIBE => {
val result: Model = qe.execDescribe()
- Ok ~> ContentType(lang.contentType) ~> ResponseModel(model, baseURI, lang)
+ Ok ~> ContentType(lang.contentType) ~> ResponseModel(model, uri, lang)
}
}
}
--- a/src/main/scala/util/FilterLogger.scala Sat Oct 15 16:47:37 2011 -0400
+++ b/src/main/scala/util/FilterLogger.scala Sat Oct 15 18:28:35 2011 -0400
@@ -13,9 +13,9 @@
def destroy(): Unit = ()
def doFilter(
- request: ServletRequest,
- response: ServletResponse,
- chain: FilterChain): Unit = {
+ request: ServletRequest,
+ response: ServletResponse,
+ chain: FilterChain): Unit = {
val r: HttpServletRequest = request.asInstanceOf[HttpServletRequest]
val method = r.getMethod
val uri = r.getRequestURI
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/util/ResponseModel.scala Sat Oct 15 18:28:35 2011 -0400
@@ -0,0 +1,15 @@
+package org.w3.readwriteweb
+
+import java.io._
+import java.net.URL
+
+import com.hp.hpl.jena.rdf.model._
+import unfiltered.response._
+
+object ResponseModel {
+ def apply(model: Model, base: URL, lang: Lang): ResponseStreamer =
+ new ResponseStreamer {
+ def stream(os: OutputStream): Unit =
+ model.getWriter(lang.jenaLang).write(model, os, base.toString)
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/util/ResponseResultSet.scala Sat Oct 15 18:28:35 2011 -0400
@@ -0,0 +1,23 @@
+package org.w3.readwriteweb
+
+import java.io._
+import com.hp.hpl.jena.rdf.model._
+import com.hp.hpl.jena.query._
+import unfiltered.response._
+import scalaz._
+import Scalaz._
+
+object ResponseResultSet {
+
+ def apply(rs: ResultSet): ResponseStreamer =
+ new ResponseStreamer {
+ def stream(os: OutputStream): Unit = ResultSetFormatter.outputAsXML(os, rs)
+ }
+
+ def apply(result: Boolean): ResponseStreamer =
+ new ResponseStreamer {
+ def stream(os: OutputStream): Unit =
+ ResultSetFormatter.outputAsXML(os, result)
+ }
+
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/util/ViaSPARQL.scala Sat Oct 15 18:28:35 2011 -0400
@@ -0,0 +1,7 @@
+package org.w3.readwriteweb
+
+import unfiltered.response._
+
+class MSAuthorVia(value: String) extends ResponseHeader("MS-Author-Via", List(value))
+
+object ViaSPARQL extends MSAuthorVia("SPARQL")