Package com.hp.hpl.jena.sparql.engine.http

Source Code of com.hp.hpl.jena.sparql.engine.http.HttpQuery

/*
* 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 com.hp.hpl.jena.sparql.engine.http;

import java.io.InputStream ;
import java.net.MalformedURLException ;
import java.net.URL ;
import java.util.concurrent.TimeUnit ;
import java.util.regex.Pattern ;

import org.apache.http.client.HttpClient ;
import org.apache.http.conn.params.ConnManagerPNames ;
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.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 ;

/**
* 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.
*/
@SuppressWarnings("deprecation")
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;

    // 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;
    private HttpClient client;

    // 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);
    }

    /**
     * Create a execution object for a whole model GET
     *
     * @param url
     *            The model
     */
    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;

        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;
    }

    /**
     * Set the content type (Accept header) for the results
     *
     * @param contentType
     *            Accept content type
     */
    public void setAccept(String contentType) {
        contentTypeResult = contentType;
    }

    /**
     * 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;
    }

    /**
     * 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;
    }

    /**
     * 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;
    }

    /**
     * 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;
    }

    /**
     * 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.setAuthenticator(new SimpleAuthenticator(user, password));
    }

    /**
     * Sets the authenticator to use
     * @param authenticator Authenticator
     */
    public void setAuthenticator(HttpAuthenticator authenticator) {
        this.authenticator = authenticator;
    }
   
    /**
     * Gets the HTTP client that is being used, may be null if no request has yet been made
     * @return HTTP Client or null
     */
    public HttpClient getClient() {
        return this.client;
    }

    /**
     * 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
     */

    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;
    }

    /**
     * Gets the HTTP Connection timeout
     *
     * @return Connection Timeout
     */
    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;
    }

    /**
     * Gets the HTTP Read timeout
     *
     * @return Read Timeout
     */
    public int getReadTimeout() {
        return readTimeout;
    }

    /**
     * Execute the operation
     *
     * @return Model The resulting model
     * @throws QueryExceptionHTTP
     */
    public InputStream exec() throws QueryExceptionHTTP {
        try {
            if (usesPOST())
                return execPost();
            return execGet();
        } catch (QueryExceptionHTTP httpEx) {
            log.trace("Exception in exec", httpEx);
            throw httpEx;
        } catch (JenaException jEx) {
            log.trace("JenaException in exec", jEx);
            throw jEx;
        }
    }

    private InputStream execGet() throws QueryExceptionHTTP {
        URL target = null;
        String qs = getQueryString();

        ARQ.getHttpRequestLogger().trace(qs);

        try {
            if (count() == 0)
                target = new URL(serviceURL);
            else
                target = new URL(serviceURL + (serviceParams ? "&" : "?") + qs);
        } catch (MalformedURLException malEx) {
            throw new QueryExceptionHTTP(0, "Malformed URL: " + malEx);
        }
        log.trace("GET " + target.toExternalForm());

        try {
            try {
                this.client = new SystemDefaultHttpClient();
               
                // Always apply a 10 second timeout to obtaining a connection lease from HTTP Client
                // This prevents a potential lock up
                this.client.getParams().setLongParameter(ConnManagerPNames.TIMEOUT, TimeUnit.SECONDS.toMillis(10));
               
                // If user has specified time outs apply them now
                if (this.connectTimeout > 0)
                    this.client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, this.connectTimeout);
                if (this.readTimeout > 0)
                    this.client.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, this.readTimeout);
               
                // Enable compression support appropriately
                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);
                }
               
                // Get the actual response stream
                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
                if (httpEx.getResponseCode() == 414)
                    return execPost();
                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());
        }
    }

    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 {
            this.client = new SystemDefaultHttpClient();
           
            // Always apply a 10 second timeout to obtaining a connection lease from HTTP Client
            // This prevents a potential lock up
            this.client.getParams().setLongParameter(ConnManagerPNames.TIMEOUT, TimeUnit.SECONDS.toMillis(10));
           
            // If user has specified time outs apply them now
            if (this.connectTimeout > 0)
                this.client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, this.connectTimeout);
            if (this.readTimeout > 0)
                this.client.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, this.readTimeout);
           
            // Enable compression support appropriately
            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);
                this.client = new DecompressingHttpClient(client);
            }

            // Get the actual response stream
            TypedInputStream stream = HttpOp.execHttpPostFormStream(serviceURL, this, contentTypeResult, client, context, 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());
        }
    }

    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;
    }
}
TOP

Related Classes of com.hp.hpl.jena.sparql.engine.http.HttpQuery

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.