applied Alexandre Bertails' "~ refactoring + abstraction for asked resources, based on URI extension and Accept headers". The nice thing is that now the n3 example are returned for those who are authenticated and authorizaed as n3. It used to be returned as rdf/xml
--- a/src/main/scala/AcceptLang.scala Sun Oct 16 21:13:38 2011 +0200
+++ /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 Sun Oct 16 21:38:18 2011 +0200
@@ -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 Sun Oct 16 21:13:38 2011 +0200
+++ b/src/main/scala/Lang.scala Sun Oct 16 21:38:18 2011 +0200
@@ -57,14 +57,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 Sun Oct 16 21:13:38 2011 +0200
+++ b/src/main/scala/Post.scala Sun Oct 16 21:38:18 2011 +0200
@@ -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 Sun Oct 16 21:38:18 2011 +0200
@@ -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/WebCache.scala Sun Oct 16 21:13:38 2011 +0200
+++ b/src/main/scala/WebCache.scala Sun Oct 16 21:38:18 2011 +0200
@@ -66,7 +66,7 @@
case Some(loc) => new URL(u,loc)
case None => new URL(u.getProtocol,u.getAuthority,u.getPort,u.getPath)
}
- res>>{ in=>modelFromInputStream(in,loc.toString,encoding) }
+ res>>{ in=>modelFromInputStream(in,loc,encoding) }
}
})
--- a/src/main/scala/plan.scala Sun Oct 16 21:13:38 2011 +0200
+++ b/src/main/scala/plan.scala Sun Oct 16 21:38:18 2011 +0200
@@ -55,8 +55,8 @@
val plan = unfiltered.filter.Planify {
authz.protect {
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")
@@ -66,22 +66,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)
@@ -106,7 +109,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 {
@@ -118,11 +121,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 Sun Oct 16 21:13:38 2011 +0200
+++ b/src/main/scala/util/FilterLogger.scala Sun Oct 16 21:38:18 2011 +0200
@@ -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 Sun Oct 16 21:38:18 2011 +0200
@@ -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 Sun Oct 16 21:38:18 2011 +0200
@@ -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 Sun Oct 16 21:38:18 2011 +0200
@@ -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")
--- a/src/main/scala/util/package.scala Sun Oct 16 21:13:38 2011 +0200
+++ b/src/main/scala/util/package.scala Sun Oct 16 21:38:18 2011 +0200
@@ -2,46 +2,21 @@
import java.io._
import com.hp.hpl.jena.rdf.model._
-import com.hp.hpl.jena.query._
-import unfiltered.response._
import scalaz._
import Scalaz._
+import java.net.URL
package object util {
- val defaultLang = "RDF/XML-ABBREV"
-
- class MSAuthorVia(value: String) extends ResponseHeader("MS-Author-Via", List(value))
-
- object ViaSPARQL extends MSAuthorVia("SPARQL")
-
- object ResponseModel {
- def apply(model: Model, base: String, lang: Lang): ResponseStreamer =
- new ResponseStreamer {
- def stream(os: OutputStream): Unit =
- model.getWriter(lang.jenaLang).write(model, os, base)
- }
- }
-
- 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)
- }
- }
def modelFromInputStream(
is: InputStream,
- base: String,
+ base: URL,
lang: Lang): Validation[Throwable, Model] =
try {
val m = ModelFactory.createDefaultModel()
- m.getReader(lang.jenaLang).read(m, is, base)
+ m.getReader(lang.jenaLang).read(m, is, base.toString)
m.success
} catch {
case t => t.fail
@@ -49,12 +24,12 @@
def modelFromString(
s: String,
- base: String,
+ base: URL,
lang: Lang): Validation[Throwable, Model] =
try {
val reader = new StringReader(s)
val m = ModelFactory.createDefaultModel()
- m.getReader(lang.jenaLang).read(m, reader, base)
+ m.getReader(lang.jenaLang).read(m, reader, base.toString)
m.success
} catch {
case t => t.fail