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

Source Code of com.hp.hpl.jena.sparql.engine.QueryExecutionBase

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

import java.util.HashMap ;
import java.util.HashSet ;
import java.util.Iterator ;
import java.util.List ;
import java.util.Map ;
import java.util.Set ;
import java.util.concurrent.TimeUnit ;

import org.openjena.atlas.lib.AlarmClock ;
import org.openjena.atlas.lib.Callback ;
import org.openjena.atlas.lib.Pingback ;
import org.openjena.atlas.logging.Log ;

import com.hp.hpl.jena.graph.Node ;
import com.hp.hpl.jena.graph.Triple ;
import com.hp.hpl.jena.n3.IRIResolver ;
import com.hp.hpl.jena.query.ARQ ;
import com.hp.hpl.jena.query.Dataset ;
import com.hp.hpl.jena.query.Query ;
import com.hp.hpl.jena.query.QueryExecException ;
import com.hp.hpl.jena.query.QueryExecution ;
import com.hp.hpl.jena.query.QuerySolution ;
import com.hp.hpl.jena.query.ResultSet ;
import com.hp.hpl.jena.rdf.model.Model ;
import com.hp.hpl.jena.rdf.model.ModelFactory ;
import com.hp.hpl.jena.rdf.model.RDFNode ;
import com.hp.hpl.jena.rdf.model.Resource ;
import com.hp.hpl.jena.rdf.model.Statement ;
import com.hp.hpl.jena.shared.PrefixMapping ;
import com.hp.hpl.jena.sparql.ARQConstants ;
import com.hp.hpl.jena.sparql.core.DatasetGraph ;
import com.hp.hpl.jena.sparql.core.describe.DescribeHandler ;
import com.hp.hpl.jena.sparql.core.describe.DescribeHandlerRegistry ;
import com.hp.hpl.jena.sparql.engine.binding.Binding ;
import com.hp.hpl.jena.sparql.engine.binding.BindingRoot ;
import com.hp.hpl.jena.sparql.engine.binding.BindingUtils ;
import com.hp.hpl.jena.sparql.engine.iterator.QueryIteratorBase ;
import com.hp.hpl.jena.sparql.engine.iterator.QueryIteratorWrapper ;
import com.hp.hpl.jena.sparql.graph.GraphFactory ;
import com.hp.hpl.jena.sparql.syntax.ElementGroup ;
import com.hp.hpl.jena.sparql.syntax.Template ;
import com.hp.hpl.jena.sparql.util.Context ;
import com.hp.hpl.jena.sparql.util.DatasetUtils ;
import com.hp.hpl.jena.sparql.util.ModelUtils ;
import com.hp.hpl.jena.sparql.util.NodeFactory ;
import com.hp.hpl.jena.util.FileManager ;

/** All the SPARQL query result forms made from a graph-level execution object */

public class QueryExecutionBase implements QueryExecution
{
    // Pull over the "build dataset code"
    // Initial bindings.
    // Split : QueryExecutionGraph already has the dataset.

    private Query              query ;
    private Dataset            dataset ;
    private QueryEngineFactory qeFactory ;
    private QueryIterator      queryIterator = null ;
    private Plan               plan = null ;
    private Context            context ;
    private FileManager        fileManager = FileManager.get() ;
    private QuerySolution      initialBinding = null ;     

    // has cancel() been called?
    private volatile boolean   cancel = false ;
   
    public QueryExecutionBase(Query query,
                              Dataset dataset,
                              Context context,
                              QueryEngineFactory qeFactory)
    {
        this.query = query ;
        this.dataset = dataset ;
        this.context = context ;
        this.qeFactory = qeFactory ;
        init() ;
    }
   
    private void init()
    {
        DatasetGraph dsg = (dataset == null) ? null : dataset.asDatasetGraph() ;
        context = Context.setupContext(context, dsg) ;
        if ( query != null )
            context.put(ARQConstants.sysCurrentQuery, query) ;
        setAnyTimeouts() ;
    }
   
