You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2013/08/14 14:46:40 UTC

svn commit: r1513851 - in /jena/trunk/jena-arq/src: main/java/org/apache/jena/atlas/web/AcceptList.java main/java/org/apache/jena/atlas/web/MediaRange.java test/java/org/apache/jena/atlas/web/TestContentNegotiation.java

Author: andy
Date: Wed Aug 14 12:46:40 2013
New Revision: 1513851

URL: http://svn.apache.org/r1513851
Log:
JENA-510 : Rewrite content negiotiation code; remove ability to offer ranges (does not make sense).
Check tests and make all valid; add tests for specific common usages.

Modified:
    jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/AcceptList.java
    jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/MediaRange.java
    jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/web/TestContentNegotiation.java

Modified: jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/AcceptList.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/AcceptList.java?rev=1513851&r1=1513850&r2=1513851&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/AcceptList.java (original)
+++ jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/AcceptList.java Wed Aug 14 12:46:40 2013
@@ -21,8 +21,6 @@ package org.apache.jena.atlas.web;
 import java.util.* ;
 
 import org.apache.jena.atlas.logging.Log ;
-import org.apache.jena.atlas.web.MediaRange ;
-import org.apache.jena.atlas.web.MediaType ;
 
 public class AcceptList
 {
@@ -106,39 +104,50 @@ public class AcceptList
 
     private final static MediaRangeCompare comparator = new MediaRangeCompare() ;
     
-    /** Find and return a match for a MediaRange */
-    public MediaRange match(MediaRange aItem)
-    {
-        // Normally aItem is an offer - a concrete media type.
-//        ensureSorted() ;
+    /** Find and return a match for a specific MediaType. 
+     * Returns the Accept header entry best matched or null.
+     */
+    public MediaRange match(MediaType offer) {
+        // "this" is the client proposal list (Accept header)
+        // aItem is one item of the server offer list - a concrete media type (no "*")
+
         // Search all, find best by specifivity, "q"(quality), and then first occurring if otherwise equal.
         
         MediaRange choice = null ;
+        double weight = -1 ;
+        int exact = -1 ;
         
         for ( MediaRange acceptItem : ranges )
         {
-            if ( acceptItem.accepts(aItem) )
+            if ( acceptItem.accepts(offer) )
             {
-                // Return the more grounded term
-                // E.g. aItem = text/plain ; acceptItem = text/*
+                boolean newChoice = false; 
+                if ( choice == null ) 
+                    // First possibility.
+                    newChoice = true ;
+                else if ( weight < acceptItem.get_q() )
+                    // New possibility has greater weight
+                    newChoice = true ;
+                else if ( weight == acceptItem.get_q() && exact < acceptItem.subweight() ) 
+                    // New possibility has same weight but better exactness.
+                    newChoice = true ;
                 
-                if ( choice != null && choice.get_q() >= acceptItem.get_q() )
-                    continue ;
-                // Return the more grounded term
-                // E.g. aItem = text/plain ; acceptItem = text/*
-                // This looses any q
-                if ( aItem.moreGroundedThan(acceptItem) )
+                if ( newChoice )
                 {
-                    // Clone/change.
-                    acceptItem = new MediaRange(aItem.getType(), aItem.getSubType(), acceptItem.getCharset()) ;
+                    choice = acceptItem ;
+                    weight = acceptItem.get_q() ;
+                    exact = acceptItem.subweight() ;
+                    continue ;
                 }
-                choice = acceptItem ;
+                //if ( weight == acceptItem.get_q() && !exact &&  
             }
         }
+        if ( choice == null )
+            return null ;
         return choice ;
     }
- 
-    /** Find the best thing in offer list with the proposal 
+
+    /** Find the best thing in offer list 8sever side) matching the proposal (client, Accept header). 
      *  "best" means highest q value, with left most being better for same q.
      * 
      * @param proposalList Client list of possibilities
@@ -148,18 +157,33 @@ public class AcceptList
     
     static public MediaType match(AcceptList proposalList, AcceptList offerList)
     {
-        MediaRange choice = null ;  // From offerlist
-        
+        MediaRange cause = null ;
+        MediaRange choice = null ;  // From the proposalList
+        double weight = -1 ;
+        int exactness = -1 ;
+
         for ( MediaRange offer : offerList.entries() )
         {
             MediaRange m = proposalList.match(offer) ;
-            if ( m != null )
-            {
-                if ( choice != null && choice.get_q() >= m.get_q() )
-                    continue ; 
-                choice = m ;  
+            if ( m == null )
+                continue ;
+            boolean newChoice = false ;
+            
+            if ( choice == null )
+                newChoice = true ;
+            else if ( weight < m.get_q() )
+                newChoice = true ;
+            else if ( weight == m.get_q() && ( exactness < m.subweight() ) )
+                newChoice = true ;
+            
+            if ( newChoice ) {
+                choice = offer ;
+                weight = m.get_q() ;
+                exactness = m.subweight() ;
             }
         }
+        
+        
         if ( choice == null )
             return null ;
         return new MediaType(choice);

Modified: jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/MediaRange.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/MediaRange.java?rev=1513851&r1=1513850&r2=1513851&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/MediaRange.java (original)
+++ jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/MediaRange.java Wed Aug 14 12:46:40 2013
@@ -96,6 +96,10 @@ public class MediaRange extends MediaTyp
         return a.equals(b) ;
     }
 
+    public boolean grounded(MediaType item) {
+        return ! isStar(item.getType()) && ! isStar(item.getSubType()) ;
+    }
+    
     // Strictly more grounded than
     public boolean moreGroundedThan(MediaType item)
     {
@@ -106,6 +110,18 @@ public class MediaRange extends MediaTyp
         return false ;
     }
     
+    // Waeighting for "exactness"
+    // 3 for grounded, 2 for foo/*, 1 for */foo and 0 for */*  
+    int subweight() {
+        int x = 0 ;
+        if ( !isStar(getType()))
+            x += 2 ;
+        if ( !isStar(getSubType()))
+            x += 1 ;
+        return x ; 
+    }
+    
+    
     private boolean isStar(String x)
     {
         return x == null || x.equals("*") ;

Modified: jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/web/TestContentNegotiation.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/web/TestContentNegotiation.java?rev=1513851&r1=1513850&r2=1513851&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/web/TestContentNegotiation.java (original)
+++ jena/trunk/jena-arq/src/test/java/org/apache/jena/atlas/web/TestContentNegotiation.java Wed Aug 14 12:46:40 2013
@@ -46,103 +46,116 @@ public class TestContentNegotiation exte
     { testMatch("application/xml", "text/plain", null) ; }
     
     @Test public void simpleNeg3()
-    { testMatch("text/*", "text/*", "text/*") ; }
+    { testMatch("text/*", "text/plain", "text/plain") ; }
     
-    @Test public void simpleNeg4()
-    { testMatch("text/xml", "text/*", "text/xml") ; }
+    @Test public void listNeg1()
+    { testMatch("text/xml,text/*", "text/xml", "text/xml") ; }
     
-    @Test public void simpleNeg5()
-    { testMatch("text/*", "text/xml", "text/xml") ; }
+    @Test public void listNeg2()
+    { testMatch("text/xml,text/*", "text/plain,text/xml", "text/xml") ; }
     
-    @Test public void listItemNeg1()
-    { testMatch("text/xml,text/*", "text/*", "text/xml") ; }
-    
-    @Test public void listListNeg1()
-    { testMatch("text/xml,text/*", "text/plain,text/*", "text/plain") ; }
-    
-    @Test public void listListNeg2()
-    { testMatch("text/xml,text/*", "text/*,text/plain", "text/xml") ; }
+    @Test public void listNeg3()
+    { testMatch("text/xml,text/*", "text/plain", "text/plain") ; }
+
+    @Test public void qualNeg1() { 
+        testMatch("text/xml;q=0.5,text/plain",
+                  "text/plain",
+                  "text/plain") ; }
     
-    @Test public void qualNeg1() { testMatch("text/xml;q=0.5,text/plain", "text/*", "text/plain") ; }
+    @Test public void qualNeg2() {
+        testMatch(
+                "text/turtle,application/rdf+xml;q=0.5",
+                "application/rdf+xml,text/turtle" , 
+                "text/turtle") ;
+    }
     
-    @Test public void qualNeg2()
-    {
+    @Test public void qualNeg3() {
         testMatch(
-                "application/n3,application/rdf+xml;q=0.5",
-                "application/rdf+xml,application/n3" , 
-                "application/n3") ;
+                "text/turtle,application/rdf+xml;q=0.5",
+                "text/turtle,application/rdf+xml" , 
+                "text/turtle") ;
     }
     
-    @Test public void qualNeg3()
+    @Test public void qualNeg4()    
     {
         testMatch(
-                "application/rdf+xml;q=0.5 , application/n3",
-                "application/n3,application/rdf+xml" , 
-                "application/n3") ;
+                  "application/rdf+xml;q=0.5,text/turtle",
+                  "text/turtle,application/rdf+xml" , 
+                  "text/turtle") ;
     }
     
-    @Test public void qualNeg4()
+    @Test public void qualNeg5()    
     {
         testMatch(
-                "application/rdf+xml;q=0.5 , application/n3",
-                "application/rdf+xml , application/n3" , 
-                "application/n3") ;
+                  "application/rdf+xml;q=0.5,text/turtle",
+                  ",application/rdf+xml,text/turtle" , 
+                  "text/turtle") ;
     }
 
+    // Content negotiations Jena/Fuseki tend to use.
+    // See DEF.rsOffer and DEF.rdfOffer in Fuseki.
+    // See WebContent.defaultGraphAcceptHeader, defaultDatasetAcceptHeader, defaultRDFAcceptHeader
+    
+    private static final String offerResultSet = "application/sparql-results+xml, application/sparql-results+json, text/csv , text/tab-separated-values, text/plain" ;
+    private static final String offerRDF = "text/turtle, application/turtle, application/x-turtle,  application/n-triples, text/plain, application/rdf+xml, application/rdf+json" ;
+    
     // SPARQL: result set
-    @Test public void qualNeg5()
+    @Test public void connegResultSet_01()
     {
         testMatch(
                 "application/sparql-results+json , application/sparql-results+xml;q=0.9 , application/rdf+xml , application/turtle;q=0.9 , */*;q=0.1",
-                "application/sparql-results+xml, application/sparql-results+json, text/csv , text/tab-separated-values, text/plain",
+                offerResultSet,
                 "application/sparql-results+json") ;
     }
     
