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)
{