Search in sources :

Example 1 with RestXqServiceException

use of org.exquery.restxq.RestXqServiceException 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)

Example 2 with RestXqServiceException

use of org.exquery.restxq.RestXqServiceException in project exist by eXist-db.

the class ResourceFunctionExecutorImpl method convertToType.

// TODO this needs to be abstracted into EXQuery library / or not, see the TODOs below
private <X> TypedValue<X> convertToType(final XQueryContext xqueryContext, final String argumentName, final TypedValue typedValue, final org.exquery.xquery.Type destinationType, final Class<X> underlyingDestinationClass) throws RestXqServiceException {
    // TODO consider changing Types that can be used as <T> to TypedValue to a set of interfaces for XDM types that
    // require absolute minimal implementation, and we provide some default or abstract implementations if possible
    final Item convertedValue;
    try {
        final int existDestinationType = TypeAdapter.toExistType(destinationType);
        final Item value;
        // Consider a factory or java.util.ServiceLoader pattern
        if (typedValue instanceof org.exquery.xdm.type.StringTypedValue) {
            value = new StringValue(((org.exquery.xdm.type.StringTypedValue) typedValue).getValue());
        } else if (typedValue instanceof org.exquery.xdm.type.Base64BinaryTypedValue) {
            value = BinaryValueFromInputStream.getInstance(xqueryContext, new Base64BinaryValueType(), ((org.exquery.xdm.type.Base64BinaryTypedValue) typedValue).getValue());
        } else {
            value = (Item) typedValue.getValue();
        }
        if (existDestinationType == value.getType()) {
            convertedValue = value;
        } else if (value instanceof AtomicValue) {
            convertedValue = value.convertTo(existDestinationType);
        } else {
            LOG.warn("Could not convert parameter '{}' from '{}' to '{}'.", argumentName, typedValue.getType().name(), destinationType.name());
            convertedValue = value;
        }
    } catch (final XPathException xpe) {
        // TODO define an ErrorCode
        throw new RestXqServiceException("TODO need to implement error code for problem with parameter conversion!: " + xpe.getMessage(), xpe);
    }
    return new TypedValue<X>() {

        @Override
        public org.exquery.xquery.Type getType() {
            // return destinationType;
            return TypeAdapter.toExQueryType(convertedValue.getType());
        }

        @Override
        public X getValue() {
            return (X) convertedValue;
        }
    };
}
Also used : RestXqServiceException(org.exquery.restxq.RestXqServiceException) org.exist.xquery(org.exist.xquery) Base64BinaryValueType(org.exist.xquery.value.Base64BinaryValueType) AtomicValue(org.exist.xquery.value.AtomicValue) Item(org.exist.xquery.value.Item) StringValue(org.exist.xquery.value.StringValue) TypedValue(org.exquery.xquery.TypedValue)

Example 3 with RestXqServiceException

use of org.exquery.restxq.RestXqServiceException in project exist by eXist-db.

the class RestXqServiceSerializerImpl method serializeNodeBody.

@Override
protected void serializeNodeBody(final Sequence result, final HttpResponse response, final Map<SerializationProperty, String> serializationProperties) throws RestXqServiceException {
    try (final DBBroker broker = getBrokerPool().getBroker();
        final Writer writer = new OutputStreamWriter(response.getOutputStream(), serializationProperties.get(SerializationProperty.ENCODING))) {
        final Properties outputProperties = serializationPropertiesToProperties(serializationProperties);
        final XQuerySerializer xqSerializer = new XQuerySerializer(broker, outputProperties, writer);
        xqSerializer.serialize(((SequenceAdapter) result).getExistSequence());
        writer.flush();
    } catch (IOException | XPathException | SAXException | EXistException ioe) {
        throw new RestXqServiceException("Error while serializing xml: " + ioe.toString(), ioe);
    }
}
Also used : DBBroker(org.exist.storage.DBBroker) RestXqServiceException(org.exquery.restxq.RestXqServiceException) XQuerySerializer(org.exist.util.serializer.XQuerySerializer) XPathException(org.exist.xquery.XPathException) OutputStreamWriter(java.io.OutputStreamWriter) IOException(java.io.IOException) EXistException(org.exist.EXistException) Properties(java.util.Properties) Writer(java.io.Writer) OutputStreamWriter(java.io.OutputStreamWriter) SAXException(org.xml.sax.SAXException)

Example 4 with RestXqServiceException

use of org.exquery.restxq.RestXqServiceException in project exist by eXist-db.

the class RestXqServlet method service.

