You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by rv...@apache.org on 2013/06/28 00:14:10 UTC
svn commit: r1497583 [1/2] - in /jena/trunk/jena-arq/src:
main/java/com/hp/hpl/jena/sparql/engine/http/
main/java/com/hp/hpl/jena/sparql/modify/ main/java/org/apache/jena/atlas/web/
main/java/org/apache/jena/atlas/web/auth/ main/java/org/apache/jena/ri...
Author: rvesse
Date: Thu Jun 27 22:14:09 2013
New Revision: 1497583
URL: http://svn.apache.org/r1497583
Log:
Finish converting SPARQL Query code to new unified HTTP framework and support broader authentication for SPARQL Queries (JENA-480)
Started work on adding support for Forms based authentication
Added:
jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/ApacheModAuthFormLogin.java
jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/FormLogin.java
jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/FormsAuthenticator.java
Modified:
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/HttpQuery.java
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryEngineHTTP.java
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryExceptionHTTP.java
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/modify/UpdateProcessRemote.java
jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/HttpException.java
jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/ServiceAuthenticator.java
jena/trunk/jena-arq/src/main/java/org/apache/jena/riot/web/HttpOp.java
jena/trunk/jena-arq/src/main/java/org/apache/jena/web/DatasetGraphAccessorHTTP.java
jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/engine/http/TestService.java
Modified: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/HttpQuery.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/HttpQuery.java?rev=1497583&r1=1497582&r2=1497583&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/HttpQuery.java (original)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/HttpQuery.java Thu Jun 27 22:14:09 2013
@@ -18,534 +18,384 @@
package com.hp.hpl.jena.sparql.engine.http;
-import java.io.* ;
-import java.net.HttpURLConnection ;
-import java.net.MalformedURLException ;
-import java.net.SocketTimeoutException ;
-import java.net.URL ;
-import java.util.ArrayList ;
-import java.util.Iterator ;
-import java.util.List ;
-import java.util.Map ;
-import java.util.regex.Pattern ;
-import java.util.zip.DeflaterInputStream ;
-import java.util.zip.GZIPInputStream ;
-
-import org.apache.commons.codec.binary.Base64 ;
-import org.apache.jena.atlas.lib.StrUtils ;
-import org.apache.jena.riot.WebContent ;
-import org.slf4j.Logger ;
-import org.slf4j.LoggerFactory ;
-
-import com.hp.hpl.jena.query.ARQ ;
-import com.hp.hpl.jena.query.QueryExecException ;
-import com.hp.hpl.jena.shared.JenaException ;
-import com.hp.hpl.jena.sparql.ARQInternalErrorException ;
-import com.hp.hpl.jena.sparql.util.Convert ;
-import com.hp.hpl.jena.util.FileUtils ;
-
-/** Create an execution object for performing a query on a model
- * over HTTP. This is the main protocol engine for HTTP query.
- * There are higher level classes for doing a query and presenting
- * the results in an API fashion.
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.zip.DeflaterInputStream;
+import java.util.zip.GZIPInputStream;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.impl.client.AbstractHttpClient;
+import org.apache.http.impl.client.DecompressingHttpClient;
+import org.apache.http.impl.client.SystemDefaultHttpClient;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.jena.atlas.AtlasException;
+import org.apache.jena.atlas.lib.StrUtils;
+import org.apache.jena.atlas.web.HttpException;
+import org.apache.jena.atlas.web.TypedInputStream;
+import org.apache.jena.atlas.web.auth.HttpAuthenticator;
+import org.apache.jena.atlas.web.auth.SimpleAuthenticator;
+import org.apache.jena.riot.WebContent;
+import org.apache.jena.riot.web.HttpOp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.hp.hpl.jena.query.ARQ;
+import com.hp.hpl.jena.query.QueryExecException;
+import com.hp.hpl.jena.shared.JenaException;
+import com.hp.hpl.jena.sparql.ARQInternalErrorException;
+import com.hp.hpl.jena.sparql.util.Convert;
+import com.hp.hpl.jena.util.FileUtils;
+
+/**
+ * Create an execution object for performing a query on a model over HTTP. This
+ * is the main protocol engine for HTTP query. There are higher level classes
+ * for doing a query and presenting the results in an API fashion.
*
- * If the query string is large, then HTTP POST is used. */
-public class HttpQuery extends Params
-{
- static final Logger log = LoggerFactory.getLogger(HttpQuery.class.getName()) ;
-
+ * If the query string is large, then HTTP POST is used.
+ */
+public class HttpQuery extends Params {
+ static final Logger log = LoggerFactory.getLogger(HttpQuery.class.getName());
+
/** The definition of "large" queries */
// Not final so that other code can change it.
- static public /*final*/ int urlLimit = 2*1024 ;
-
- String serviceURL ;
-
- String contentTypeResult = WebContent.contentTypeResultsXML ;
- HttpURLConnection httpConnection = null ;
-
- // An object indicate no value associated with parameter name
- final static Object noValue = new Object() ;
- String user = null ;
- char[] password = null ;
-
- int responseCode = 0;
- String responseMessage = null ;
- boolean forcePOST = false ;
- String queryString = null ;
- boolean serviceParams = false ;
- private final Pattern queryParamPattern = Pattern.compile(".+[&|\\?]query=.*") ;
-
- int connectTimeout = 0;
- int readTimeout = 0;
-
- private boolean allowGZip = false ;
+ static public/* final */int urlLimit = 2 * 1024;
+
+ String serviceURL;
+ String contentTypeResult = WebContent.contentTypeResultsXML;
+
+ // An object indicate no value associated with parameter name
+ final static Object noValue = new Object();
+
+ private HttpAuthenticator authenticator = null;
+ private int responseCode = 0;
+ private String responseMessage = null;
+ private boolean forcePOST = false;
+ private String queryString = null;
+ private boolean serviceParams = false;
+ private final Pattern queryParamPattern = Pattern.compile(".+[&|\\?]query=.*");
+ private int connectTimeout = 0, readTimeout = 0;
+ private boolean allowGZip = false;
private boolean allowDeflate = false;
-
- //static final String ENC_UTF8 = "UTF-8" ;
-
- /** Create a execution object for a whole model GET
- * @param serviceURL The model
+
+ // static final String ENC_UTF8 = "UTF-8" ;
+
+ /**
+ * Create a execution object for a whole model GET
+ *
+ * @param serviceURL
+ * The model
*/
-
- public HttpQuery(String serviceURL)
- {
- init(serviceURL) ;
+ public HttpQuery(String serviceURL) {
+ init(serviceURL);
}
-
- /** Create a execution object for a whole model GET
- * @param url The model
+ /**
+ * Create a execution object for a whole model GET
+ *
+ * @param url
+ * The model
*/
-
- public HttpQuery(URL url)
- {
- init(url.toString()) ;
+ public HttpQuery(URL url) {
+ init(url.toString());
}
-
- private void init(String serviceURL)
- {
- if ( log.isTraceEnabled())
- log.trace("URL: "+serviceURL) ;
-
- if ( serviceURL.indexOf('?') >= 0 )
- serviceParams = true ;
+ private void init(String serviceURL) {
+ if (log.isTraceEnabled())
+ log.trace("URL: " + serviceURL);
- if ( queryParamPattern.matcher(serviceURL).matches() )
- throw new QueryExecException("SERVICE URL overrides the 'query' SPARQL protocol parameter") ;
+ if (serviceURL.indexOf('?') >= 0)
+ serviceParams = true;
- this.serviceURL = serviceURL ;
+ if (queryParamPattern.matcher(serviceURL).matches())
+ throw new QueryExecException("SERVICE URL overrides the 'query' SPARQL protocol parameter");
+
+ this.serviceURL = serviceURL;
}
-
- private String getQueryString()
- {
- if ( queryString == null )
- queryString = super.httpString() ;
- return queryString ;
+
+ private String getQueryString() {
+ if (queryString == null)
+ queryString = super.httpString();
+ return queryString;
}
- public HttpURLConnection getConnection() { return httpConnection ; }
-
- /** Set the content type (Accept header) for the results
+ /**
+ * Set the content type (Accept header) for the results
+ *
+ * @param contentType
+ * Accept content type
*/
- public void setAccept(String contentType)
- {
- contentTypeResult = contentType ;
+ public void setAccept(String contentType) {
+ contentTypeResult = contentType;
}
-
+
/**
- * Gets the Content Type, if the query has been made this reflects the Content-Type header returns, if it has not been made this reflects only the Accept header that will be sent (as set via the {@link #setAccept(String)} method)
+ * Gets the Content Type
+ * <p>
+ * If the query has been made this reflects the Content-Type header returns,
+ * if it has not been made this reflects only the Accept header that will be
+ * sent (as set via the {@link #setAccept(String)} method)
+ * </p>
+ *
+ * @return Content Type
*/
- public String getContentType()
- {
- return contentTypeResult;
+ public String getContentType() {
+ return contentTypeResult;
}
-
+
/**
- * Gets the HTTP Response Code returned by the request (returns 0 if request has yet to be made)
+ * Gets the HTTP Response Code returned by the request (returns 0 if request
+ * has yet to be made)
+ *
+ * @return Response Code
*/
- public int getResponseCode()
- {
- return responseCode;
+ public int getResponseCode() {
+ return responseCode;
}
-
+
/**
* Sets whether the HTTP request will include a Accept-Encoding: gzip header
+ *
+ * @param allow
+ * Whether to allow GZip encoding
*/
- public void setAllowGZip(boolean allow)
- {
- allowGZip = allow;
+ public void setAllowGZip(boolean allow) {
+ allowGZip = allow;
}
-
+
/**
- * Sets whether the HTTP request will include a Accept-Encoding: deflate header
+ * Sets whether the HTTP request will include a Accept-Encoding: deflate
+ * header
+ *
+ * @param allow
+ * Whether to allow Deflate encoding
*/
- public void setAllowDeflate(boolean allow)
- {
- allowDeflate = allow;
+ public void setAllowDeflate(boolean allow) {
+ allowDeflate = allow;
}
-
+
/**
- * Sets basic authentication
- * @param user Username
- * @param password Password
+ * Sets basic authentication. It may be preferable to use the
+ * {@link #setAuthenticator(HttpAuthenticator)} method since that provides
+ * more flexibility in the type of authentication supported.
+ *
+ * @param user
+ * User name
+ * @param password
+ * Password
*/
- public void setBasicAuthentication(String user, char[] password)
- {
- this.user = user ;
- this.password = password ;
+ public void setBasicAuthentication(String user, char[] password) {
+ this.setAuthenticator(new SimpleAuthenticator(user, password));
}
-
- /** Return whether this request will go by GET or POST
- * @return boolean
+
+ /**
+ * Sets the authenticator to use
+ * @param authenticator Authenticator
*/
- public boolean usesPOST()
- {
- if ( forcePOST )
- return true ;
- String s = getQueryString() ;
-
- return serviceURL.length()+s.length() >= urlLimit ;
+ public void setAuthenticator(HttpAuthenticator authenticator) {
+ this.authenticator = authenticator;
+ }
+
+ /**
+ * Return whether this request will go by GET or POST
+ *
+ * @return boolean
+ */
+ public boolean usesPOST() {
+ if (forcePOST)
+ return true;
+ String s = getQueryString();
+
+ return serviceURL.length() + s.length() >= urlLimit;
}
- /** Force the use of HTTP POST for the query operation
+ /**
+ * Force the use of HTTP POST for the query operation
*/
- public void setForcePOST()
- {
- forcePOST = true ;
+ public void setForcePOST() {
+ forcePOST = true;
}
-
+
/**
* Sets HTTP Connection timeout, any value <= 0 is taken to mean no timeout
+ *
+ * @param timeout
+ * Connection Timeout
*/
- public void setConnectTimeout(int timeout)
- {
- connectTimeout = timeout;
+ public void setConnectTimeout(int timeout) {
+ connectTimeout = timeout;
}
-
+
/**
* Gets the HTTP Connection timeout
+ *
+ * @return Connection Timeout
*/
- public int getConnectTimeout()
- {
- return connectTimeout;
+ public int getConnectTimeout() {
+ return connectTimeout;
}
-
+
/**
* Sets HTTP Read timeout, any value <= 0 is taken to mean no timeout
+ *
+ * @param timeout
+ * Read Timeout
*/
- public void setReadTimeout(int timeout)
- {
- readTimeout = timeout;
+ public void setReadTimeout(int timeout) {
+ readTimeout = timeout;
}
-
+
/**
* Gets the HTTP Read timeout
+ *
+ * @return Read Timeout
*/
- public int getReadTimeout()
- {
- return readTimeout;
+ public int getReadTimeout() {
+ return readTimeout;
}
- /** Execute the operation
- * @return Model The resulting model
+ /**
+ * Execute the operation
+ *
+ * @return Model The resulting model
* @throws QueryExceptionHTTP
*/
- public InputStream exec() throws QueryExceptionHTTP
- {
+ public InputStream exec() throws QueryExceptionHTTP {
try {
if (usesPOST())
return execPost();
return execGet();
- } catch (QueryExceptionHTTP httpEx)
- {
+ } catch (QueryExceptionHTTP httpEx) {
log.trace("Exception in exec", httpEx);
throw httpEx;
- }
- catch (JenaException jEx)
- {
+ } catch (JenaException jEx) {
log.trace("JenaException in exec", jEx);
- throw jEx ;
+ throw jEx;
}
}
- private InputStream execGet() throws QueryExceptionHTTP
- {
- URL target = null ;
- String qs = getQueryString() ;
-
- ARQ.getHttpRequestLogger().trace(qs) ;
-
+ private InputStream execGet() throws QueryExceptionHTTP {
+ URL target = null;
+ String qs = getQueryString();
+
+ ARQ.getHttpRequestLogger().trace(qs);
+
try {
- if ( count() == 0 )
- target = new URL(serviceURL) ;
+ if (count() == 0)
+ target = new URL(serviceURL);
else
- target = new URL(serviceURL+(serviceParams ? "&" : "?")+qs) ;
+ target = new URL(serviceURL + (serviceParams ? "&" : "?") + qs);
+ } catch (MalformedURLException malEx) {
+ throw new QueryExceptionHTTP(0, "Malformed URL: " + malEx);
}
- catch (MalformedURLException malEx)
- { throw new QueryExceptionHTTP(0, "Malformed URL: "+malEx) ; }
- log.trace("GET "+target.toExternalForm()) ;
-
- try
- {
- httpConnection = (HttpURLConnection) target.openConnection();
- // This is the default setting - but be clear about it.
- httpConnection.setInstanceFollowRedirects(true) ;
- httpConnection.setRequestProperty("Accept", contentTypeResult) ;
-
- int x = httpConnection.getReadTimeout() ;
-
- // By default, following 3xx redirects is true
- //conn.setFollowRedirects(true) ;
- basicAuthentication(httpConnection) ;
- applyTimeouts(httpConnection);
- applyEncodings(httpConnection);
-
- httpConnection.setDoInput(true);
- httpConnection.connect();
- try
- {
- return execCommon();
- }
- catch (QueryExceptionHTTP qEx)
- {
+ log.trace("GET " + target.toExternalForm());
+
+ try {
+ try {
+ HttpClient client = new SystemDefaultHttpClient();
+ if (this.connectTimeout > 0)
+ client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, this.connectTimeout);
+ if (this.readTimeout > 0)
+ client.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, this.readTimeout);
+ HttpContext context = new BasicHttpContext();
+ if (allowGZip || allowDeflate) {
+ // Apply auth early as the decompressing client we're about
+ // to add will block this being applied later
+ HttpOp.applyAuthentication((AbstractHttpClient) client, serviceURL, context, authenticator);
+ client = new DecompressingHttpClient(client);
+ }
+ TypedInputStream stream = HttpOp.execHttpGet(target.toString(), contentTypeResult, client, context,
+ this.authenticator);
+ if (stream == null)
+ throw new QueryExceptionHTTP(404);
+ return execCommon(stream);
+ } catch (HttpException httpEx) {
// Back-off and try POST if something complain about long URIs
- // Broken
- if (qEx.getResponseCode() == 414 /*HttpServletResponse.SC_REQUEST_URI_TOO_LONG*/ )
+ if (httpEx.getResponseCode() == 414)
return execPost();
- throw qEx;
+ throw httpEx;
}
+ } catch (HttpException httpEx) {
+ // Unwrap and re-wrap the HTTP exception
+ responseCode = httpEx.getResponseCode();
+ throw new QueryExceptionHTTP(responseCode, "Error making the query, see cause for details", httpEx.getCause());
}
- catch (java.net.ConnectException connEx)
- { throw new QueryExceptionHTTP(QueryExceptionHTTP.NoServer, "Failed to connect to remote server"); }
- catch (IOException ioEx)
- { throw new QueryExceptionHTTP(ioEx); }
- }
-
- private InputStream execPost() throws QueryExceptionHTTP
- {
+ }
+
+ private InputStream execPost() throws QueryExceptionHTTP {
URL target = null;
- try { target = new URL(serviceURL); }
- catch (MalformedURLException malEx)
- { throw new QueryExceptionHTTP(0, "Malformed URL: " + malEx); }
- log.trace("POST "+target.toExternalForm()) ;
-
- ARQ.getHttpRequestLogger().trace(target.toExternalForm()) ;
-
- try
- {
- httpConnection = (HttpURLConnection) target.openConnection();
- httpConnection.setRequestMethod("POST") ;
- httpConnection.setRequestProperty("Accept", contentTypeResult) ;
- httpConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") ;
- basicAuthentication(httpConnection) ;
- applyTimeouts(httpConnection);
- applyEncodings(httpConnection);
- httpConnection.setDoOutput(true) ;
-
- boolean first = true ;
- OutputStream out = httpConnection.getOutputStream() ;
- for ( Iterator<Pair> iter = pairs().listIterator() ; iter.hasNext() ; )
- {
- if ( ! first )
- out.write('&') ;
- first = false ;
- Pair p = iter.next() ;
- out.write(p.getName().getBytes()) ;
- out.write('=') ;
- String x = p.getValue() ;
- x = Convert.encWWWForm(x) ;
- out.write(x.getBytes()) ;
- ARQ.getHttpRequestLogger().trace("Param: "+x) ;
- }
- out.flush() ;
- httpConnection.connect() ;
- return execCommon() ;
- }
- catch (java.net.ConnectException connEx)
- { throw new QueryExceptionHTTP(-1, "Failed to connect to remote server"); }
- catch (SocketTimeoutException timeoutEx)
- { throw new QueryExceptionHTTP(-1, "Failed to connect to remove server within specified timeout"); }
- catch (IOException ioEx)
- { throw new QueryExceptionHTTP(ioEx); }
- }
-
- private void basicAuthentication(HttpURLConnection httpConnection2)
- {
- // Do basic authentication : do directly, not via an Authenticator, because it
- // avoids an extra round trip (Java normally does the request without authetication,
- // then reties with)
-
- if ( user != null || password != null)
- {
- try
- {
- if ( user == null || password == null )
- log.warn("Only one of user/password is set") ;
- // We want: "Basic user:password" except user:password is base 64 encoded.
- // Build string, get as UTF-8, bytes, translate to base 64.
- StringBuffer x = new StringBuffer() ;
- byte b[] = x.append(user).append(":").append(password).toString().getBytes("UTF-8") ;
- String y = Base64.encodeBase64String(b) ;
- httpConnection.setRequestProperty("Authorization", "Basic "+y) ;
- // Overwrite any password details we copied.
- // Still leaves the copy in the HTTP connection. But this only basic auth.
- for ( int i = 0 ; i < x.length() ; i++ ) x.setCharAt(i, '*') ;
- for ( int i = 0 ; i < b.length ; i++ ) b[i] = (byte)0 ;
- } catch (UnsupportedEncodingException ex)
- {
- // Can't happen - UTF-8 is required of all Java platforms.
- throw new ARQInternalErrorException("UTF-8 is broken on this platform", ex) ;
- }
+ try {
+ target = new URL(serviceURL);
+ } catch (MalformedURLException malEx) {
+ throw new QueryExceptionHTTP(0, "Malformed URL: " + malEx);
}
- }
+ log.trace("POST " + target.toExternalForm());
- private void applyTimeouts(HttpURLConnection conn)
- {
- if (connectTimeout > 0)
- {
- conn.setConnectTimeout(connectTimeout);
- }
- if (readTimeout > 0)
- {
- conn.setReadTimeout(readTimeout);
- }
- }
-
- private void applyEncodings(HttpURLConnection conn)
- {
- List<String> encodings = new ArrayList<String>();
- if (allowGZip) encodings.add("gzip");
- if (allowDeflate) encodings.add("deflate");
- if (encodings.size() > 0)
- {
- //Apply the Accept-Encoding header if at least one encoding has been selected
- conn.setRequestProperty("Accept-Encoding", StrUtils.strjoin(", ", encodings));
- }
- }
+ ARQ.getHttpRequestLogger().trace(target.toExternalForm());
- private InputStream execCommon() throws QueryExceptionHTTP
- {
try {
- try {
- responseCode = httpConnection.getResponseCode() ;
- responseMessage = Convert.decWWWForm(httpConnection.getResponseMessage()) ;
- } catch (NullPointerException ex) {
- // This happens if you talk to a non-HTTP port.
- // e.g. memcached!
- throw new QueryExceptionHTTP("Problems with HTTP response (was it an HTTP server?)", ex) ;
+ HttpClient client = new SystemDefaultHttpClient();
+ if (this.connectTimeout > 0)
+ client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, this.connectTimeout);
+ if (this.readTimeout > 0)
+ client.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, this.readTimeout);
+ HttpContext context = new BasicHttpContext();
+ if (allowGZip || allowDeflate) {
+ // Apply auth early as the decompressing client we're about
+ // to add will block this being applied later
+ HttpOp.applyAuthentication((AbstractHttpClient) client, serviceURL, context, authenticator);
+ client = new DecompressingHttpClient(client);
}
- // 1xx: Informational
- // 2xx: Success
- // 3xx: Redirection
- // 4xx: Client Error
- // 5xx: Server Error
-
- if ( 300 <= responseCode && responseCode < 400 )
- throw new QueryExceptionHTTP(responseCode, responseMessage) ;
-
- // Other 400 and 500 - errors
-
- if ( responseCode >= 400 )
- {
-
- InputStream x = httpConnection.getErrorStream() ;
- String str = null ;
- if ( x != null )
- {
- //String ct = httpConnection.getContentType() ;
- //httpConnection.getContentEncoding() ;
-
- try { str = FileUtils.readWholeFileAsUTF8(x) ; }
- catch (Throwable ex) {}
- }
- if ( str != null )
- throw new QueryExceptionHTTP(responseCode, responseMessage+"\n"+str) ;
- else
- throw new QueryExceptionHTTP(responseCode, responseMessage) ;
- }
-
- // Request succeeded
- //httpConnection.setReadTimeout(10) ;
- InputStream in = httpConnection.getInputStream() ;
-
- //Get the returned content type so we can expose this later via the getContentType() method
- //We strip any parameters off the returned content type e.g. ;charset=UTF-8 since code that
- //consumes our getContentType() method will expect a bare MIME type
- contentTypeResult = httpConnection.getContentType() ;
- if (contentTypeResult.contains(";"))
- {
- contentTypeResult = contentTypeResult.substring(0, contentTypeResult.indexOf(';'));
- }
-
-
- //If compression was enabled and we got a compressed response as indicated by the presence of
- //a Content-Encoding header we need to ensure the input stream is appropriately wrapped in
- //the relevant stream type but checking that the JVM hasn't been clever enough to do
- //this for us already
- String contentEnc = httpConnection.getContentEncoding() ;
-
- if (contentEnc != null)
- {
- if (contentEnc.equalsIgnoreCase("gzip"))
- {
- if (!(in instanceof GZIPInputStream))
- {
- in = new GZIPInputStream(in);
- }
- }
- else if (contentEnc.equalsIgnoreCase("deflate"))
- {
- if (!(in instanceof DeflaterInputStream))
- {
- in = new DeflaterInputStream(in);
- }
- }
- }
-
- if ( false )
- {
- // Dump the header
- Map<String,List<String>> map = httpConnection.getHeaderFields() ;
- for ( Iterator<String> iter = map.keySet().iterator() ; iter.hasNext() ; )
- {
- String k = iter.next();
- List<String> v = map.get(k) ;
- System.out.println(k+" = "+v) ;
- }
- }
-
- // Dump response body
- if ( false )
- {
- StringBuffer b = new StringBuffer(1000) ;
- byte[] chars = new byte[1000] ;
- while(true)
- {
- int x = in.read(chars) ;
- if ( x < 0 ) break ;
- b.append(new String(chars, 0, x, FileUtils.encodingUTF8)) ;
- }
- System.out.println(b.toString()) ;
- System.out.flush() ;
- // Reset
- in = new ByteArrayInputStream(b.toString().getBytes(FileUtils.encodingUTF8)) ;
- }
-
-
- // +++ WORKAROUND for badly behaved apps.
- // Apps sometimes call QueryExecution.close straight after .execSelect.
- // that results in some resuls being seen, not all of them => XMl parse errors.
-// byte[] bytes = IO.readWholeFile(in) ;
-// in.close()
-// in = new ByteArrayInputStream(bytes) ;
- // +++
-
- return in ;
- }
- catch (IOException ioEx)
- {
- throw new QueryExceptionHTTP(ioEx) ;
- }
- catch (QueryExceptionHTTP httpEx)
- {
- //We want to throw this upwards and not catch it in the next block and inadvertently rewrap it
- //since that can hide the real error details from the user
- throw httpEx;
+
+ TypedInputStream stream = HttpOp.execHttpPostForm(serviceURL, contentTypeResult, (Params) this, client, context,
+ this.authenticator);
+ if (stream == null)
+ throw new QueryExceptionHTTP(404);
+ return execCommon(stream);
+ } catch (HttpException httpEx) {
+ // Unwrap and re-wrap the HTTP Exception
+ responseCode = httpEx.getResponseCode();
+ throw new QueryExceptionHTTP(responseCode, "Error making the query, see cause for details", httpEx.getCause());
}
- catch (JenaException rdfEx)
- {
- throw new QueryExceptionHTTP(rdfEx) ;
+ }
+
+ private InputStream execCommon(TypedInputStream stream) throws QueryExceptionHTTP {
+ // Assume response code must be 200 if we got here
+ responseCode = 200;
+
+ // Get the returned content type so we can expose this later via the
+ // getContentType() method
+ // We strip any parameters off the returned content type e.g.
+ // ;charset=UTF-8 since code that
+ // consumes our getContentType() method will expect a bare MIME type
+ contentTypeResult = stream.getContentType();
+ if (contentTypeResult != null && contentTypeResult.contains(";")) {
+ contentTypeResult = contentTypeResult.substring(0, contentTypeResult.indexOf(';'));
}
+
+ // NB - Content Encoding is now handled at a higher level
+ // so we don't have to worry about wrapping the stream at all
+
+ return stream;
}
-
+
@Override
- public String toString()
- {
- String s = httpString() ;
- if ( s != null && s.length() > 0 )
- return serviceURL+"?"+s ;
- return serviceURL ;
+ public String toString() {
+ String s = httpString();
+ if (s != null && s.length() > 0)
+ return serviceURL + "?" + s;
+ return serviceURL;
}
}
Modified: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryEngineHTTP.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryEngineHTTP.java?rev=1497583&r1=1497582&r2=1497583&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryEngineHTTP.java (original)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryEngineHTTP.java Thu Jun 27 22:14:09 2013
@@ -18,134 +18,128 @@
package com.hp.hpl.jena.sparql.engine.http;
-import java.io.ByteArrayInputStream ;
-import java.io.InputStream ;
-import java.util.ArrayList ;
-import java.util.Iterator ;
-import java.util.List ;
-import java.util.Map ;
-import java.util.concurrent.TimeUnit ;
-
-import org.apache.jena.atlas.io.IO ;
-import org.apache.jena.riot.* ;
-import org.slf4j.Logger ;
-import org.slf4j.LoggerFactory ;
-
-import com.hp.hpl.jena.graph.Triple ;
-import com.hp.hpl.jena.query.* ;
-import com.hp.hpl.jena.rdf.model.Model ;
-import com.hp.hpl.jena.sparql.ARQException ;
-import com.hp.hpl.jena.sparql.graph.GraphFactory ;
-import com.hp.hpl.jena.sparql.resultset.CSVInput ;
-import com.hp.hpl.jena.sparql.resultset.JSONInput ;
-import com.hp.hpl.jena.sparql.resultset.TSVInput ;
-import com.hp.hpl.jena.sparql.resultset.XMLInput ;
-import com.hp.hpl.jena.sparql.util.Context ;
-import com.hp.hpl.jena.util.FileManager ;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.jena.atlas.io.IO;
+import org.apache.jena.atlas.web.auth.HttpAuthenticator;
+import org.apache.jena.atlas.web.auth.SimpleAuthenticator;
+import org.apache.jena.riot.*;
+import org.apache.jena.riot.web.HttpOp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.query.*;
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.sparql.ARQException;
+import com.hp.hpl.jena.sparql.graph.GraphFactory;
+import com.hp.hpl.jena.sparql.resultset.CSVInput;
+import com.hp.hpl.jena.sparql.resultset.JSONInput;
+import com.hp.hpl.jena.sparql.resultset.TSVInput;
+import com.hp.hpl.jena.sparql.resultset.XMLInput;
+import com.hp.hpl.jena.sparql.util.Context;
+import com.hp.hpl.jena.util.FileManager;
/**
- * A query execution implementation where queries are executed against a remote service
- *
+ * A query execution implementation where queries are executed against a remote
+ * service
+ *
*/
-public class QueryEngineHTTP implements QueryExecution
-{
- private static Logger log = LoggerFactory.getLogger(QueryEngineHTTP.class) ;
-
- public static final String QUERY_MIME_TYPE = WebContent.contentTypeSPARQLQuery ; // "application/sparql-query" ;
- private final Query query ;
- private final String queryString ;
- private final String service ;
- private final Context context ;
-
- //Params
- Params params = null ;
-
+public class QueryEngineHTTP implements QueryExecution {
+ private static Logger log = LoggerFactory.getLogger(QueryEngineHTTP.class);
+
+ public static final String QUERY_MIME_TYPE = WebContent.contentTypeSPARQLQuery; // "application/sparql-query"
+ // ;
+ private final Query query;
+ private final String queryString;
+ private final String service;
+ private final Context context;
+
+ // Params
+ Params params = null;
+
// Protocol
- List<String> defaultGraphURIs = new ArrayList<String>() ;
- List<String> namedGraphURIs = new ArrayList<String>() ;
- private String user = null ;
- private char[] password = null ;
-
- private boolean finished = false ;
-
- //Timeouts
- private long connectTimeout = -1 ;
+ List<String> defaultGraphURIs = new ArrayList<String>();
+ List<String> namedGraphURIs = new ArrayList<String>();
+ private HttpAuthenticator authenticator;
+
+ private boolean finished = false;
+
+ // Timeouts
+ private long connectTimeout = -1;
private TimeUnit connectTimeoutUnit = TimeUnit.MILLISECONDS;
- private long readTimeout = -1 ;
+ private long readTimeout = -1;
private TimeUnit readTimeoutUnit = TimeUnit.MILLISECONDS;
-
- //Compression Support
- private boolean allowGZip = true ;
- private boolean allowDeflate = true;
-
- //Content Types
+
+ // Compression Support
+ private boolean allowGZip = true;
+ private boolean allowDeflate = true;
+
+ // Content Types
private String selectContentType = WebContent.contentTypeResultsXML;
private String askContentType = WebContent.contentTypeResultsXML;
private String modelContentType = WebContent.contentTypeRDFXML;
- public static String[] supportedSelectContentTypes = new String []
- {
- WebContent.contentTypeResultsXML,
- WebContent.contentTypeResultsJSON,
- WebContent.contentTypeTextTSV,
- WebContent.contentTypeTextCSV
- };
- public static String[] supportedAskContentTypes = new String []
- {
- WebContent.contentTypeResultsXML,
- WebContent.contentTypeJSON,
- WebContent.contentTypeTextTSV,
- WebContent.contentTypeTextCSV
- };
-
+ public static String[] supportedSelectContentTypes = new String[] { WebContent.contentTypeResultsXML,
+ WebContent.contentTypeResultsJSON, WebContent.contentTypeTextTSV, WebContent.contentTypeTextCSV };
+ public static String[] supportedAskContentTypes = new String[] { WebContent.contentTypeResultsXML,
+ WebContent.contentTypeJSON, WebContent.contentTypeTextTSV, WebContent.contentTypeTextCSV };
+
// Releasing HTTP input streams is important. We remember this for SELECT,
// and will close when the engine is closed
private InputStream retainedConnection = null;
-
- public QueryEngineHTTP(String serviceURI, Query query)
- {
- this(serviceURI, query, query.toString()) ;
- }
-
- public QueryEngineHTTP(String serviceURI, String queryString)
- {
- this(serviceURI, null, queryString) ;
- }
-
- private QueryEngineHTTP(String serviceURI, Query query, String queryString)
- {
- this.query = query ;
- this.queryString = queryString ;
- this.service = serviceURI ;
+
+ public QueryEngineHTTP(String serviceURI, Query query) {
+ this(serviceURI, query, query.toString());
+ }
+
+ public QueryEngineHTTP(String serviceURI, String queryString) {
+ this(serviceURI, null, queryString);
+ }
+
+ private QueryEngineHTTP(String serviceURI, Query query, String queryString) {
+ this.query = query;
+ this.queryString = queryString;
+ this.service = serviceURI;
// Copy the global context to freeze it.
- this.context = new Context(ARQ.getContext()) ;
-
+ this.context = new Context(ARQ.getContext());
+
// Apply service configuration if relevant
QueryEngineHTTP.applyServiceConfig(serviceURI, this);
}
-
+
/**
* <p>
- * Helper method which applies configuration from the Context to the query engine
- * if a service context exists for the given URI
+ * Helper method which applies configuration from the Context to the query
+ * engine if a service context exists for the given URI
* </p>
* <p>
- * Based off proposed patch for JENA-405 but modified to apply all relevant configuration, this is in part also
- * based off of the private {@code configureQuery()} method of the {@link Service} class though it omits
- * parameter merging since that will be done automatically whenever the {@link QueryEngineHTTP} instance
- * makes a query for remote submission.
+ * Based off proposed patch for JENA-405 but modified to apply all relevant
+ * configuration, this is in part also based off of the private
+ * {@code configureQuery()} method of the {@link Service} class though it
+ * omits parameter merging since that will be done automatically whenever
+ * the {@link QueryEngineHTTP} instance makes a query for remote submission.
* </p>
- * @param serviceURI Service URI
+ *
+ * @param serviceURI
+ * Service URI
*/
private static void applyServiceConfig(String serviceURI, QueryEngineHTTP engine) {
- if (engine.context == null) return;
-
+ if (engine.context == null)
+ return;
+
@SuppressWarnings("unchecked")
Map<String, Context> serviceContextMap = (Map<String, Context>) engine.context.get(Service.serviceContext);
if (serviceContextMap != null && serviceContextMap.containsKey(serviceURI)) {
Context serviceContext = serviceContextMap.get(serviceURI);
if (log.isDebugEnabled())
log.debug("Endpoint URI {} has SERVICE Context: {} ", serviceURI, serviceContext);
-
+
// Apply behavioral options
engine.setAllowGZip(serviceContext.isTrueOrUndef(Service.queryGzip));
engine.setAllowDeflate(serviceContext.isTrueOrUndef(Service.queryDeflate));
@@ -164,491 +158,554 @@ public class QueryEngineHTTP implements
}
}
}
-
+
/**
* Applies context provided timeouts to the given engine
- * @param engine Engine
- * @param context Context
+ *
+ * @param engine
+ * Engine
+ * @param context
+ * Context
*/
private static void applyServiceTimeouts(QueryEngineHTTP engine, Context context) {
- if (context.isDefined(Service.queryTimeout))
- {
+ if (context.isDefined(Service.queryTimeout)) {
Object obj = context.get(Service.queryTimeout);
- if (obj instanceof Number)
- {
+ if (obj instanceof Number) {
int x = ((Number) obj).intValue();
engine.setTimeout(-1, x);
- }
- else if (obj instanceof String)
- {
+ } else if (obj instanceof String) {
try {
String str = obj.toString();
if (str.contains(",")) {
-
+
String[] a = str.split(",");
int connect = Integer.parseInt(a[0]);
int read = Integer.parseInt(a[1]);
engine.setTimeout(read, connect);
- }
- else
- {
+ } else {
int x = Integer.parseInt(str);
engine.setTimeout(-1, x);
}
- }
- catch (NumberFormatException ex)
- {
+ } catch (NumberFormatException ex) {
throw new QueryExecException("Can't interpret string for timeout: " + obj);
}
- }
- else
- {
+ } else {
throw new QueryExecException("Can't interpret timeout: " + obj);
}
}
}
-
-// public void setParams(Params params)
-// { this.params = params ; }
-
+
+ // public void setParams(Params params)
+ // { this.params = params ; }
+
// Meaning-less
@Override
- public void setFileManager(FileManager fm)
- { throw new UnsupportedOperationException("FileManagers do not apply to remote query execution") ; }
+ public void setFileManager(FileManager fm) {
+ throw new UnsupportedOperationException("FileManagers do not apply to remote query execution");
+ }
@Override
- public void setInitialBinding(QuerySolution binding)
- { throw new UnsupportedOperationException("Initial bindings not supported for remote queries, consider using a ParameterizedSparqlString to prepare a query for remote execution") ; }
-
- public void setInitialBindings(ResultSet table)
- { throw new UnsupportedOperationException("Initial bindings not supported for remote queries, consider using a ParameterizedSparqlString to prepare a query for remote execution") ; }
-
- /** @param defaultGraphURIs The defaultGraphURIs to set. */
- public void setDefaultGraphURIs(List<String> defaultGraphURIs)
- {
- this.defaultGraphURIs = defaultGraphURIs ;
- }
-
- /** @param namedGraphURIs The namedGraphURIs to set. */
- public void setNamedGraphURIs(List<String> namedGraphURIs)
- {
- this.namedGraphURIs = namedGraphURIs ;
+ public void setInitialBinding(QuerySolution binding) {
+ throw new UnsupportedOperationException(
+ "Initial bindings not supported for remote queries, consider using a ParameterizedSparqlString to prepare a query for remote execution");
}
-
+
+ public void setInitialBindings(ResultSet table) {
+ throw new UnsupportedOperationException(
+ "Initial bindings not supported for remote queries, consider using a ParameterizedSparqlString to prepare a query for remote execution");
+ }
+
+ /**
+ * @param defaultGraphURIs
+ * The defaultGraphURIs to set.
+ */
+ public void setDefaultGraphURIs(List<String> defaultGraphURIs) {
+ this.defaultGraphURIs = defaultGraphURIs;
+ }
+
+ /**
+ * @param namedGraphURIs
+ * The namedGraphURIs to set.
+ */
+ public void setNamedGraphURIs(List<String> namedGraphURIs) {
+ this.namedGraphURIs = namedGraphURIs;
+ }
+
/**
* Sets whether the HTTP request will specify Accept-Encoding: gzip
*/
- public void setAllowGZip(boolean allowed)
- {
- allowGZip = allowed;
+ public void setAllowGZip(boolean allowed) {
+ allowGZip = allowed;
}
-
+
/**
* Sets whether the HTTP requests will specify Accept-Encoding: deflate
*/
- public void setAllowDeflate(boolean allowed)
- {
- allowDeflate = allowed;
- }
-
- public void addParam(String field, String value)
- {
- if ( params == null )
- params = new Params() ;
- params.addParam(field, value) ;
- }
-
- /** @param defaultGraph The defaultGraph to add. */
- public void addDefaultGraph(String defaultGraph)
- {
- if ( defaultGraphURIs == null )
- defaultGraphURIs = new ArrayList<String>() ;
- defaultGraphURIs.add(defaultGraph) ;
- }
-
- /** @param name The URI to add. */
- public void addNamedGraph(String name)
- {
- if ( namedGraphURIs == null )
- namedGraphURIs = new ArrayList<String>() ;
- namedGraphURIs.add(name) ;
+ public void setAllowDeflate(boolean allowed) {
+ allowDeflate = allowed;
}
-
+
+ public void addParam(String field, String value) {
+ if (params == null)
+ params = new Params();
+ params.addParam(field, value);
+ }
+
/**
- * Gets whether basic authentication credentials have been provided
- * @return True if basic authentication credentials have been provided
+ * @param defaultGraph
+ * The defaultGraph to add.
+ */
+ public void addDefaultGraph(String defaultGraph) {
+ if (defaultGraphURIs == null)
+ defaultGraphURIs = new ArrayList<String>();
+ defaultGraphURIs.add(defaultGraph);
+ }
+
+ /**
+ * @param name
+ * The URI to add.
+ */
+ public void addNamedGraph(String name) {
+ if (namedGraphURIs == null)
+ namedGraphURIs = new ArrayList<String>();
+ namedGraphURIs.add(name);
+ }
+
+ /**
+ * Gets whether an authentication mechanism has been provided.
+ * <p>
+ * Even if this returns false authentication may still be used if the
+ * default authenticator applies, this is controlled via the
+ * {@link HttpOp#setDefaultAuthenticator(HttpAuthenticator)} method
+ * </p>
+ *
+ * @return True if an authenticator has been provided
*/
public boolean isUsingBasicAuthentication() {
- return this.user != null || this.password != null;
+ return this.authenticator != null;
}
-
- /** Set user and password for basic authentication.
- * After the request is made (one of the exec calls), the application
- * can overwrite the password array to remove details of the secret.
+
+ /**
+ * Set user and password for basic authentication. After the request is made
+ * (one of the exec calls), the application can overwrite the password array
+ * to remove details of the secret.
+ * <p>
+ * Note that it may be more flexible to
+ * </p>
+ *
* @param user
* @param password
*/
- public void setBasicAuthentication(String user, char[] password)
- {
- this.user = user ;
- this.password = password ;
- }
-
- @Override
- public ResultSet execSelect()
- {
- HttpQuery httpQuery = makeHttpQuery() ;
- httpQuery.setAccept(selectContentType) ;
- InputStream in = httpQuery.exec() ;
-
- if ( false )
- {
- byte b[] = IO.readWholeFile(in) ;
- String str = new String(b) ;
- System.out.println(str) ;
- in = new ByteArrayInputStream(b) ;
+ public void setBasicAuthentication(String user, char[] password) {
+ this.authenticator = new SimpleAuthenticator(user, password);
+ }
+
+ /**
+ * Sets the HTTP authenticator to use, if none is set then the default
+ * authenticator is used. This may be configured via the
+ * {@link HttpOp#setDefaultAuthenticator(HttpAuthenticator)} method.
+ *
+ * @param authenticator
+ * HTTP authenticator
+ */
+ public void setAuthenticator(HttpAuthenticator authenticator) {
+ this.authenticator = authenticator;
+ }
+
+ @Override
+ public ResultSet execSelect() {
+ HttpQuery httpQuery = makeHttpQuery();
+ httpQuery.setAccept(selectContentType);
+ InputStream in = httpQuery.exec();
+
+ if (false) {
+ byte b[] = IO.readWholeFile(in);
+ String str = new String(b);
+ System.out.println(str);
+ in = new ByteArrayInputStream(b);
}
-
+
retainedConnection = in; // This will be closed on close()
-
- //TODO: Find a way to auto-detect how to create the ResultSet based on the content type in use
-
- //Don't assume the endpoint actually gives back the content type we asked for
+
+ // TODO: Find a way to auto-detect how to create the ResultSet based on
+ // the content type in use
+
+ // Don't assume the endpoint actually gives back the content type we
+ // asked for
String actualContentType = httpQuery.getContentType();
-
- //If the server fails to return a Content-Type then we will assume
- //the server returned the type we asked for
- if (actualContentType == null || actualContentType.equals(""))
- {
- actualContentType = selectContentType;
+
+ // If the server fails to return a Content-Type then we will assume
+ // the server returned the type we asked for
+ if (actualContentType == null || actualContentType.equals("")) {
+ actualContentType = selectContentType;
}
-
+
if (actualContentType.equals(WebContent.contentTypeResultsXML))
return ResultSetFactory.fromXML(in);
if (actualContentType.equals(WebContent.contentTypeResultsJSON))
- return ResultSetFactory.fromJSON(in);
+ return ResultSetFactory.fromJSON(in);
if (actualContentType.equals(WebContent.contentTypeTextTSV))
return ResultSetFactory.fromTSV(in);
if (actualContentType.equals(WebContent.contentTypeTextCSV))
return CSVInput.fromCSV(in);
- throw new QueryException("Endpoint returned Content-Type: " + actualContentType + " which is not currently supported for SELECT queries");
+ throw new QueryException("Endpoint returned Content-Type: " + actualContentType
+ + " which is not currently supported for SELECT queries");
}
@Override
- public Model execConstruct() { return execConstruct(GraphFactory.makeJenaDefaultModel()) ; }
-
+ public Model execConstruct() {
+ return execConstruct(GraphFactory.makeJenaDefaultModel());
+ }
+
@Override
- public Model execConstruct(Model model) { return execModel(model) ; }
-
+ public Model execConstruct(Model model) {
+ return execModel(model);
+ }
+
@Override
- public Iterator<Triple> execConstructTriples() { return execTriples() ; }
+ public Iterator<Triple> execConstructTriples() {
+ return execTriples();
+ }
@Override
- public Model execDescribe() { return execDescribe(GraphFactory.makeJenaDefaultModel()) ; }
-
+ public Model execDescribe() {
+ return execDescribe(GraphFactory.makeJenaDefaultModel());
+ }
+
@Override
- public Model execDescribe(Model model) { return execModel(model) ; }
-
+ public Model execDescribe(Model model) {
+ return execModel(model);
+ }
+
@Override
- public Iterator<Triple> execDescribeTriples() { return execTriples() ; }
+ public Iterator<Triple> execDescribeTriples() {
+ return execTriples();
+ }
- private Model execModel(Model model)
- {
- HttpQuery httpQuery = makeHttpQuery() ;
- httpQuery.setAccept(modelContentType) ;
- InputStream in = httpQuery.exec() ;
-
- //Don't assume the endpoint actually gives back the content type we asked for
+ private Model execModel(Model model) {
+ HttpQuery httpQuery = makeHttpQuery();
+ httpQuery.setAccept(modelContentType);
+ InputStream in = httpQuery.exec();
+
+ // Don't assume the endpoint actually gives back the content type we
+ // asked for
String actualContentType = httpQuery.getContentType();
-
- //If the server fails to return a Content-Type then we will assume
- //the server returned the type we asked for
- if (actualContentType == null || actualContentType.equals(""))
- {
- actualContentType = modelContentType;
+
+ // If the server fails to return a Content-Type then we will assume
+ // the server returned the type we asked for
+ if (actualContentType == null || actualContentType.equals("")) {
+ actualContentType = modelContentType;
}
-
- //Try to select language appropriately here based on the model content type
+
+ // Try to select language appropriately here based on the model content
+ // type
Lang lang = WebContent.contentTypeToLang(actualContentType);
- if (! RDFLanguages.isTriples(lang))
- throw new QueryException("Endpoint returned Content Type: " + actualContentType + " which is not a valid RDF Graph syntax");
- RDFDataMgr.read(model, in, lang) ;
- this.close() ;
- return model ;
- }
-
- private Iterator<Triple> execTriples()
- {
- HttpQuery httpQuery = makeHttpQuery() ;
- httpQuery.setAccept(modelContentType) ;
- InputStream in = httpQuery.exec() ;
-
- //Don't assume the endpoint actually gives back the content type we asked for
+ if (!RDFLanguages.isTriples(lang))
+ throw new QueryException("Endpoint returned Content Type: " + actualContentType
+ + " which is not a valid RDF Graph syntax");
+ RDFDataMgr.read(model, in, lang);
+ this.close();
+ return model;
+ }
+
+ private Iterator<Triple> execTriples() {
+ HttpQuery httpQuery = makeHttpQuery();
+ httpQuery.setAccept(modelContentType);
+ InputStream in = httpQuery.exec();
+
+ // Don't assume the endpoint actually gives back the content type we
+ // asked for
String actualContentType = httpQuery.getContentType();
-
- //If the server fails to return a Content-Type then we will assume
- //the server returned the type we asked for
- if (actualContentType == null || actualContentType.equals(""))
- {
+
+ // If the server fails to return a Content-Type then we will assume
+ // the server returned the type we asked for
+ if (actualContentType == null || actualContentType.equals("")) {
actualContentType = modelContentType;
}
-
- //Try to select language appropriately here based on the model content type
+
+ // Try to select language appropriately here based on the model content
+ // type
Lang lang = WebContent.contentTypeToLang(actualContentType);
- if (! RDFLanguages.isTriples(lang))
- throw new QueryException("Endpoint returned Content Type: " + actualContentType + " which is not a valid RDF Graph syntax");
-
+ if (!RDFLanguages.isTriples(lang))
+ throw new QueryException("Endpoint returned Content Type: " + actualContentType
+ + " which is not a valid RDF Graph syntax");
+
return RiotReader.createIteratorTriples(in, lang, null);
}
-
+
@Override
- public boolean execAsk()
- {
- HttpQuery httpQuery = makeHttpQuery() ;
- httpQuery.setAccept(askContentType) ;
- InputStream in = httpQuery.exec() ;
+ public boolean execAsk() {
+ HttpQuery httpQuery = makeHttpQuery();
+ httpQuery.setAccept(askContentType);
+ InputStream in = httpQuery.exec();
try {
- //Don't assume the endpoint actually gives back the content type we asked for
+ // Don't assume the endpoint actually gives back the content type we
+ // asked for
String actualContentType = httpQuery.getContentType();
-
- //If the server fails to return a Content-Type then we will assume
- //the server returned the type we asked for
- if (actualContentType == null || actualContentType.equals(""))
- {
- actualContentType = askContentType;
+
+ // If the server fails to return a Content-Type then we will assume
+ // the server returned the type we asked for
+ if (actualContentType == null || actualContentType.equals("")) {
+ actualContentType = askContentType;
}
Lang lang = WebContent.contentTypeToLang(actualContentType);
- if (! RDFLanguages.isTriples(lang))
+ if (!RDFLanguages.isTriples(lang))
- //Parse the result appropriately depending on the selected content type
- if (actualContentType.equals(WebContent.contentTypeResultsXML))
- return XMLInput.booleanFromXML(in) ;
+ // Parse the result appropriately depending on the selected
+ // content type
+ if (actualContentType.equals(WebContent.contentTypeResultsXML))
+ return XMLInput.booleanFromXML(in);
if (actualContentType.equals(WebContent.contentTypeResultsJSON))
- return JSONInput.booleanFromJSON(in) ;
+ return JSONInput.booleanFromJSON(in);
if (actualContentType.equals(WebContent.contentTypeTextTSV))
- return TSVInput.booleanFromTSV(in);
+ return TSVInput.booleanFromTSV(in);
if (actualContentType.equals(WebContent.contentTypeTextCSV))
- return CSVInput.booleanFromCSV(in);
- throw new QueryException("Endpoint returned Content-Type: " + actualContentType + " which is not currently supported for ASK queries");
+ return CSVInput.booleanFromCSV(in);
+ throw new QueryException("Endpoint returned Content-Type: " + actualContentType
+ + " which is not currently supported for ASK queries");
} finally {
// Ensure connection is released
- try { in.close(); }
- catch (java.io.IOException e) { log.warn("Failed to close connection", e); }
+ try {
+ in.close();
+ } catch (java.io.IOException e) {
+ log.warn("Failed to close connection", e);
+ }
}
}
@Override
- public Context getContext() { return context ; }
-
- @Override public Dataset getDataset() { return null ; }
+ public Context getContext() {
+ return context;
+ }
+
+ @Override
+ public Dataset getDataset() {
+ return null;
+ }
- // This may be null - if we were created form a query string,
+ // This may be null - if we were created form a query string,
// we don't guarantee to parse it so we let through non-SPARQL
- // extensions to the far end.
- @Override public Query getQuery() { return query ; }
-
+ // extensions to the far end.
+ @Override
+ public Query getQuery() {
+ return query;
+ }
+
@Override
- public void setTimeout(long readTimeout)
- {
+ public void setTimeout(long readTimeout) {
this.readTimeout = readTimeout;
this.readTimeoutUnit = TimeUnit.MILLISECONDS;
}
@Override
- public void setTimeout(long readTimeout, long connectTimeout)
- {
+ public void setTimeout(long readTimeout, long connectTimeout) {
this.readTimeout = readTimeout;
this.readTimeoutUnit = TimeUnit.MILLISECONDS;
this.connectTimeout = connectTimeout;
this.connectTimeoutUnit = TimeUnit.MILLISECONDS;
}
-
@Override
- public void setTimeout(long readTimeout, TimeUnit timeoutUnits)
- {
+ public void setTimeout(long readTimeout, TimeUnit timeoutUnits) {
this.readTimeout = readTimeout;
this.readTimeoutUnit = timeoutUnits;
}
@Override
- public void setTimeout(long timeout1, TimeUnit timeUnit1, long timeout2, TimeUnit timeUnit2)
- {
+ public void setTimeout(long timeout1, TimeUnit timeUnit1, long timeout2, TimeUnit timeUnit2) {
this.readTimeout = timeout1;
this.readTimeoutUnit = timeUnit1;
this.connectTimeout = timeout2;
this.connectTimeoutUnit = timeUnit2;
}
-
+
@Override
- public long getTimeout1() { return asMillis(readTimeout, readTimeoutUnit) ; }
-
+ public long getTimeout1() {
+ return asMillis(readTimeout, readTimeoutUnit);
+ }
+
@Override
- public long getTimeout2() { return asMillis(connectTimeout, connectTimeoutUnit) ; }
-
+ public long getTimeout2() {
+ return asMillis(connectTimeout, connectTimeoutUnit);
+ }
+
/**
- * Gets whether HTTP requests will indicate to the remote server that GZip encoding of responses is accepted
+ * Gets whether HTTP requests will indicate to the remote server that GZip
+ * encoding of responses is accepted
+ *
* @return True if GZip encoding will be accepted
*/
- public boolean getAllowGZip() { return allowGZip; }
-
+ public boolean getAllowGZip() {
+ return allowGZip;
+ }
+
/**
- * Gets whether HTTP requests will indicate to the remote server that Deflate encoding of responses is accepted
+ * Gets whether HTTP requests will indicate to the remote server that
+ * Deflate encoding of responses is accepted
+ *
* @return True if Deflate encoding will be accepted
*/
- public boolean getAllowDeflate() { return allowDeflate; }
+ public boolean getAllowDeflate() {
+ return allowDeflate;
+ }
+
+ private static long asMillis(long duration, TimeUnit timeUnit) {
+ return (duration < 0) ? duration : timeUnit.toMillis(duration);
+ }
+
+ private HttpQuery makeHttpQuery() {
+ if (finished)
+ throw new ARQException("HTTP execution already closed");
+
+ HttpQuery httpQuery = new HttpQuery(service);
+ httpQuery.merge(getServiceParams(service, context));
+ httpQuery.addParam(HttpParams.pQuery, queryString);
+
+ for (Iterator<String> iter = defaultGraphURIs.iterator(); iter.hasNext();) {
+ String dft = iter.next();
+ httpQuery.addParam(HttpParams.pDefaultGraph, dft);
+ }
+ for (Iterator<String> iter = namedGraphURIs.iterator(); iter.hasNext();) {
+ String name = iter.next();
+ httpQuery.addParam(HttpParams.pNamedGraph, name);
+ }
+
+ if (params != null)
+ httpQuery.merge(params);
- private static long asMillis(long duration, TimeUnit timeUnit)
- {
- return (duration < 0 ) ? duration : timeUnit.toMillis(duration) ;
- }
-
- private HttpQuery makeHttpQuery()
- {
- // Also need to tie to ResultSet returned which is streamed back if StAX.
- if ( finished )
- throw new ARQException("HTTP execution already closed") ;
-
- HttpQuery httpQuery = new HttpQuery(service) ;
- httpQuery.merge(getServiceParams(service, context)) ;
- httpQuery.addParam(HttpParams.pQuery, queryString );
-
- for ( Iterator<String> iter = defaultGraphURIs.iterator() ; iter.hasNext() ; )
- {
- String dft = iter.next() ;
- httpQuery.addParam(HttpParams.pDefaultGraph, dft) ;
- }
- for ( Iterator<String> iter = namedGraphURIs.iterator() ; iter.hasNext() ; )
- {
- String name = iter.next() ;
- httpQuery.addParam(HttpParams.pNamedGraph, name) ;
- }
-
- if ( params != null )
- httpQuery.merge(params) ;
-
if (allowGZip)
- httpQuery.setAllowGZip(true);
+ httpQuery.setAllowGZip(true);
if (allowDeflate)
- httpQuery.setAllowDeflate(true);
-
- httpQuery.setBasicAuthentication(user, password) ;
-
- //Apply timeouts
- if (connectTimeout > 0)
- {
- httpQuery.setConnectTimeout((int)connectTimeoutUnit.toMillis(connectTimeout));
- }
- if (readTimeout > 0)
- {
- httpQuery.setReadTimeout((int)readTimeoutUnit.toMillis(readTimeout));
- }
-
- return httpQuery ;
- }
-
-
- // This is to allow setting additional/optional query parameters on a per SERVICE level, see: JENA-195
- protected static Params getServiceParams(String serviceURI, Context context) throws QueryExecException
- {
+ httpQuery.setAllowDeflate(true);
+
+ httpQuery.setAuthenticator(this.authenticator);
+
+ // Apply timeouts
+ if (connectTimeout > 0) {
+ httpQuery.setConnectTimeout((int) connectTimeoutUnit.toMillis(connectTimeout));
+ }
+ if (readTimeout > 0) {
+ httpQuery.setReadTimeout((int) readTimeoutUnit.toMillis(readTimeout));
+ }
+
+ return httpQuery;
+ }
+
+ // This is to allow setting additional/optional query parameters on a per
+ // SERVICE level, see: JENA-195
+ protected static Params getServiceParams(String serviceURI, Context context) throws QueryExecException {
Params params = new Params();
@SuppressWarnings("unchecked")
- Map<String, Map<String,List<String>>> serviceParams = (Map<String, Map<String,List<String>>>)context.get(ARQ.serviceParams) ;
- if ( serviceParams != null )
- {
- Map<String,List<String>> paramsMap = serviceParams.get(serviceURI) ;
- if ( paramsMap != null )
- {
- for (String param : paramsMap.keySet())
- {
- if ( HttpParams.pQuery.equals(param) )
- throw new QueryExecException("ARQ serviceParams overrides the 'query' SPARQL protocol parameter") ;
-
- List<String> values = paramsMap.get(param) ;
- for (String value : values)
- params.addParam(param, value) ;
+ Map<String, Map<String, List<String>>> serviceParams = (Map<String, Map<String, List<String>>>) context
+ .get(ARQ.serviceParams);
+ if (serviceParams != null) {
+ Map<String, List<String>> paramsMap = serviceParams.get(serviceURI);
+ if (paramsMap != null) {
+ for (String param : paramsMap.keySet()) {
+ if (HttpParams.pQuery.equals(param))
+ throw new QueryExecException("ARQ serviceParams overrides the 'query' SPARQL protocol parameter");
+
+ List<String> values = paramsMap.get(param);
+ for (String value : values)
+ params.addParam(param, value);
}
- }
+ }
}
return params;
}
- public void cancel() { finished = true ; }
-
+ /**
+ * Cancel query evaluation
+ */
+ public void cancel() {
+ finished = true;
+ }
+
@Override
- public void abort() { try { close() ; } catch (Exception ex) {} }
+ public void abort() {
+ try {
+ close();
+ } catch (Exception ex) {
+ log.warn("Error during abort", ex);
+ }
+ }
@Override
public void close() {
- finished = true ;
+ finished = true;
if (retainedConnection != null) {
- try { retainedConnection.close(); }
- catch (java.io.IOException e) { log.warn("Failed to close connection", e); }
- finally { retainedConnection = null; }
+ try {
+ retainedConnection.close();
+ } catch (java.io.IOException e) {
+ log.warn("Failed to close connection", e);
+ } finally {
+ retainedConnection = null;
+ }
}
}
-// public boolean isActive() { return false ; }
-
+ // public boolean isActive() { return false ; }
+
@Override
- public String toString()
- {
- HttpQuery httpQuery = makeHttpQuery() ;
- return "GET "+httpQuery.toString() ;
+ public String toString() {
+ HttpQuery httpQuery = makeHttpQuery();
+ return "GET " + httpQuery.toString();
}
-
+
/**
- * Sets the Content Type for SELECT queries provided that the format is supported
+ * Sets the Content Type for SELECT queries provided that the format is
+ * supported
+ *
* @param contentType
*/
- public void setSelectContentType(String contentType)
- {
- boolean ok = false;
- for (String supportedType : supportedSelectContentTypes)
- {
- if (supportedType.equals(contentType))
- {
- ok = true;
- break;
- }
- }
- if (!ok) throw new IllegalArgumentException("Given Content Type '" + contentType + "' is not a supported SELECT results format");
- selectContentType = contentType;
+ public void setSelectContentType(String contentType) {
+ boolean ok = false;
+ for (String supportedType : supportedSelectContentTypes) {
+ if (supportedType.equals(contentType)) {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok)
+ throw new IllegalArgumentException("Given Content Type '" + contentType
+ + "' is not a supported SELECT results format");
+ selectContentType = contentType;
}
-
+
/**
- * Sets the Content Type for ASK queries provided that the format is supported
+ * Sets the Content Type for ASK queries provided that the format is
+ * supported
+ *
* @param contentType
*/
- public void setAskContentType(String contentType)
- {
- boolean ok = false;
- for (String supportedType : supportedAskContentTypes)
- {
- if (supportedType.equals(contentType))
- {
- ok = true;
- break;
- }
- }
- if (!ok) throw new IllegalArgumentException("Given Content Type '" + contentType + "' is not a supported ASK results format");
- askContentType = contentType;
+ public void setAskContentType(String contentType) {
+ boolean ok = false;
+ for (String supportedType : supportedAskContentTypes) {
+ if (supportedType.equals(contentType)) {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok)
+ throw new IllegalArgumentException("Given Content Type '" + contentType + "' is not a supported ASK results format");
+ askContentType = contentType;
}
-
+
/**
- * Sets the Content Type for CONSTRUCT/DESCRIBE queries provided that the format is supported
+ * Sets the Content Type for CONSTRUCT/DESCRIBE queries provided that the
+ * format is supported
+ *
* @param contentType
*/
- public void setModelContentType(String contentType)
- {
+ public void setModelContentType(String contentType) {
// Check that this is a valid setting
- Lang lang = WebContent.contentTypeToLang(contentType) ;
- if (lang == null)
- throw new IllegalArgumentException("Given Content Type '" + contentType + "' is not supported by RIOT") ;
- if (!RDFLanguages.isTriples(lang))
- throw new IllegalArgumentException("Given Content Type '" + contentType + "' is not a RDF Graph format") ;
- modelContentType = contentType ;
+ Lang lang = WebContent.contentTypeToLang(contentType);
+ if (lang == null)
+ throw new IllegalArgumentException("Given Content Type '" + contentType + "' is not supported by RIOT");
+ if (!RDFLanguages.isTriples(lang))
+ throw new IllegalArgumentException("Given Content Type '" + contentType + "' is not a RDF Graph format");
+ modelContentType = contentType;
}
}
Modified: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryExceptionHTTP.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryExceptionHTTP.java?rev=1497583&r1=1497582&r2=1497583&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryExceptionHTTP.java (original)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/engine/http/QueryExceptionHTTP.java Thu Jun 27 22:14:09 2013
@@ -18,6 +18,8 @@
package com.hp.hpl.jena.sparql.engine.http;
+import org.apache.jena.atlas.web.HttpException;
+
import com.hp.hpl.jena.query.QueryException ;
/** Exception class for all operations in the SPARQL client library.
@@ -86,6 +88,12 @@ public class QueryExceptionHTTP extends
this.responseMessage = msg ;
}
+ public QueryExceptionHTTP(int responseCode, String message, Throwable cause) {
+ super(message, cause);
+ this.responseCode = responseCode;
+ }
+
+
@Override
public String toString()
{
Modified: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/modify/UpdateProcessRemote.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/modify/UpdateProcessRemote.java?rev=1497583&r1=1497582&r2=1497583&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/modify/UpdateProcessRemote.java (original)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/modify/UpdateProcessRemote.java Thu Jun 27 22:14:09 2013
@@ -54,7 +54,9 @@ public class UpdateProcessRemote extends
// Build endpoint URL
String endpoint = this.getEndpoint();
String querystring = this.getQueryString();
- endpoint = endpoint.contains("?") ? endpoint + "&" + querystring : endpoint + "?" + querystring;
+ if (querystring != null && !querystring.equals("")) {
+ endpoint = endpoint.contains("?") ? endpoint + "&" + querystring : endpoint + "?" + querystring;
+ }
// Execution
String reqStr = this.getUpdateRequest().toString() ;
Modified: jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/HttpException.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/HttpException.java?rev=1497583&r1=1497582&r2=1497583&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/HttpException.java (original)
+++ jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/HttpException.java Thu Jun 27 22:14:09 2013
@@ -39,6 +39,10 @@ public class HttpException extends Runti
super(message, cause);
}
+ public HttpException(Throwable cause) {
+ super(cause);
+ }
+
/**
* Gets the response code, may be -1 if unknown
* @return Response Code if known, -1 otherwise
Added: jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/ApacheModAuthFormLogin.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/ApacheModAuthFormLogin.java?rev=1497583&view=auto
==============================================================================
--- jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/ApacheModAuthFormLogin.java (added)
+++ jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/ApacheModAuthFormLogin.java Thu Jun 27 22:14:09 2013
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.atlas.web.auth;
+
+/**
+ * Represents form login credentials where form logins are against Apache
+ * mod_auth_form secured servers using default form field configuration
+ *
+ */
+public class ApacheModAuthFormLogin extends FormLogin {
+
+ private static final String APACHE_MOD_AUTH_FORM_USER_FIELD = "httpd_username";
+ private static final String APACHE_MOD_AUTH_FORM_PASSWORD_FIELD = "httpd_password";
+
+ /**
+ * Creates new form login credentials
+ *
+ * @param loginFormURL
+ * Login Form URL
+ * @param username
+ * User name
+ * @param password
+ * Password
+ */
+ public ApacheModAuthFormLogin(String loginFormURL, String username, char[] password) {
+ super(loginFormURL, APACHE_MOD_AUTH_FORM_USER_FIELD, APACHE_MOD_AUTH_FORM_PASSWORD_FIELD, username, password);
+ }
+}
Added: jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/FormLogin.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/FormLogin.java?rev=1497583&view=auto
==============================================================================
--- jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/FormLogin.java (added)
+++ jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/FormLogin.java Thu Jun 27 22:14:09 2013
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.atlas.web.auth;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.message.BasicNameValuePair;
+
+/**
+ * Represents form login credentials
+ *
+ */
+public class FormLogin {
+
+ private String loginForm, loginUserField, loginPasswordField, username;
+ private char[] password;
+
+ /**
+ * Creates new form login credentials
+ *
+ * @param loginFormURL
+ * Login Form URL
+ * @param loginUserField
+ * Login Form User field name
+ * @param loginPasswordField
+ * Login Form Password field name
+ * @param username
+ * User name
+ * @param password
+ * Password
+ */
+ public FormLogin(String loginFormURL, String loginUserField, String loginPasswordField, String username, char[] password) {
+ this.loginForm = loginFormURL;
+ this.loginUserField = loginUserField;
+ this.loginPasswordField = loginPasswordField;
+ this.username = username;
+ this.password = password;
+ }
+
+ /**
+ * Gets the login form URL
+ *
+ * @return Login Form URL
+ */
+ public String getLoginFormURL() {
+ return this.loginForm;
+ }
+
+ /**
+ * Gets the HTTP Entity for the Login request
+ *
+ * @return Login request entity
+ * @throws UnsupportedEncodingException
+ * Thrown if the platform does not support UTF-8
+ */
+ public HttpEntity getLoginEntity() throws UnsupportedEncodingException {
+ List<NameValuePair> nvps = new ArrayList<NameValuePair>();
+ nvps.add(new BasicNameValuePair(this.loginUserField, this.username));
+ nvps.add(new BasicNameValuePair(this.loginPasswordField, new String(this.password)));
+
+ return new UrlEncodedFormEntity(nvps, "UTF-8");
+ }
+}
Added: jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/FormsAuthenticator.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/FormsAuthenticator.java?rev=1497583&view=auto
==============================================================================
--- jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/FormsAuthenticator.java (added)
+++ jena/trunk/jena-arq/src/main/java/org/apache/jena/atlas/web/auth/FormsAuthenticator.java Thu Jun 27 22:14:09 2013
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.web.auth;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.AbstractHttpClient;
+import org.apache.http.impl.client.BasicCookieStore;
+import org.apache.http.protocol.HttpContext;
+import org.apache.jena.atlas.web.HttpException;
+
+/**
+ * An authenticator capable of making Form based logins and using cookies to
+ * maintain authentication state
+ *
+ */
+public class FormsAuthenticator implements HttpAuthenticator {
+
+ private Map<URI, CookieStore> cookies = new HashMap<URI, CookieStore>();
+ private Map<URI, FormLogin> logins = new HashMap<URI, FormLogin>();
+
+ /**
+ * Creates a new authenticator with the given login
+ * @param target Target URI
+ * @param login Login
+ */
+ public FormsAuthenticator(URI target, FormLogin login) {
+ if (target == null) throw new IllegalArgumentException("Target URI cannot be null");
+ this.logins.put(target, login);
+ }
+
+ /**
+ * Creates a new authenticator with the given logins
+ * @param logins Logins
+ */
+ public FormsAuthenticator(Map<URI, FormLogin> logins) {
+ this.logins.putAll(logins);
+ }
+
+ @Override
+ public synchronized void apply(AbstractHttpClient client, HttpContext httpContext, URI target) {
+ if (client == null)
+ return;
+
+ synchronized (this.cookies) {
+ if (this.cookies.containsKey(target)) {
+ // Use existing cookies
+ CookieStore store = this.cookies.get(target);
+ if (store != null)
+ client.setCookieStore(store);
+ return;
+ }
+ }
+
+ // Do we have a login available for the target server?
+ FormLogin login = this.logins.get(target);
+ if (login == null)
+ return;
+
+ // Use a fresh Cookie Store for new login attempts
+ CookieStore store = new BasicCookieStore();
+ client.setCookieStore(store);
+
+ try {
+ // Try to login
+ HttpPost post = new HttpPost(login.getLoginFormURL());
+ post.setEntity(login.getLoginEntity());
+ HttpResponse response = client.execute(post, httpContext);
+
+ // Check for successful login
+ if (response.getStatusLine().getStatusCode() >= 400) {
+ throw new HttpException(response.getStatusLine().getStatusCode(), "Login attempt failed - "
+ + response.getStatusLine().getReasonPhrase());
+ }
+
+ // Otherwise assume a successful login
+ synchronized (this.cookies) {
+ this.cookies.put(target, client.getCookieStore());
+ }
+
+ } catch (UnsupportedEncodingException e) {
+ throw new HttpException("UTF-8 encoding not supported on your platform", e);
+ } catch (IOException e) {
+ throw new HttpException("Error making login request", e);
+ }
+ }
+
+ /**
+ * Adds a login to the authenticator, if the authenticator had previously logged into the given URI cookies for that URI are discarded
+ * @param target Target URI
+ * @param login Login
+ */
+ public void addLogin(URI target, FormLogin login) {
+ if (target == null) throw new IllegalArgumentException("Target URI cannot be null");
+ this.logins.put(target, login);
+ synchronized (this.cookies) {
+ this.cookies.remove(target);
+ }
+ }
+
+}