    // Put any per-dataset execution global configuration state here.
    public static Context setupContext(Context context, DatasetGraph dataset)
    {
        if ( context == null )
            context = ARQ.getContext() ;    // Already copied?
        context = context.copy() ;

        if ( dataset != null && dataset.getContext() != null )
            // Copy per-dataset settings.
            context.putAll(dataset.getContext()) ;
       
        context.set(ARQConstants.sysCurrentTime, NodeFactory.nowAsDateTime()) ;
       
        // Allocators.
//        context.set(ARQConstants.sysVarAllocNamed, new VarAlloc(ARQConstants.allocVarMarkerExec)) ;
//        context.set(ARQConstants.sysVarAllocAnon,  new VarAlloc(ARQConstants.allocVarAnonMarkerExec)) ;
        // Add VarAlloc for variables and bNodes (this is not the parse name).
        // More added later e.g. query (if there is a query), algebra form (in setOp)
       
        return context ;
    }
   
    private void setAnyTimeouts()
    {
        if ( context.isDefined(ARQ.queryTimeout) )
        {
            Object obj = context.get(ARQ.queryTimeout) ;
            if ( obj instanceof Number )
            {
                long x = ((Number)obj).longValue() ;
                //System.err.println("timeout("+x+")") ;
                setTimeout(x) ;
            } else if ( obj instanceof String )
            {
                try {
                    String str = obj.toString() ;
                    if ( str.contains(",") )
                    {
                        String[] a = str.split(",") ;
                        long x1 = Long.parseLong(a[0]) ;
                        long x2 = Long.parseLong(a[1]) ;
                        //System.err.println("timeout("+x1+", "+x2+")") ;
                        setTimeout(x1, x2) ;
                    }
                    else
                    {
                        long x = Long.parseLong(str) ;
                        //System.err.println("timeout("+x+")") ;
                        setTimeout(x) ;
                    }
                } catch (RuntimeException ex) { Log.warn(this, "Can't interpret string for timeout: "+obj) ; }
            }
            else
                Log.warn(this, "Can't interpret timeout: "+obj) ;
        }
    }
   
    // Old, synchronous code.
    // Delete when we are sure cancellation is stable.
//    public void abort()
//    {
//        abort = true ;
//        if ( queryIterator != null )
//            queryIterator.abort() ;
//        cancel = true ;
//    }

    @Override
    public void close()
    {
        if ( queryIterator != null )
            queryIterator.close() ;
        if ( plan != null )
            plan.close() ;
        cancelPingback() ;
    }

    @Deprecated
    public static boolean cancelAllowDrain = false ;
    //public synchronized void cancel()
    @Override
    public synchronized void abort()
  {
      // This is called asynchronously to the execution.
        // synchronized is for coordination with other calls of .abort.
    if ( queryIterator != null )
    {
      // we cancel the chain of iterators, however, we do *not* close the iterators.
      // That happens after the cancellation is properly over.
        if ( cancelAllowDrain && queryIterator instanceof QueryIteratorBase )
        {
            QueryIteratorBase qIter = (QueryIteratorBase)queryIterator ;
            qIter.cancelAllowContinue() ;
        }
        else
            // Normal case - correct SPARQL
            queryIterator.cancel() ;
      cancel = true ;
    }
        cancel = true ;
  }
   
    @Override
    public ResultSet execSelect()
    {
        if ( ! query.isSelectType() )
            throw new QueryExecException("Attempt to have ResultSet from a "+labelForQuery(query)+" query") ;
        return execResultSet() ;
    }

