Package org.apache.jena.fuseki.servlets

Source Code of org.apache.jena.fuseki.servlets.SPARQL_Query$HttpActionQuery

/*
* 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.fuseki.servlets;

import static java.lang.String.format ;
import static org.apache.jena.fuseki.HttpNames.paramAccept ;
import static org.apache.jena.fuseki.HttpNames.paramCallback ;
import static org.apache.jena.fuseki.HttpNames.paramDefaultGraphURI ;
import static org.apache.jena.fuseki.HttpNames.paramForceAccept ;
import static org.apache.jena.fuseki.HttpNames.paramNamedGraphURI ;
import static org.apache.jena.fuseki.HttpNames.paramOutput1 ;
import static org.apache.jena.fuseki.HttpNames.paramOutput2 ;
import static org.apache.jena.fuseki.HttpNames.paramQuery ;
import static org.apache.jena.fuseki.HttpNames.paramQueryRef ;
import static org.apache.jena.fuseki.HttpNames.paramStyleSheet ;
import static org.apache.jena.fuseki.HttpNames.paramTimeout ;

import java.io.IOException ;
import java.io.InputStream ;
import java.util.Arrays ;
import java.util.Enumeration ;
import java.util.HashSet ;
import java.util.Set ;

import javax.servlet.http.HttpServletRequest ;
import javax.servlet.http.HttpServletResponse ;

import org.apache.jena.fuseki.FusekiException ;
import org.apache.jena.fuseki.FusekiLib ;
import org.apache.jena.fuseki.HttpNames ;
import org.apache.jena.fuseki.http.HttpSC ;
import org.apache.jena.fuseki.migrate.WebIO ;
import org.apache.jena.fuseki.server.DatasetRef ;
import org.openjena.atlas.io.IO ;
import org.openjena.atlas.io.IndentedLineBuffer ;
import org.openjena.atlas.web.MediaType ;
import org.openjena.riot.WebContent ;

import com.hp.hpl.jena.query.Dataset ;
import com.hp.hpl.jena.query.Query ;
import com.hp.hpl.jena.query.QueryException ;
import com.hp.hpl.jena.query.QueryExecution ;
import com.hp.hpl.jena.query.QueryExecutionFactory ;
import com.hp.hpl.jena.query.QueryFactory ;
import com.hp.hpl.jena.query.QueryParseException ;
import com.hp.hpl.jena.query.ResultSet ;
import com.hp.hpl.jena.query.Syntax ;
import com.hp.hpl.jena.rdf.model.Model ;
import com.hp.hpl.jena.sparql.core.DatasetDescription ;
import com.hp.hpl.jena.sparql.resultset.SPARQLResult ;

public abstract class SPARQL_Query extends SPARQL_Protocol
{
    protected class HttpActionQuery extends HttpActionProtocol {
       
        // Used if the protocol or query has a dataset description.
        DatasetDescription datasetDesc = null ;
       
        public HttpActionQuery(long id, DatasetRef desc, HttpServletRequest request, HttpServletResponse response, boolean verbose)
        {
            super(id, desc, request, response, verbose) ;
        }
    }
   
    public SPARQL_Query(boolean verbose)
    { super(PlainRequestFlag.DIFFERENT, verbose) ; }

   
    public SPARQL_Query()
    { this(false) ; }

    // Choose REST verbs to support.
   
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    { doCommon(request, response) ; }
   
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    { doCommon(request, response) ; }

    // HEAD
   
    @Override
    protected void doOptions(HttpServletRequest request, HttpServletResponse response)
    {
        //response.setHeader(HttpNames.hAllow, "GET,HEAD,OPTIONS,POST");
        response.setHeader(HttpNames.hAllow, "GET,OPTIONS,POST");
        response.setHeader(HttpNames.hContentLengh, "0") ;
    }
   
    @Override
    protected final void perform(long id, DatasetRef desc, HttpServletRequest request, HttpServletResponse response)
    {
        validate(request) ;
        HttpActionQuery action = new HttpActionQuery(id, desc, request, response, verbose_debug) ;
        // GET
        if ( request.getMethod().equals(HttpNames.METHOD_GET) )
        {
            executeWithParameter(action) ;
            return ;
        }

        MediaType ct = FusekiLib.contentType(request) ;
        String incoming = ct.getContentType() ;
       
        // POST application/sparql-query
        if (WebContent.contentTypeSPARQLQuery.equals(incoming))
        {
            executeBody(action) ;
            return ;
        }
        // POST application/x-www-form-url
        if (WebContent.contentTypeForm.equals(incoming))
        {
            executeWithParameter(action) ;
            return ;
        }

        error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415, "Bad content type: "+incoming) ;
    }

    // All the params we support
    private static String[] params_ = { paramQuery, paramDefaultGraphURI, paramNamedGraphURI,
                                        paramQueryRef,
                                        paramStyleSheet,
                                        paramAccept,
                                        paramOutput1, paramOutput2,
                                        paramCallback,
                                        paramForceAccept,
                                        paramTimeout } ;
    protected static Set<String> allParams = new HashSet<String>(Arrays.asList(params_)) ;
    /** Called to validate arguments */
    protected abstract void validate(HttpServletRequest request) ;
   
    /** Helper for validating request */
    protected void validate(HttpServletRequest request, Set<String> params)
    {
        MediaType ct = FusekiLib.contentType(request) ;
        boolean mustHaveQueryParam = true ;
        if ( ct != null )
        {
            String incoming = ct.getContentType() ;
           
            if ( WebContent.contentTypeSPARQLQuery.equals(incoming) )
            {
                mustHaveQueryParam = false ;
                //error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415, "Unofficial "+WebContent.contentTypeSPARQLQuery+" not supported") ;
            }
            else if ( WebContent.contentTypeForm.equals(incoming) ) {}
            else
                error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415, "Unsupported: "+incoming) ;
        }
       
        // GET/POST of a form at this point.
       
        if ( mustHaveQueryParam )
        {
            // application/sparql-query does not use a query param.
            String queryStr = request.getParameter(HttpNames.paramQuery) ;
           
            if ( queryStr == null )
                errorBadRequest("SPARQL Query: No query specified (no 'query=' found)") ;
            if ( queryStr.isEmpty() )
                errorBadRequest("SPARQL Query: Empty query string") ;
        }

        if ( params != null )
        {
            @SuppressWarnings("unchecked")
            Enumeration<String> en = request.getParameterNames() ;
            for ( ; en.hasMoreElements() ; )
            {
                String name = en.nextElement() ;
                if ( ! params.contains(name) )
                    warning("SPARQL Query: Unrecognize request parameter (ignored): "+name) ;
            }
        }
    }

    private void executeWithParameter(HttpActionQuery action)
    {
        String queryString = action.request.getParameter(paramQuery) ;
        execute(queryString, action) ;
    }

    private void executeBody(HttpActionQuery action)
    {
        String queryString = null ;
        try {
            InputStream input = action.request.getInputStream() ;
            queryString = IO.readWholeFileAsUTF8(input) ;
        }
        catch (IOException ex) { errorOccurred(ex) ; }
        execute(queryString, action) ;
    }

    private void execute(String queryString, HttpActionQuery action)
    {
        String queryStringLog = formatForLog(queryString) ;
        log.info(format("[%d] Query = %s", action.id, queryStringLog));

        Query query = null ;
        try {
            // NB syntax is ARQ (a superset of SPARQL)
            query = QueryFactory.create(queryString, Syntax.syntaxARQ) ;
            queryStringLog = formatForLog(query) ;
        }
        catch (QueryParseException ex) { errorBadRequest("Parse error: \n"+queryString +"\n\r" + messageForQPE(ex)) ; }
        // Should not happen.
        catch (QueryException ex) { errorBadRequest("Error: \n"+queryString +"\n\r" + ex.getMessage()) ; }
        validateQuery(action, query) ;
       
        // Assumes finished whole thing by end of sendResult.
        action.beginRead() ;
        try {
            SPARQLResult result = executeQuery(action, query, queryStringLog) ;
            sendResults(action, result) ;
        } finally { action.endRead() ; }
    }

    /** Check the query - throw ActionErrorException or call super.error* */
    protected abstract void validateQuery(HttpActionQuery action, Query query) ;

    protected QueryExecution createQueryExecution(Query query, Dataset dataset)
    {
        return QueryExecutionFactory.create(query, dataset) ;
    }

    protected SPARQLResult executeQuery(HttpActionQuery action, Query query, String queryStringLog)
    {
        Dataset dataset = decideDataset(action, query, queryStringLog) ;
        QueryExecution qexec = createQueryExecution(query, dataset) ;
        setAnyTimeouts(qexec, action);

        if ( query.isSelectType() )
        {
            ResultSet rs = qexec.execSelect() ;
           
            // Force some query execution now.
            // Do this to force the query to do something that should touch any underlying database,
            // and hence ensure the communications layer is working.
            // MySQL can time out after 8 hours of an idle connection
            rs.hasNext() ;

//            // Not necessary if we are inside a read lock until the end of sending results.
//            rs = ResultSetFactory.copyResults(rs) ;

            log.info(format("[%d] OK/select", action.id)) ;
            return new SPARQLResult(rs) ;
        }

        if ( query.isConstructType() )
        {
            Model model = qexec.execConstruct() ;
            log.info(format("[%d] OK/construct", action.id)) ;
            return new SPARQLResult(model) ;
        }

        if ( query.isDescribeType() )
        {
            Model model = qexec.execDescribe() ;
            log.info(format("[%d] OK/describe",action.id)) ;
            return new SPARQLResult(model) ;
        }

        if ( query.isAskType() )
        {
            boolean b = qexec.execAsk() ;
            log.info(format("[%d] OK/ask",action.id)) ;
            return new SPARQLResult(b) ;
        }

        errorBadRequest("Unknown query type - "+queryStringLog) ;
        return null ;
    }

    private void setAnyTimeouts(QueryExecution qexec, HttpActionQuery action) {
        if (!(action.getDatasetRef().allowTimeoutOverride))
            return;

        long desiredTimeout = Long.MAX_VALUE;
        String timeoutHeader = action.request.getHeader("Timeout");
        String timeoutParameter = action.request.getParameter("timeout");
        if (timeoutHeader != null) {
            try {
                desiredTimeout = (int) Float.parseFloat(timeoutHeader) * 1000;
            } catch (NumberFormatException e) {
                throw new FusekiException("Timeout header must be a number", e);
            }
        } else if (timeoutParameter != null) {
            try {
                desiredTimeout = (int) Float.parseFloat(timeoutParameter) * 1000;
            } catch (NumberFormatException e) {
                throw new FusekiException("timeout parameter must be a number", e);
            }
        }

        desiredTimeout = Math.min(action.getDatasetRef().maximumTimeoutOverride, desiredTimeout);
        if (desiredTimeout != Long.MAX_VALUE)
            qexec.setTimeout(desiredTimeout);
    }

    protected abstract Dataset decideDataset(HttpActionQuery action, Query query, String queryStringLog) ;

    protected void sendResults(HttpActionQuery action, SPARQLResult result)
    {
        if ( result.isResultSet() )
            ResponseResultSet.doResponseResultSet(result.getResultSet(), null, action.request, action.response) ;
        else if ( result.isGraph() )
            ResponseModel.doResponseModel(result.getModel(), action.request, action.response) ;
        else if ( result.isBoolean() )
            // Make different?
            ResponseResultSet.doResponseResultSet(null, result.getBooleanResult(), action.request, action.response) ;
        else
            errorOccurred("Unknown or invalid result type") ;
    }
   
    private String formatForLog(Query query)
    {
        IndentedLineBuffer out = new IndentedLineBuffer() ;
        out.setFlatMode(true) ;
        query.serialize(out) ;
        return out.asString() ;
    }
       
    /**
     * @param queryURI
     * @return
     */
    private String getRemoteString(String queryURI)
    {
        return WebIO.exec_get(queryURI) ;
    }

}
TOP

Related Classes of org.apache.jena.fuseki.servlets.SPARQL_Query$HttpActionQuery

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.