-    // SPARQL: result set
-    @Test public void qualNeg5a()
+    @Test public void connegResultSet_02()
     {
         testMatch(
-                "application/sparql-results+json , application/sparql-results+xml;q=0.9 , application/rdf+xml , application/turtle;q=0.9 , */*;q=0.1",
-                "application/sparql-results+json, application/sparql-results+xml, text/csv , text/tab-separated-values, text/plain",
-                "application/sparql-results+json") ;
+                "application/sparql-results+xml;q=0.9, */*;q=0.1",
+                offerResultSet,
+                "application/sparql-results+xml") ;
     }
     
-    // SPARQL: RDF
-    @Test public void qualNeg6()
+//    conneg("application/sparql-results+xml;q=0.9, */*;q=0.1", DEF.rsOffer) ;
+//    conneg("application/sparql-results+json;q=0.9, */*;q=0.1", DEF.rsOffer) ;
+    
+    @Test public void connegResultSet_03()
     {
         testMatch(
-                "application/sparql-results+json , application/sparql-results+xml;q=0.9 , application/rdf+xml , application/turtle;q=0.9 , */*;q=0.1",
-                "application/rdf+xml , application/turtle , application/x-turtle ,  text/turtle , text/plain  application/n-triples",
-                "application/rdf+xml") ;
+                "application/sparql-results+json;q=0.9, */*;q=0.1",
+                offerResultSet,
+                "application/sparql-results+json") ;
+    }
+
+    // SPARQL - all
+    @Test public void conneg_01()
+    {
+        testMatch(
+                  // SPARQL -- ask for either.
+                "application/sparql-results+json , application/sparql-results+xml;q=0.9 , text/turtle, application/rdf+xml;q=0.9 , */*;q=0.1",
+                offerRDF,
+                "text/turtle") ;
     }
     