    // Construct
    @Override
    public Model execConstruct()
    {
        return execConstruct(GraphFactory.makeJenaDefaultModel()) ;
    }

//  TODO: enable this?
//    /**
//     * Executes as a construct query, placing the results into a newly constructed {@link com.hp.hpl.jena.sparql.graph.GraphDistinctDataBag}.
//     * The threshold policy is set from the current context.
//     */
//    @Override
//    public Model execConstructDataBag()
//    {
//        ThresholdPolicy<Triple> thresholdPolicy = ThresholdPolicyFactory.policyFromContext(context);
//        return execConstruct(GraphFactory.makeDataBagModel(thresholdPolicy)) ;
//    }
 
    @Override
    public Model execConstruct(Model model)
    {
        if ( ! query.isConstructType() )
            throw new QueryExecException("Attempt to get a CONSTRUCT model from a "+labelForQuery(query)+" query") ;
        // This causes there to be no PROJECT around the pattern.
        // That in turn, exposes the initial bindings. 
        query.setQueryResultStar(true) ;

        startQueryIterator() ;
       
        // Prefixes for result
        insertPrefixesInto(model) ;
        Template template = query.getConstructTemplate() ;

        // Build each template substitution as triples.
        for ( ; queryIterator.hasNext() ; )
        {
            Set<Triple> set = new HashSet<Triple>() ;
            Map<Node, Node> bNodeMap = new HashMap<Node, Node>() ;
            Binding binding = queryIterator.nextBinding() ;
            template.subst(set, bNodeMap, binding) ;

            // Convert and merge into Model.
            for ( Iterator<Triple> iter = set.iterator() ; iter.hasNext() ; )
            {
                Triple t = iter.next() ;
                Statement stmt = ModelUtils.tripleToStatement(model, t) ;
                if ( stmt != null )
                    model.add(stmt) ;
            }
        }
        this.close() ;
        return model ;
    }

    @Override
    public Model execDescribe()
    { return execDescribe(GraphFactory.makeJenaDefaultModel()) ; }


    @Override
    public Model execDescribe(Model model)
    {
        if ( ! query.isDescribeType() )
            throw new QueryExecException("Attempt to get a DESCRIBE result from a "+labelForQuery(query)+" query") ;
        //Was: query.setQueryResultStar(true) ; but why?
        query.setResultVars() ;
        // If there was no WhereClause, use an empty pattern (one solution, no columns).
        if ( query.getQueryPattern() == null )
            query.setQueryPattern(new ElementGroup()) ;
       
        Set<RDFNode> set = new HashSet<RDFNode>() ;

        //May return null (no query pattern)
        ResultSet qRes = execResultSet() ;

        // Prefixes for result (after initialization)
        insertPrefixesInto(model) ;
        if ( qRes != null )
        {
            for ( ; qRes.hasNext() ; )
            {
                QuerySolution rb = qRes.nextSolution() ;
                for ( String varName : query.getResultVars() )
                {
                    RDFNode n = rb.get(varName) ;
                    set.add(n) ;
                }
            }
            this.close() ;
        }

        if ( query.getResultURIs() != null )
        {
            // Any URIs in the DESCRIBE
            for (Node n : query.getResultURIs())
            {
                // Need to make dataset available to describe handlers.
                RDFNode rNode = ModelUtils.convertGraphNodeToRDFNode(n, dataset.getDefaultModel()) ;
                set.add(rNode) ;
            }
        }

        // Create new handlers for this process.
        List<DescribeHandler> dhList = DescribeHandlerRegistry.get().newHandlerList() ;

        getContext().put(ARQConstants.sysCurrentDataset, getDataset()) ;
        // Notify start of describe phase
        for (DescribeHandler dh : dhList)
            dh.start(model, getContext()) ;

        // Do describe for each resource found.
        for (Iterator<RDFNode> iter = set.iterator() ; iter.hasNext() ;)
        {
            RDFNode n = iter.next() ;

            if ( n instanceof Resource )
            {
                for (DescribeHandler dh : dhList)
                    dh.describe((Resource)n) ;
            }
            else
                // Can't describe literals
                continue ;
        }

        for (DescribeHandler dh : dhList)
            dh.finish() ;

        this.close() ;
        return model ;
    }