@Override
protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
    // authenticate
    final Subject user = authenticate(request, response);
    if (user == null) {
        // "Permission denied: unknown user or password");
        return;
    }
    try (final DBBroker broker = getPool().get(Optional.of(user))) {
        final Configuration configuration = broker.getConfiguration();
        final HttpRequest requestAdapter = new HttpServletRequestAdapter(request, () -> (String) configuration.getProperty(Configuration.BINARY_CACHE_CLASS_PROPERTY));
        final RestXqService service = getRegistry().findService(requestAdapter);
        if (service != null) {
            if (log.isTraceEnabled()) {
                log.trace("Received {} request for \"{}\" and found Resource Function \"{}\" in  module \"{}\"", requestAdapter.getMethod().name(), requestAdapter.getPath(), service.getResourceFunction().getFunctionSignature(), service.getResourceFunction().getXQueryLocation());
            }
            service.service(requestAdapter, new HttpServletResponseAdapter(response), new ResourceFunctionExecutorImpl(getPool(), request.getContextPath() + request.getServletPath(), request.getRequestURI()), new RestXqServiceSerializerImpl(getPool()));
        } else {
            if (log.isTraceEnabled()) {
                log.trace("Received {} request for \"{}\" but no suitable Resource Function found!", requestAdapter.getMethod().name(), requestAdapter.getPath());
            }
            super.service(request, response);
        }
    } catch (final EXistException e) {
        getLog().error(e.getMessage(), e);
        throw new ServletException(e.getMessage(), e);
    } catch (final RestXqServiceException e) {
        if (e.getCause() instanceof PermissionDeniedException) {
            getAuthenticator().sendChallenge(request, response);
        } else {
            // TODO should probably be caught higher up and returned as a HTTP Response? maybe need two different types of exception to differentiate critical vs processing exception
            getLog().error(e.getMessage(), e);
            throw new ServletException(e.getMessage(), e);
        }
    }
}
Also used : HttpRequest(org.exquery.http.HttpRequest) HttpServletResponseAdapter(org.exist.extensions.exquery.restxq.impl.adapters.HttpServletResponseAdapter) RestXqServiceException(org.exquery.restxq.RestXqServiceException) Configuration(org.exist.util.Configuration) EXistException(org.exist.EXistException) Subject(org.exist.security.Subject) ServletException(javax.servlet.ServletException) RestXqService(org.exquery.restxq.RestXqService) DBBroker(org.exist.storage.DBBroker) HttpServletRequestAdapter(org.exist.extensions.exquery.restxq.impl.adapters.HttpServletRequestAdapter) PermissionDeniedException(org.exist.security.PermissionDeniedException)

Example 5 with RestXqServiceException

use of org.exquery.restxq.RestXqServiceException in project exist by eXist-db.

the class RestXqServiceCompiledXQueryCacheImpl method getCompiledQuery.

@Override
public CompiledXQuery getCompiledQuery(final DBBroker broker, final URI xqueryLocation) throws RestXqServiceException {
    final Queue<CompiledXQuery> queue = cache.get(xqueryLocation, key -> new MpmcAtomicArrayQueue<>(DEFAULT_MAX_QUERY_STACK_SIZE));
    CompiledXQuery xquery = queue.poll();
    if (xquery == null) {
        xquery = XQueryCompiler.compile(broker, xqueryLocation);
    } else {
        // prepare the context for re-use
        try {
            xquery.getContext().prepareForReuse();
        } catch (final XPathException e) {
            throw new RestXqServiceException("Unable to prepare compiled XQuery for reuse", e);
        }
    }
    xquery.getContext().prepareForExecution();
    return xquery;
}
Also used : RestXqServiceException(org.exquery.restxq.RestXqServiceException) XPathException(org.exist.xquery.XPathException) CompiledXQuery(org.exist.xquery.CompiledXQuery)

Aggregations

RestXqServiceException (org.exquery.restxq.RestXqServiceException)6 EXistException (org.exist.EXistException)3 DBBroker (org.exist.storage.DBBroker)3 XPathException (org.exist.xquery.XPathException)3 IOException (java.io.IOException)2 PermissionDeniedException (org.exist.security.PermissionDeniedException)2 Configuration (org.exist.util.Configuration)2 org.exist.xquery (org.exist.xquery)2 Base64BinaryValueType (org.exist.xquery.value.Base64BinaryValueType)2 StringValue (org.exist.xquery.value.StringValue)2 Sequence (org.exquery.xquery.Sequence)2 InputStream (java.io.InputStream)1 OutputStreamWriter (java.io.OutputStreamWriter)1 Writer (java.io.Writer)1 URISyntaxException (java.net.URISyntaxException)1 Properties (java.util.Properties)1 ServletException (javax.servlet.ServletException)1 CloseShieldInputStream (org.apache.commons.io.input.CloseShieldInputStream)1 DocumentImpl (org.exist.dom.memtree.DocumentImpl)1 RestXqServiceCompiledXQueryCache (org.exist.extensions.exquery.restxq.RestXqServiceCompiledXQueryCache)1