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 webid
authorHenry Story <henry.story@bblfish.net>
Sun, 16 Oct 2011 21:38:18 +0200
branchwebid
changeset 82 42e553469cef
parent 81 fed900642d29 (current diff)
parent 70 1a34982ea440 (diff)
child 83 642d8a1b35d5
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
src/main/scala/AcceptLang.scala
src/main/scala/Lang.scala
src/main/scala/WebCache.scala
src/main/scala/plan.scala
src/main/scala/util/package.scala
--- 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