    @Override
    public boolean execAsk()
    {
        if ( ! query.isAskType() )
            throw new QueryExecException("Attempt to have boolean from a "+labelForQuery(query)+" query") ;

        startQueryIterator() ;
        boolean r = queryIterator.hasNext() ;
        this.close() ;
        return r ;
    }

    @Override
    public void setTimeout(long timeout, TimeUnit timeUnit)
    {
        long x = asMillis(timeout, timeUnit) ;
        this.timeout1 = x ;
        this.timeout2 = TIMEOUT_UNSET ;
    }

    @Override
    public void setTimeout(long timeout)
    {
        setTimeout(timeout, TimeUnit.MILLISECONDS) ;
    }

    @Override
    public void setTimeout(long timeout1, TimeUnit timeUnit1, long timeout2, TimeUnit timeUnit2)
    {
        long x1 = asMillis(timeout1, timeUnit1) ;
        long x2 = asMillis(timeout2, timeUnit2) ;
        this.timeout1 = x1 ;
        if ( timeout2 < 0 )
            this.timeout2 = TIMEOUT_INF ;
        else
            this.timeout2 = x2 ;
    }

    @Override
    public void setTimeout(long timeout1, long timeout2)
    {
        setTimeout(timeout1, TimeUnit.MILLISECONDS, timeout2, TimeUnit.MILLISECONDS) ;
    }

    private static long asMillis(long duration, TimeUnit timeUnit)
    {
        return (duration < 0 ) ? duration : timeUnit.toMillis(duration) ;
    }
   
    private static final long TIMEOUT_UNSET = -1 ;
    private static final long TIMEOUT_INF = -2 ;
    private long timeout1 = TIMEOUT_UNSET ;
    private long timeout2 = TIMEOUT_UNSET ;
   
    private static AlarmClock alarmClock = AlarmClock.get() ;
    private static final Callback<QueryExecution> callback =
        new Callback<QueryExecution>() {
            @Override
            public void proc(QueryExecution qExec)
            {
                qExec.abort() ;
               
            }
        } ;
       
    private Pingback<QueryExecution> pingback = null ;
   
    private void initTimeout1()
    {
        if ( timeout1 == TIMEOUT_UNSET ) return ;
       
        if ( pingback != null )
            alarmClock.reset(pingback, timeout1) ;
        else
            pingback = alarmClock.add(callback, this, timeout1) ;
        return ;
        // Second timeout done by wrapping the iterator.
    }
   
    private QueryIterator initTimeout2(QueryIterator queryIterator)
    {
        if ( timeout2 < 0 && timeout2 != TIMEOUT_INF )
            return queryIterator ;
        // Wrap with a resetter.
        return new QueryIteratorWrapper(queryIterator)
        {
            boolean resetDone = false ;
            @Override
            protected Binding moveToNextBinding()
            {
                Binding b = super.moveToNextBinding() ;
                //System.out.println(b) ;
                if ( ! resetDone )
                {
                    //System.out.printf("Reset timer: ==> %d\n", timeout2) ;
                    if ( pingback == null )
                    {
                        if ( timeout2 > 0 )
                            // No first timeout - finite second timeout.
                            pingback = alarmClock.add(callback, QueryExecutionBase.this, timeout2) ;
                    }
                    else
                    {
                        // We have moved for the first time.
                        // Reset the timer if finite timeout else cancel.
                        if ( timeout2 < 0 )
                            alarmClock.cancel(pingback) ;
                        else
                            pingback = alarmClock.reset(pingback, timeout2) ;
                    }
                    resetDone = true ;
                }
                return b ;
            }
        };
    }
   
    private void cancelPingback()
    {
        if ( pingback != null )
            alarmClock.cancel(pingback) ;
    }
   
    protected final void execInit()
    { }

