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 2022/02/20 14:51:06 UTC
[jena] branch main updated: JENA-2287: Content negotiation for success response page (for SPARQL Update)
This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new efba196 JENA-2287: Content negotiation for success response page (for SPARQL Update)
new f852ef1 Merge pull request #1201 from afs/fuseki-update-response
efba196 is described below
commit efba19666c444bbf388e02b855d8047e216dbd60
Author: Andy Seaborne <an...@apache.org>
AuthorDate: Sat Feb 19 19:27:48 2022 +0000
JENA-2287: Content negotiation for success response page (for SPARQL Update)
---
.../org/apache/jena/atlas/web/ContentType.java | 69 ++++----
.../java/org/apache/jena/atlas/web/MediaType.java | 181 ++++++++++-----------
.../java/org/apache/jena/query/QueryExecution.java | 1 -
.../apache/jena/fuseki/servlets/ServletOps.java | 71 ++++++++
4 files changed, 196 insertions(+), 126 deletions(-)
diff --git a/jena-arq/src/main/java/org/apache/jena/atlas/web/ContentType.java b/jena-arq/src/main/java/org/apache/jena/atlas/web/ContentType.java
index 6214055..6c5a320 100644
--- a/jena-arq/src/main/java/org/apache/jena/atlas/web/ContentType.java
+++ b/jena-arq/src/main/java/org/apache/jena/atlas/web/ContentType.java
@@ -18,81 +18,92 @@
package org.apache.jena.atlas.web ;
-/** A restricted view of MediaType */
-public class ContentType
-{
- private MediaType mediaType ;
- private static final String charsetParamName = "charset" ;
+import static org.apache.jena.atlas.lib.Lib.equalsIgnoreCase;
+
+import org.apache.jena.riot.web.HttpNames;
+
+/** A restricted view of MediaType: type, subtype and charset. */
+public class ContentType {
+ private MediaType mediaType;
public static ContentType create(String string) {
if ( string == null )
- return null ;
- ContentType ct = new ContentType(MediaType.create(string)) ;
- return ct ;
+ return null;
+ ContentType ct = new ContentType(MediaType.create(string));
+ return ct;
}
public static ContentType create(String ctString, String charset) {
- MediaType.ParsedMediaType x = MediaType.parse(ctString) ;
- x.params.put(charsetParamName, charset) ;
- return new ContentType(new MediaType(x)) ;
+ MediaType.ParsedMediaType x = MediaType.parse(ctString);
+ x.params.put(HttpNames.charset, charset); // Ignore params.
+ return new ContentType(new MediaType(x));
}
private ContentType(MediaType m) {
- mediaType = m ;
+ mediaType = m;
}
/**
* Get the type/subtype as a string.
+ *
* @see #toHeaderString toHeaderString for use in HTTP headers.
*/
public String getContentTypeStr() {
- return mediaType.getContentTypeStr() ;
+ return mediaType.getContentTypeStr();
}
public String getCharset() {
- return mediaType.getCharset() ;
+ return mediaType.getCharset();
}
public String getType() {
- return mediaType.getType() ;
+ return mediaType.getType();
}
public String getSubType() {
- return mediaType.getSubType() ;
+ return mediaType.getSubType();
+ }
+
+ /**
+ * Return true if the media type has same type and subtype.
+ */
+ public boolean agreesWith(MediaType mt) {
+ return equalsIgnoreCase(mediaType.getType(), mt.getType()) &&
+ equalsIgnoreCase(mediaType.getSubType(), mt.getSubType());
}
public String toHeaderString() {
- return mediaType.toHeaderString() ;
+ return mediaType.toHeaderString();
}
@Override
public int hashCode() {
- final int prime = 31 ;
- int result = 1 ;
- result = prime * result + ((mediaType == null) ? 0 : mediaType.hashCode()) ;
- return result ;
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mediaType == null) ? 0 : mediaType.hashCode());
+ return result;
}
@Override
public boolean equals(Object obj) {
if ( this == obj )
- return true ;
+ return true;
if ( obj == null )
- return false ;
+ return false;
if ( getClass() != obj.getClass() )
- return false ;
- ContentType other = (ContentType)obj ;
+ return false;
+ ContentType other = (ContentType)obj;
if ( mediaType == null ) {
if ( other.mediaType != null )
- return false ;
+ return false;
} else if ( !mediaType.equals(other.mediaType) )
- return false ;
- return true ;
+ return false;
+ return true;
}
@Override
public String toString() {
- return mediaType.toString() ;
+ return mediaType.toString();
}
}
diff --git a/jena-arq/src/main/java/org/apache/jena/atlas/web/MediaType.java b/jena-arq/src/main/java/org/apache/jena/atlas/web/MediaType.java
index 5230828..de62433 100644
--- a/jena-arq/src/main/java/org/apache/jena/atlas/web/MediaType.java
+++ b/jena-arq/src/main/java/org/apache/jena/atlas/web/MediaType.java
@@ -16,197 +16,186 @@
* limitations under the License.
*/
-package org.apache.jena.atlas.web ;
+package org.apache.jena.atlas.web;
-import static org.apache.jena.atlas.lib.Lib.hashCodeObject ;
+import static org.apache.jena.atlas.lib.Lib.hashCodeObject;
-import java.util.LinkedHashMap ;
-import java.util.Map ;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.Objects;
-import org.slf4j.Logger ;
-import org.slf4j.LoggerFactory ;
+import org.apache.jena.riot.web.HttpNames;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
- * A structure to represent a <a
- * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7">media
- * type</a>. See also the <a
- * href="http://httpd.apache.org/docs/current/content-negotiation.html">Apache
+ * A structure to represent a
+ * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7">media
+ * type</a>. See also the
+ * <a href="http://httpd.apache.org/docs/current/content-negotiation.html">Apache
* httpd documentation</a>.
+ * <p>
+ * MediaType is the general form, with parameters. ContentType is limited to type,
+ * subtype and charset.
*/
public class MediaType {
- private static Logger log = LoggerFactory.getLogger(MediaType.class) ;
+ private static Logger log = LoggerFactory.getLogger(MediaType.class);
- private static final String strCharset = "charset" ;
-
- private final String type ;
- private final String subType ;
+ private final String type;
+ private final String subType;
// Keys in insertion order.
- private final Map<String, String> params ;
+ private final Map<String, String> params;
protected MediaType(ParsedMediaType parser) {
- this.type = parser.type ;
- this.subType = parser.subType ;
- this.params = parser.params ;
+ this.type = parser.type;
+ this.subType = parser.subType;
+ this.params = parser.params;
}
public MediaType(MediaType other) {
- this.type = other.type ;
- this.subType = other.subType ;
+ this.type = other.type;
+ this.subType = other.subType;
// Order preserving copy.
- this.params = new LinkedHashMap<>(other.params) ;
+ this.params = new LinkedHashMap<>(other.params);
}
/** Create a media type from type and subType */
public MediaType(String type, String subType) {
- this(type, subType, null) ;
+ this(type, subType, null);
}
/** Create a media type from type and subType */
public MediaType(String type, String subType, String charset) {
- this.type = type ;
- this.subType = subType ;
- this.params = new LinkedHashMap<>() ;
+ this.type = type;
+ this.subType = subType;
+ this.params = new LinkedHashMap<>();
if ( charset != null )
- setParameter(strCharset, charset) ;
+ setParameter(HttpNames.charset, charset);
}
public static MediaType create(String contentType, String charset) {
- ParsedMediaType mediaType = parse(contentType) ;
+ ParsedMediaType mediaType = parse(contentType);
if ( charset != null )
- mediaType.params.put(strCharset, charset) ;
- return new MediaType(mediaType) ;
+ mediaType.params.put(HttpNames.charset, charset);
+ return new MediaType(mediaType);
}
public static MediaType createFromContentType(String string) {
- return new MediaType(parse(string)) ;
+ return new MediaType(parse(string));
}
public static MediaType create(String contentType, String subType, String charset) {
- return new MediaType(contentType, subType, charset) ;
+ return new MediaType(contentType, subType, charset);
}
public static MediaType create(String string) {
if ( string == null )
- return null ;
- return new MediaType(parse(string)) ;
+ return null;
+ return new MediaType(parse(string));
}
public static ParsedMediaType parse(String string) {
- ParsedMediaType mt = new ParsedMediaType() ;
+ ParsedMediaType mt = new ParsedMediaType();
- String[] x = WebLib.split(string, ";") ;
- String[] t = WebLib.split(x[0], "/") ;
- mt.type = t[0] ;
+ String[] x = WebLib.split(string, ";");
+ String[] t = WebLib.split(x[0], "/");
+ mt.type = t[0];
if ( t.length > 1 )
- mt.subType = t[1] ;
+ mt.subType = t[1];
- for (int i = 1; i < x.length; i++) {
+ for ( int i = 1 ; i < x.length ; i++ ) {
// Each a parameter
- String z[] = WebLib.split(x[i], "=") ;
+ String z[] = WebLib.split(x[i], "=");
if ( z.length == 2 )
- mt.params.put(z[0], z[1]) ;
+ mt.params.put(z[0], z[1]);
else
- log.warn("Duff parameter: " + x[i] + " in " + string) ;
+ log.warn("Duff parameter: " + x[i] + " in " + string);
}
- return mt ;
+ return mt;
}
/** Format for use in HTTP header */
-
public String toHeaderString() {
- StringBuilder b = new StringBuilder() ;
- b.append(type) ;
+ StringBuilder b = new StringBuilder();
+ b.append(type);
if ( subType != null )
- b.append("/").append(subType) ;
+ b.append("/").append(subType);
- for (Map.Entry<String, String> entry : params.entrySet()) {
- b.append(";") ;
- b.append(entry.getKey()) ;
- b.append("=") ;
- b.append(entry.getValue()) ;
+ for ( Map.Entry<String, String> entry : params.entrySet() ) {
+ b.append(";");
+ b.append(entry.getKey());
+ b.append("=");
+ b.append(entry.getValue());
}
- return b.toString() ;
+ return b.toString();
}
/**
- * Format to show structure - intentionally different from header form so
- * you can tell parsing happened correctly
+ * Format to show structure - intentionally different from header form so you can
+ * tell parsing happened correctly
*/
@Override
public String toString() {
- StringBuilder b = new StringBuilder() ;
- b.append("[") ;
- b.append(type) ;
+ StringBuilder b = new StringBuilder();
+ b.append("[");
+ b.append(type);
if ( subType != null )
- b.append("/").append(subType) ;
- for (String k : params.keySet()) {
+ b.append("/").append(subType);
+ for ( String k : params.keySet() ) {
if ( k.equals("boundary") )
- continue ;
- String v = params.get(k) ;
- b.append(" ") ;
- b.append(k) ;
- b.append("=") ;
- b.append(v) ;
+ continue;
+ String v = params.get(k);
+ b.append(" ");
+ b.append(k);
+ b.append("=");
+ b.append(v);
}
- b.append("]") ;
- return b.toString() ;
+ b.append("]");
+ return b.toString();
}
- // private String type = null ;
- // private String subType = null ;
- // // Keys in insertion order.
- // private Map<String, String> params = new LinkedHashMap<String, String>()
- // ;
-
@Override
public int hashCode() {
- return hashCodeObject(type, 1) ^ hashCodeObject(subType, 2) ^ hashCodeObject(params, 3) ;
+ return hashCodeObject(type, 1) ^ hashCodeObject(subType, 2) ^ hashCodeObject(params, 3);
}
@Override
public boolean equals(Object object) {
if ( this == object )
- return true ;
+ return true;
if ( !(object instanceof MediaType) )
- return false ;
- MediaType mt = (MediaType)object ;
- return Objects.equals(type, mt.type) && Objects.equals(subType, mt.subType) && Objects.equals(params, mt.params) ;
+ return false;
+ MediaType mt = (MediaType)object;
+ return Objects.equals(type, mt.type) && Objects.equals(subType, mt.subType) && Objects.equals(params, mt.params);
}
public String getParameter(String name) {
- return params.get(name) ;
+ return params.get(name);
}
private void setParameter(String name, String value) {
- params.put(name, value) ;
- }
-
- /** @deprecated Use {@link #getContentTypeStr} */
- @Deprecated
- public String getContentType() {
- return getContentTypeStr();
+ params.put(name, value);
}
public String getContentTypeStr() {
if ( subType == null )
- return type ;
- return type + "/" + subType ;
+ return type;
+ return type + "/" + subType;
}
public String getCharset() {
- return getParameter(strCharset) ;
+ return getParameter(HttpNames.charset);
}
public String getSubType() {
- return subType ;
+ return subType;
}
// public void setSubType(String subType) { this.subType = subType ;
// strContentType = null ; }
public String getType() {
- return type ;
+ return type;
}
// public void setType(String type) { this.type = type ; strContentType =
// null ; }
@@ -217,8 +206,8 @@ public class MediaType {
* @see MediaType#parse
*/
/* package */static class ParsedMediaType {
- public String type ;
- public String subType ;
- public Map<String, String> params = new LinkedHashMap<>() ;
+ public String type;
+ public String subType;
+ public Map<String, String> params = new LinkedHashMap<>();
}
}
diff --git a/jena-arq/src/main/java/org/apache/jena/query/QueryExecution.java b/jena-arq/src/main/java/org/apache/jena/query/QueryExecution.java
index 5a99d90..5afd2c8 100644
--- a/jena-arq/src/main/java/org/apache/jena/query/QueryExecution.java
+++ b/jena-arq/src/main/java/org/apache/jena/query/QueryExecution.java
@@ -66,7 +66,6 @@ public interface QueryExecution extends AutoCloseable
return QueryExecution.service(endpointURL).query(queryString).build();
}
-
// Short cuts to QueryExecution builders.
/** Create a local execution builder on a dataset */
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java
index a111dfd..2bab790 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java
@@ -20,6 +20,7 @@ package org.apache.jena.fuseki.servlets;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.ServletOutputStream;
@@ -28,7 +29,12 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.jena.atlas.RuntimeIOException;
import org.apache.jena.atlas.io.IO;
import org.apache.jena.atlas.json.JSON;
+import org.apache.jena.atlas.json.JsonBuilder;
+import org.apache.jena.atlas.json.JsonObject;
import org.apache.jena.atlas.json.JsonValue;
+import org.apache.jena.atlas.web.AcceptList;
+import org.apache.jena.atlas.web.MediaType;
+import org.apache.jena.fuseki.system.ConNeg;
import org.apache.jena.fuseki.system.UploadDetails;
import org.apache.jena.fuseki.system.UploadDetails.PreState;
import org.apache.jena.riot.RiotParseException;
@@ -109,7 +115,72 @@ public class ServletOps {
action.setResponseStatus(httpStatusCode);
}
+ private static MediaType mtTextHTML = MediaType.create("text/html");
+ private static AcceptList successReponseAccept = AcceptList.create("text/html", WebContent.contentTypeTextPlain, WebContent.contentTypeJSON);
+
public static void successPage(HttpAction action, String message) {
+ String x = action.getRequestHeader(HttpNames.hAccept);
+ MediaType mt = null ;
+ if ( x != null && x.equals("*/*") ) {
+ if ( action.getRequestContentType().equals(WebContent.contentTypeHTMLForm))
+ mt = mtTextHTML;
+ }
+
+ if ( mt == null && x != null )
+ mt = ConNeg.chooseContentType(action.getRequest(), successReponseAccept, MediaType.create("text/plain"));
+
+ if ( mt == null )
+ mt = mtTextHTML;
+
+ if ( WebContent.ctTextPlain.agreesWith(mt) ) {
+ successPageText(action, message);
+ return ;
+ }
+ if ( WebContent.ctJSON.agreesWith(mt) ) {
+ successPageJson(action, message);
+ return ;
+ }
+ // Default.
+ successPageHtml(action, message);
+ }
+
+ private static void successPageJson(HttpAction action, String message) {
+ try {
+ action.setResponseContentType(WebContent.contentTypeJSON);
+ action.setResponseCharacterEncoding(WebContent.charsetUTF8);
+ action.setResponseStatus(HttpSC.OK_200);
+ OutputStream out = action.getResponseOutputStream();
+ JsonObject obj = JsonBuilder.buildObject(builder->{
+ builder.pair("statusCode", 200);
+ if ( message != null )
+ builder.pair("message", message);
+ });
+ JSON.write(out, obj);
+ return;
+ } catch (IOException ex) {
+ errorOccurred(ex);
+ return;
+ }
+ }
+
+ private static void successPageText(HttpAction action, String message) {
+ if ( message == null )
+ message = HttpSC.getMessage(HttpSC.OK_200);
+ try {
+ action.setResponseContentType("text/plain");
+ action.setResponseCharacterEncoding(WebContent.charsetUTF8);
+ action.setResponseStatus(HttpSC.OK_200);
+ PrintWriter out = action.getResponseWriter();
+ if ( message != null )
+ out.println(message);
+ return;
+ } catch (IOException ex) {
+ errorOccurred(ex);
+ return;
+ }
+ }
+
+ private static void successPageHtml(HttpAction action, String message) {
try {
action.setResponseContentType("text/html");
action.setResponseCharacterEncoding(WebContent.charsetUTF8);