-    // HTTP: RDF
-    @Test public void qualNeg7()
+
+    @Test public void connegRDF_01()
     {
         testMatch(
-                "application/rdf+xml , application/turtle;q=0.9 , */*;q=0.1",
-                "application/rdf+xml , application/turtle , application/x-turtle ,  text/turtle , text/plain  application/n-triples",
+                "application/rdf+xml , text/turtle;q=0.9 , */*;q=0.1",
+                offerRDF, 
                 "application/rdf+xml") ;
     }
     
-    // HTTP: RDF
-    @Test public void qualNeg8()
+    @Test public void connegRDF_02()
     {
         testMatch(
                 "application/turtle;q=0.9 , application/rdf+xml , */*;q=0.1",
-                "application/rdf+xml , application/turtle , application/x-turtle ,  text/turtle , text/plain  application/n-triples",
+                offerRDF,
                 "application/rdf+xml") ;
     }
     
-    // TODO Standard headers from clients of RDf and for SPARQL results
-    
-    // RDF:
-    //  Accept: application/rdf+xml , application/turtle;q=0.9 , */*;q=0.1
-    //  Offer: application/rdf+xml , application/turtle , application/x-turtle ,  text/turtle , text/plain  application/n-triples
-    
-    // SPARQL:
-    //  Accept: application/sparql-results+json , application/sparql-results+xml;q=0.9 , application/rdf+xml , application/turtle;q=0.9 , */*;q=0.1
-    //  Offer:  application/sparql-results+xml, application/sparql-results+json, text/csv , text/tab-separated-values, text/plain
+    // HTTP: RDF
+    //See WebContent.defaultGraphAcceptHeader, defaultDatasetAcceptHeader, defaultRDFAcceptHeader
     
     private void testMatch(String header, String offer, String result)
     {