    private ResultSet asResultSet(QueryIterator qIter)
    {
        Model model = null ;
        if ( dataset != null )
            model = dataset.getDefaultModel() ;
        else
            model = ModelFactory.createDefaultModel() ;
       
        ResultSetStream rStream = new ResultSetStream(query.getResultVars(), model, qIter) ;
        return rStream ;
    }
   
    private void startQueryIterator()
    {
        execInit() ;
        if ( queryIterator != null )
            Log.warn(this, "Query iterator has already been started") ;
        initTimeout1() ;
        // We don't know if getPlan().iterator() does a lot of work or not
        // (ideally it shouldn't start executing the query but in some sub-systems
        // it might be necessary)
        queryIterator = getPlan().iterator() ;
        // Add the second timeout wrapper.
        queryIterator = initTimeout2(queryIterator) ;
        if ( cancel ) queryIterator.cancel() ;
    }
   
    private ResultSet execResultSet()
    {
        startQueryIterator() ;
        return asResultSet(queryIterator) ;
    }

    public Plan getPlan()
    {
        if ( plan == null )
        {
            DatasetGraph dsg = prepareDataset(dataset, query, fileManager) ;
            Binding inputBinding = null ;
            if ( initialBinding != null )
                inputBinding = BindingUtils.asBinding(initialBinding) ;
            if ( inputBinding == null )
                inputBinding = BindingRoot.create() ;

            plan = qeFactory.create(query, dsg, inputBinding, getContext()) ;
        }           
        return plan ;
    }

    private void insertPrefixesInto(Model model)
    {
        try {
            if ( dataset != null )
            {
                // Load the models prefixes first
                PrefixMapping m = dataset.getDefaultModel() ;
                model.setNsPrefixes(m) ;
            }
            // Then add the queries (just the declared mappings)
            // so the query declarations override the data sources.
            model.setNsPrefixes(query.getPrefixMapping()) ;

        } catch (Exception ex)
        {
            Log.warn(this, "Exception in insertPrefixes: "+ex.getMessage(), ex) ;
        }
    }

    static private String labelForQuery(Query q)
    {
        if ( q.isSelectType() )     return "SELECT" ;
        if ( q.isConstructType() )  return "CONSTRUCT" ;
        if ( q.isDescribeType() )   return "DESCRIBE" ;
        if ( q.isAskType() )        return "ASK" ;
        return "<<unknown>>" ;
    }

    @Override
    public Context getContext() { return context ; }
   
    @Override
    public Dataset getDataset() { return dataset ; }

    @Override
    public Query getQuery()     { return query ; }

    // Call after setFM called.
    private static DatasetGraph prepareDataset(Dataset dataset, Query query, FileManager fileManager)
    {
        if ( dataset != null )
            return dataset.asDatasetGraph() ;
       
        if ( ! query.hasDatasetDescription() )
            //Query.Log.warn(this, "No data for query (no URL, no model)");
            throw new QueryExecException("No dataset description for query");
       
        String baseURI = query.getBaseURI() ;
        if ( baseURI == null )
            baseURI = IRIResolver.chooseBaseURI() ;
       
        DatasetGraph dsg =
            DatasetUtils.createDatasetGraph(query.getGraphURIs(),
                                            query.getNamedGraphURIs(),
                                            fileManager, baseURI ) ;
        return dsg ;
    }

   
    @Override
    public void setFileManager(FileManager fm) { fileManager = fm ; }
   
    @Override
    public void setInitialBinding(QuerySolution startSolution)
    {
        initialBinding = startSolution ;
    }

   
    //protected QuerySolution getInputBindings() { return initialBinding ; }

    public void setInitialBindings(ResultSet table)
    { throw new UnsupportedOperationException("setInitialBindings(ResultSet)") ; }
}
TOP

Related Classes of com.hp.hpl.jena.sparql.engine.QueryExecutionBase

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.