Search in sources :

Example 1 with SequenceAdapter

use of org.exist.extensions.exquery.restxq.impl.adapters.SequenceAdapter in project exist by eXist-db.

the class ResourceFunctionExecutorImpl method execute.

@Override
public Sequence execute(final ResourceFunction resourceFunction, final Iterable<TypedArgumentValue> arguments, final HttpRequest request) throws RestXqServiceException {
    final RestXqServiceCompiledXQueryCache cache = RestXqServiceCompiledXQueryCacheImpl.getInstance();
    CompiledXQuery xquery = null;
    ProcessMonitor processMonitor = null;
    try (final DBBroker broker = getBrokerPool().getBroker()) {
        // ensure we can execute the function before going any further
        checkSecurity(broker, resourceFunction.getXQueryLocation());
        // get a compiled query service from the cache
        xquery = cache.getCompiledQuery(broker, resourceFunction.getXQueryLocation());
        // find the function that we will execute
        final UserDefinedFunction fn = findFunction(xquery, resourceFunction.getFunctionSignature());
        final XQueryContext xqueryContext = xquery.getContext();
        // set the request object - can later be used by the EXQuery Request Module
        xqueryContext.setAttribute(EXQ_REQUEST_ATTR, request);
        // TODO this is a workaround?
        declareVariables(xqueryContext);
        // START workaround: evaluate global variables in modules, as they are reset by XQueryContext.reset()
        final Expression rootExpr = xqueryContext.getRootExpression();
        for (int i = 0; i < rootExpr.getSubExpressionCount(); i++) {
            final Expression subExpr = rootExpr.getSubExpression(i);
            if (subExpr instanceof VariableDeclaration) {
                subExpr.eval(null);
            }
        }
        // END workaround
        // setup monitoring
        processMonitor = broker.getBrokerPool().getProcessMonitor();
        xqueryContext.getProfiler().traceQueryStart();
        processMonitor.queryStarted(xqueryContext.getWatchDog());
        // create a function call
        try (final FunctionReference fnRef = new FunctionReference(new FunctionCall(xqueryContext, fn))) {
            // convert the arguments
            final org.exist.xquery.value.Sequence[] fnArgs = convertToExistFunctionArguments(xqueryContext, fn, arguments);
            // execute the function call
            fnRef.analyze(new AnalyzeContextInfo());
            // if setUid/setGid, determine the effectiveSubject to use for execution
            final Optional<EffectiveSubject> effectiveSubject = getEffectiveSubject(xquery);
            try {
                // switch to effective user if setUid/setGid
                effectiveSubject.ifPresent(broker::pushSubject);
                final org.exist.xquery.value.Sequence result = fnRef.evalFunction(null, null, fnArgs);
                // copy for closure
                final CompiledXQuery xquery1 = xquery;
                // return a sequence adapter which returns the query when it is finished with the results
                return new SequenceAdapter(result, () -> {
                    if (xquery1 != null) {
                        // return the compiled query to the pool
                        cache.returnCompiledQuery(resourceFunction.getXQueryLocation(), xquery1);
                    }
                });
            } finally {
                // switch back from effective user if setUid/setGid
                if (effectiveSubject.isPresent()) {
                    broker.popSubject();
                }
            }
        }
    } catch (final URISyntaxException | EXistException | XPathException | PermissionDeniedException use) {
        // if an error occurred we should return the compiled query
        if (xquery != null) {
            // return the compiled query to the pool
            cache.returnCompiledQuery(resourceFunction.getXQueryLocation(), xquery);
        }
        throw new RestXqServiceException(use.getMessage(), use);
    } finally {
        // clear down monitoring
        if (processMonitor != null) {
            xquery.getContext().getProfiler().traceQueryEnd(xquery.getContext());
            processMonitor.queryCompleted(xquery.getContext().getWatchDog());
        }
    }
}
Also used : RestXqServiceCompiledXQueryCache(org.exist.extensions.exquery.restxq.RestXqServiceCompiledXQueryCache) RestXqServiceException(org.exquery.restxq.RestXqServiceException) SequenceAdapter(org.exist.extensions.exquery.restxq.impl.adapters.SequenceAdapter) URISyntaxException(java.net.URISyntaxException) FunctionReference(org.exist.xquery.value.FunctionReference) EffectiveSubject(org.exist.security.EffectiveSubject) org.exist.xquery(org.exist.xquery) ValueSequence(org.exist.xquery.value.ValueSequence) Sequence(org.exquery.xquery.Sequence) EXistException(org.exist.EXistException) ProcessMonitor(org.exist.storage.ProcessMonitor) DBBroker(org.exist.storage.DBBroker) PermissionDeniedException(org.exist.security.PermissionDeniedException)

Aggregations

URISyntaxException (java.net.URISyntaxException)1 EXistException (org.exist.EXistException)1 RestXqServiceCompiledXQueryCache (org.exist.extensions.exquery.restxq.RestXqServiceCompiledXQueryCache)1 SequenceAdapter (org.exist.extensions.exquery.restxq.impl.adapters.SequenceAdapter)1 EffectiveSubject (org.exist.security.EffectiveSubject)1 PermissionDeniedException (org.exist.security.PermissionDeniedException)1 DBBroker (org.exist.storage.DBBroker)1 ProcessMonitor (org.exist.storage.ProcessMonitor)1 org.exist.xquery (org.exist.xquery)1 FunctionReference (org.exist.xquery.value.FunctionReference)1 ValueSequence (org.exist.xquery.value.ValueSequence)1 RestXqServiceException (org.exquery.restxq.RestXqServiceException)1 Sequence (org.exquery.xquery.Sequence)1