Fixing content negotiation to work with Tabulator.
This commit is contained in:
parent
cc1b8a2579
commit
740553e293
3 changed files with 205 additions and 33 deletions
|
@ -81,7 +81,7 @@ public class IndividualController extends FreemarkerHttpServlet {
|
|||
|
||||
private static final String TEMPLATE_INDIVIDUAL_DEFAULT = "individual.ftl";
|
||||
private static final String TEMPLATE_HELP = "individual-help.ftl";
|
||||
|
||||
private static Map<String,Float>qsMap;
|
||||
|
||||
@Override
|
||||
protected ResponseValues processRequest(VitroRequest vreq) {
|
||||
|
@ -486,42 +486,36 @@ public class IndividualController extends FreemarkerHttpServlet {
|
|||
*/
|
||||
protected ContentType checkForLinkedDataRequest(String url, VitroRequest vreq ) {
|
||||
try {
|
||||
ContentType contentType = null;
|
||||
Matcher m;
|
||||
// Check for url param specifying format
|
||||
String formatParam = (String) vreq.getParameter("format");
|
||||
if (formatParam != null) {
|
||||
m = RDFXML_FORMAT.matcher(formatParam);
|
||||
if ( m.matches() ) {
|
||||
return new ContentType(RDFXML_MIMETYPE);
|
||||
return ContentType.RDFXML;
|
||||
}
|
||||
m = N3_FORMAT.matcher(formatParam);
|
||||
if( m.matches() ) {
|
||||
return new ContentType(N3_MIMETYPE);
|
||||
return ContentType.N3;
|
||||
}
|
||||
m = TTL_FORMAT.matcher(formatParam);
|
||||
if( m.matches() ) {
|
||||
return new ContentType(TTL_MIMETYPE);
|
||||
return ContentType.TURTLE;
|
||||
}
|
||||
}
|
||||
|
||||
//check the accept header
|
||||
String acceptHeader = vreq.getHeader("accept");
|
||||
if (acceptHeader != null) {
|
||||
List<ContentType> actualContentTypes = new ArrayList<ContentType>();
|
||||
actualContentTypes.add(new ContentType( XHTML_MIMETYPE ));
|
||||
actualContentTypes.add(new ContentType( HTML_MIMETYPE ));
|
||||
|
||||
actualContentTypes.add(new ContentType( RDFXML_MIMETYPE ));
|
||||
actualContentTypes.add(new ContentType( N3_MIMETYPE ));
|
||||
actualContentTypes.add(new ContentType( TTL_MIMETYPE ));
|
||||
|
||||
contentType = ContentType.getBestContentType(acceptHeader,actualContentTypes);
|
||||
if (contentType!=null && (
|
||||
RDFXML_MIMETYPE.equals(contentType.getMediaType()) ||
|
||||
N3_MIMETYPE.equals(contentType.getMediaType()) ||
|
||||
TTL_MIMETYPE.equals(contentType.getMediaType()) ))
|
||||
return contentType;
|
||||
if (acceptHeader != null) {
|
||||
String ctStr = ContentType.getBestContentType(
|
||||
ContentType.getTypesAndQ(acceptHeader),
|
||||
getAcceptedContentTypes());
|
||||
|
||||
if (ctStr!=null && (
|
||||
RDFXML_MIMETYPE.equals(ctStr) ||
|
||||
N3_MIMETYPE.equals(ctStr) ||
|
||||
TTL_MIMETYPE.equals(ctStr) ))
|
||||
return new ContentType(ctStr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -532,15 +526,15 @@ public class IndividualController extends FreemarkerHttpServlet {
|
|||
*/
|
||||
m = RDF_REQUEST.matcher(url);
|
||||
if( m.matches() ) {
|
||||
return new ContentType(RDFXML_MIMETYPE);
|
||||
return ContentType.RDFXML;
|
||||
}
|
||||
m = N3_REQUEST.matcher(url);
|
||||
if( m.matches() ) {
|
||||
return new ContentType(N3_MIMETYPE);
|
||||
return ContentType.N3;
|
||||
}
|
||||
m = TTL_REQUEST.matcher(url);
|
||||
if( m.matches() ) {
|
||||
return new ContentType(TTL_MIMETYPE);
|
||||
return ContentType.TURTLE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -550,10 +544,6 @@ public class IndividualController extends FreemarkerHttpServlet {
|
|||
return null;
|
||||
}
|
||||
|
||||
private ContentType getContentTypeFromString(String string) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private boolean checkForSunset(VitroRequest vreq, Individual entity) {
|
||||
|
@ -750,4 +740,21 @@ public class IndividualController extends FreemarkerHttpServlet {
|
|||
return new TemplateResponseValues(Template.TITLED_ERROR_MESSAGE.toString(), body);
|
||||
}
|
||||
|
||||
public static Map<String, Float> getAcceptedContentTypes() {
|
||||
if( qsMap == null ){
|
||||
HashMap<String,Float> map = new HashMap<String,Float>();
|
||||
map.put(HTML_MIMETYPE , 0.5f);
|
||||
map.put(XHTML_MIMETYPE, 0.5f);
|
||||
map.put("application/xml", 0.5f);
|
||||
map.put(RDFXML_MIMETYPE, 1.0f);
|
||||
map.put(N3_MIMETYPE, 1.0f);
|
||||
map.put(TTL_MIMETYPE, 1.0f);
|
||||
qsMap = map;
|
||||
}
|
||||
return qsMap;
|
||||
}
|
||||
|
||||
// static String getAcceptedContentType(String acceptHeader,Map<String,Float>qs){
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -16,15 +16,14 @@ package edu.cornell.mannlib.vitro.webapp.web;
|
|||
*/
|
||||
|
||||
/*
|
||||
* THIS CODE HAS BEEN MODIFIED:
|
||||
* The members of the Vitro/VIVO project have modified this code. It has
|
||||
* been modified from the version produced by Google Inc.
|
||||
*
|
||||
* The code in this file is from the Google data API project 1.40.3 on 2010-03-08.
|
||||
* See full license from gdata at bottom of this file.
|
||||
* The Vitro project only uses the method getBestContentType().
|
||||
* See full license from gdata at bottom of this file.
|
||||
*/
|
||||
|
||||
//package com.google.gdata.util;
|
||||
|
||||
//import com.google.gdata.client.Service;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -215,6 +214,26 @@ public class ContentType implements Serializable {
|
|||
*/
|
||||
public static final ContentType ANY = new ContentType("*/*").lock();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A ContetType that describes RDF/XML.
|
||||
* Added by Brian Caruso for VIVO.
|
||||
*/
|
||||
public final static ContentType RDFXML = new ContentType("application/rdf+xml").lock();
|
||||
|
||||
/**
|
||||
* A ContetType that describes N3 RDF, this is unofficial and unregistered
|
||||
* Added by Brian Caruso for VIVO.
|
||||
*/
|
||||
public final static ContentType N3 = new ContentType("text/n3").lock();
|
||||
|
||||
/**
|
||||
* A ContetType that describes turtle RDF, this is unofficial and unregistered
|
||||
* Added by Brian Caruso for VIVO.
|
||||
*/
|
||||
public final static ContentType TURTLE = new ContentType("text/turtle").lock();
|
||||
|
||||
/**
|
||||
* Determines the best "Content-Type" header to use in a servlet response
|
||||
* based on the "Accept" header from a servlet request.
|
||||
|
@ -301,6 +320,81 @@ public class ContentType implements Serializable {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the best content type based weighted q from client accept header and
|
||||
* the server weighted q of the extent that the type conveys the resource.
|
||||
*
|
||||
* From suggestions by Tim Berners-Lee at http://www.w3.org/DesignIssues/Conneg
|
||||
*
|
||||
* @param clentAcceptsTypes types the client can accept with Q weights.
|
||||
* @param serverTypes types the server can provide with Q weights.
|
||||
* @return returns content type of best match or null if no match.
|
||||
*/
|
||||
public static String getBestContentType(
|
||||
Map<String, Float> clientAcceptsTypes,
|
||||
Map<String, Float> serverTypes) {
|
||||
float maxQ = 0.0f;
|
||||
String type = null;
|
||||
for( String serverType: serverTypes.keySet()){
|
||||
float serverQ = serverTypes.get(serverType);
|
||||
Float clientQ = clientAcceptsTypes.get(serverType);
|
||||
if( clientQ != null && ((serverQ * clientQ)+ 0.001) > (maxQ + 0.001) ){
|
||||
maxQ = (serverQ * clientQ);
|
||||
type = serverType;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was added by Brian Caruso of the VIVO project. March 15 2011.
|
||||
*
|
||||
* @param acceptHeader
|
||||
* @return the types and the q values from the accept header
|
||||
*/
|
||||
public static Map<String,Float> getTypesAndQ(String acceptHeader){
|
||||
if (acceptHeader == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String,Float> qcMap = new HashMap<String,Float>();
|
||||
// iterate over all of the accepted content types
|
||||
String[] acceptedTypes = acceptHeader.split(",");
|
||||
for (String acceptedTypeString : acceptedTypes) {
|
||||
|
||||
// create the content type object
|
||||
ContentType acceptedContentType;
|
||||
try {
|
||||
acceptedContentType = new ContentType(acceptedTypeString.trim());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// ignore exception
|
||||
continue;
|
||||
}
|
||||
|
||||
// parse the "q" value (default of 1)
|
||||
float curQ = 1;
|
||||
try {
|
||||
String qAttr = acceptedContentType.getAttribute("q");
|
||||
if (qAttr != null) {
|
||||
float qValue = Float.valueOf(qAttr);
|
||||
if (qValue <= 0 || qValue > 1) {
|
||||
continue;
|
||||
}
|
||||
curQ = qValue + 0.0001F;
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
// ignore exception
|
||||
continue;
|
||||
}
|
||||
|
||||
if( acceptedContentType != null ){
|
||||
qcMap.put(acceptedContentType.getMediaType(), curQ);
|
||||
}
|
||||
}
|
||||
|
||||
return qcMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance with default media type
|
||||
*/
|
||||
|
@ -407,6 +501,8 @@ public class ContentType implements Serializable {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
private Float q=1.0f;
|
||||
|
||||
private HashMap<String, String> attributes = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
|
@ -445,6 +541,17 @@ public class ContentType implements Serializable {
|
|||
return attributes.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns q associated with content type.
|
||||
*/
|
||||
public float getQ(){
|
||||
return q;
|
||||
}
|
||||
|
||||
public void setQ(float q){
|
||||
this.q = q;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the charset attribute of the content type or null if the
|
||||
* attribute has not been set.
|
||||
|
@ -545,6 +652,7 @@ public class ContentType implements Serializable {
|
|||
return (type.hashCode() * 31 + subType.hashCode()) * 31 + attributes
|
||||
.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package edu.cornell.mannlib.vitro.webapp.web;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualController;
|
||||
|
||||
|
||||
public class ContentTypeTest {
|
||||
|
||||
@Test
|
||||
public void typeAndQTest1(){
|
||||
Map<String,Float> map = ContentType.getTypesAndQ(
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/rdf+xml;q=0.93,text/rdf+n3;q=0.5");
|
||||
Assert.assertEquals(1.0f, map.get("text/html"), 0.01f);
|
||||
Assert.assertEquals(1.0f, map.get("application/xhtml+xml"), 0.01f);
|
||||
Assert.assertEquals(0.9f, map.get("application/xml"), 0.01f);
|
||||
Assert.assertEquals(0.93f,map.get("application/rdf+xml"), 0.01f);
|
||||
Assert.assertEquals(0.5f, map.get("text/rdf+n3"), 0.01f);
|
||||
Assert.assertEquals(0.8f,map.get("*/*"), 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typeAndQTest2(){
|
||||
Map<String,Float> map = ContentType.getTypesAndQ(
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
Assert.assertEquals(1.0f, map.get("text/html"), 0.01f);
|
||||
Assert.assertEquals(1.0f, map.get("application/xhtml+xml"), 0.01f);
|
||||
Assert.assertEquals(0.9f, map.get("application/xml"), 0.01f);
|
||||
Assert.assertEquals(0.8f,map.get("*/*"), 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWeightedBestContentTypeForTabulator(){
|
||||
//accept header from tabulator
|
||||
Map<String,Float> clientAccepts = ContentType.getTypesAndQ(
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/rdf+xml;q=0.93,text/rdf+n3;q=0.5");
|
||||
|
||||
Map<String,Float> serverTypes = IndividualController.getAcceptedContentTypes();
|
||||
|
||||
Assert.assertEquals("application/rdf+xml", ContentType.getBestContentType(clientAccepts, serverTypes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWeightedBestContentTypeForFirefox(){
|
||||
//accept header from normal firefox
|
||||
Map<String,Float> clientAccepts = ContentType.getTypesAndQ(
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
|
||||
Map<String,Float> serverTypes = IndividualController.getAcceptedContentTypes();
|
||||
|
||||
Assert.assertEquals("application/xhtml+xml", ContentType.getBestContentType(clientAccepts, serverTypes));
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue