Search in sources :

Example 6 with Task

use of com.linkedin.parseq.Task in project rest.li by linkedin.

the class TestRestLiMethodInvocation method checkInvocation.

private void checkInvocation(Object resource, RequestContext requestContext, ResourceMethodDescriptor resourceMethodDescriptor, ResourceMethodConfig resourceMethodConfig, String httpMethod, ProtocolVersion version, String uri, String entityBody, MutablePathKeys pathkeys, final Callback<RestResponse> callback, final boolean isDebugMode, final boolean expectRoutingException, final RestLiAttachmentReader expectedRequestAttachments, final RestLiResponseAttachments expectedResponseAttachments) throws Exception {
    assertNotNull(resource);
    assertNotNull(resourceMethodDescriptor);
    try {
        EasyMock.replay(resource);
        RestRequestBuilder builder = new RestRequestBuilder(new URI(uri)).setMethod(httpMethod).addHeaderValue("Accept", "application/json").setHeader(RestConstants.HEADER_RESTLI_PROTOCOL_VERSION, version.toString());
        if (entityBody != null) {
            builder.setEntity(entityBody.getBytes(Data.UTF_8_CHARSET));
        }
        if (expectedResponseAttachments != null) {
            builder.addHeaderValue(RestConstants.HEADER_ACCEPT, RestConstants.HEADER_VALUE_MULTIPART_RELATED);
        }
        RestRequest request = builder.build();
        if (isDebugMode) {
            requestContext.putLocalAttr(RestLiMethodInvoker.ATTRIBUTE_PROMISE_LISTENER, new PromiseListener<Object>() {

                @Override
                public void onResolved(Promise<Object> promise) {
                    // PromiseListener is invoked with a task.
                    if (promise instanceof Task) {
                        requestContext.putLocalAttr(ATTRIBUTE_PARSEQ_TRACE, ((Task<?>) promise).getTrace());
                    }
                }
            });
        }
        final ServerResourceContext resourceContext = new ResourceContextImpl(pathkeys, request, requestContext);
        resourceContext.setRequestAttachmentReader(expectedRequestAttachments);
        if (expectedResponseAttachments != null) {
            resourceContext.setResponseAttachments(expectedResponseAttachments);
        }
        RoutingResult routingResult = new RoutingResult(resourceContext, resourceMethodDescriptor, resourceMethodConfig);
        RestLiArgumentBuilder argumentBuilder = _methodAdapterProvider.getArgumentBuilder(resourceMethodDescriptor.getType());
        RestLiRequestData requestData = argumentBuilder.extractRequestData(routingResult, entityBody != null && !entityBody.isEmpty() ? DataMapUtils.readMapWithExceptions(request) : null);
        FilterRequestContext filterContext = new FilterRequestContextInternalImpl(routingResult.getContext(), resourceMethodDescriptor, requestData);
        final CountDownLatch latch = new CountDownLatch(1);
        final CountDownLatch expectedRoutingExceptionLatch = new CountDownLatch(1);
        RestLiResponseHandler restLiResponseHandler = new RestLiResponseHandler(_methodAdapterProvider, _errorResponseBuilder);
        Callback<RestLiResponse> executionCallback = new Callback<RestLiResponse>() {

            @Override
            public void onError(Throwable e) {
                if (e.getCause() != null && e.getCause().getCause() instanceof RoutingException) {
                    expectedRoutingExceptionLatch.countDown();
                }
                if (callback != null) {
                    callback.onError(e);
                }
                Assert.assertEquals(resourceContext.getRequestAttachmentReader(), expectedRequestAttachments);
                Assert.assertEquals(resourceContext.getResponseAttachments(), expectedResponseAttachments);
                latch.countDown();
            }

            @Override
            public void onSuccess(final RestLiResponse result) {
                if (callback != null) {
                    callback.onSuccess(ResponseUtils.buildResponse(routingResult, result));
                }
                Assert.assertEquals(resourceContext.getResponseAttachments(), expectedResponseAttachments);
                latch.countDown();
            }
        };
        FilterChainDispatcher filterChainDispatcher = new FilterChainDispatcherImpl(routingResult, _invoker, argumentBuilder);
        FilterChainCallback filterChainCallback = new FilterChainCallbackImpl(routingResult, restLiResponseHandler, executionCallback, _errorResponseBuilder);
        final RestLiCallback outerCallback = new RestLiCallback(filterContext, new RestLiFilterResponseContextFactory(request, routingResult, restLiResponseHandler), new RestLiFilterChain(null, filterChainDispatcher, filterChainCallback));
        RestUtils.validateRequestHeadersAndUpdateResourceContext(request.getHeaders(), Collections.emptySet(), routingResult.getContext());
        _invoker.invoke(requestData, routingResult, argumentBuilder, outerCallback);
        try {
            latch.await();
            if (expectRoutingException) {
                expectedRoutingExceptionLatch.await();
            }
        } catch (InterruptedException e) {
        // Ignore
        }
        EasyMock.verify(resource);
        Assert.assertEquals((routingResult.getContext()).getResponseMimeType(), "application/json");
    } catch (RestLiSyntaxException e) {
        throw new RoutingException("syntax exception", 400);
    } finally {
        EasyMock.reset(resource);
        EasyMock.makeThreadSafe(resource, true);
    }
}
Also used : FilterRequestContextInternalImpl(com.linkedin.restli.internal.server.filter.FilterRequestContextInternalImpl) RoutingException(com.linkedin.restli.server.RoutingException) Task(com.linkedin.parseq.Task) BaseTask(com.linkedin.parseq.BaseTask) RestLiSyntaxException(com.linkedin.restli.internal.server.util.RestLiSyntaxException) FilterChainDispatcherImpl(com.linkedin.restli.internal.server.filter.FilterChainDispatcherImpl) URI(java.net.URI) RestLiFilterChain(com.linkedin.restli.internal.server.filter.RestLiFilterChain) RoutingResult(com.linkedin.restli.internal.server.RoutingResult) FilterChainCallback(com.linkedin.restli.internal.server.filter.FilterChainCallback) FilterChainDispatcher(com.linkedin.restli.internal.server.filter.FilterChainDispatcher) RestLiResponseHandler(com.linkedin.restli.internal.server.response.RestLiResponseHandler) FilterChainCallbackImpl(com.linkedin.restli.internal.server.filter.FilterChainCallbackImpl) RestLiCallback(com.linkedin.restli.internal.server.RestLiCallback) FilterRequestContext(com.linkedin.restli.server.filter.FilterRequestContext) ResourceContextImpl(com.linkedin.restli.internal.server.ResourceContextImpl) RestLiResponse(com.linkedin.restli.internal.server.response.RestLiResponse) RestLiArgumentBuilder(com.linkedin.restli.internal.server.methods.arguments.RestLiArgumentBuilder) CountDownLatch(java.util.concurrent.CountDownLatch) RestLiFilterResponseContextFactory(com.linkedin.restli.internal.server.filter.RestLiFilterResponseContextFactory) RestRequest(com.linkedin.r2.message.rest.RestRequest) Callback(com.linkedin.common.callback.Callback) RestLiCallback(com.linkedin.restli.internal.server.RestLiCallback) FilterChainCallback(com.linkedin.restli.internal.server.filter.FilterChainCallback) ServerResourceContext(com.linkedin.restli.internal.server.ServerResourceContext) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) RestLiRequestData(com.linkedin.restli.server.RestLiRequestData)

Example 7 with Task

use of com.linkedin.parseq.Task in project rest.li by linkedin.

the class RestLiMethodInvoker method doInvoke.

@SuppressWarnings("deprecation")
private void doInvoke(final ResourceMethodDescriptor descriptor, final RequestExecutionCallback<Object> callback, final RequestExecutionReportBuilder requestExecutionReportBuilder, final Object resource, final ServerResourceContext resourceContext, final Object... arguments) throws IllegalAccessException {
    final Method method = descriptor.getMethod();
    try {
        switch(descriptor.getInterfaceType()) {
            case CALLBACK:
                int callbackIndex = descriptor.indexOfParameterType(ParamType.CALLBACK);
                final RequestExecutionReport executionReport = getRequestExecutionReport(requestExecutionReportBuilder);
                //Delegate the callback call to the request execution callback along with the
                //request execution report.
                arguments[callbackIndex] = new Callback<Object>() {

                    @Override
                    public void onError(Throwable e) {
                        callback.onError(e instanceof RestLiServiceException ? e : new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, e), executionReport, resourceContext.getRequestAttachmentReader(), resourceContext.getResponseAttachments());
                    }

                    @Override
                    public void onSuccess(Object result) {
                        callback.onSuccess(result, executionReport, resourceContext.getResponseAttachments());
                    }
                };
                method.invoke(resource, arguments);
                // App code should use the callback
                break;
            case SYNC:
                Object applicationResult = method.invoke(resource, arguments);
                callback.onSuccess(applicationResult, getRequestExecutionReport(requestExecutionReportBuilder), resourceContext.getResponseAttachments());
                break;
            case PROMISE:
                if (!checkEngine(resourceContext, callback, descriptor, requestExecutionReportBuilder)) {
                    break;
                }
                int contextIndex = descriptor.indexOfParameterType(ParamType.PARSEQ_CONTEXT_PARAM);
                if (contextIndex == -1) {
                    contextIndex = descriptor.indexOfParameterType(ParamType.PARSEQ_CONTEXT);
                }
                // run through the engine to get the context
                Task<Object> restliTask = new RestLiParSeqTask(arguments, contextIndex, method, resource);
                // propagate the result to the callback
                restliTask.addListener(new CallbackPromiseAdapter<>(callback, restliTask, requestExecutionReportBuilder, resourceContext.getRequestAttachmentReader(), resourceContext.getResponseAttachments()));
                runTask(restliTask, toPlanClass(descriptor));
                break;
            case TASK:
                if (!checkEngine(resourceContext, callback, descriptor, requestExecutionReportBuilder)) {
                    break;
                }
                //addListener requires Task<Object> in this case
                @SuppressWarnings("unchecked") Task<Object> task = (Task<Object>) method.invoke(resource, arguments);
                if (task == null) {
                    callback.onError(new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Error in application code: null Task"), getRequestExecutionReport(requestExecutionReportBuilder), resourceContext.getRequestAttachmentReader(), resourceContext.getResponseAttachments());
                } else {
                    task.addListener(new CallbackPromiseAdapter<>(callback, task, requestExecutionReportBuilder, resourceContext.getRequestAttachmentReader(), resourceContext.getResponseAttachments()));
                    runTask(task, toPlanClass(descriptor));
                }
                break;
            default:
                throw new AssertionError("Unexpected interface type " + descriptor.getInterfaceType());
        }
    } catch (InvocationTargetException e) {
        // InvocationTargetException wrapped around the root cause.
        if (RestLiServiceException.class.isAssignableFrom(e.getCause().getClass())) {
            RestLiServiceException restLiServiceException = (RestLiServiceException) e.getCause();
            callback.onError(restLiServiceException, getRequestExecutionReport(requestExecutionReportBuilder), resourceContext.getRequestAttachmentReader(), resourceContext.getResponseAttachments());
        } else {
            callback.onError(new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, _errorResponseBuilder.getInternalErrorMessage(), e.getCause()), getRequestExecutionReport(requestExecutionReportBuilder), resourceContext.getRequestAttachmentReader(), resourceContext.getResponseAttachments());
        }
    }
}
Also used : BaseTask(com.linkedin.parseq.BaseTask) Task(com.linkedin.parseq.Task) Method(java.lang.reflect.Method) RequestExecutionReport(com.linkedin.restli.server.RequestExecutionReport) InvocationTargetException(java.lang.reflect.InvocationTargetException) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException)

Example 8 with Task

use of com.linkedin.parseq.Task in project rest.li by linkedin.

the class ParSeqBasedCompletionStage method produceEitherStage.

/**
 *  According to the {@link CompletionStage} documentation:
 *  <quote>
 *  If a stage is dependent on either of two others, and only one of them completes exceptionally,
 *  no guarantees are made about whether the dependent stage completes normally or exceptionally
 *  </quote>
 *
 *  Therefore we only need to guarantee that if both stage completes exceptionally, the returned stage also completes
 *  exceptionally.
 */
private <U> ParSeqBasedCompletionStage<U> produceEitherStage(String taskName, CompletionStage<? extends T> other, Function<? super T, U> fn) {
    Task<T> that = getOrGenerateTaskFromStage(other);
    // TODO: Synchronization is now needed since we cannot enforce a happen-before relation.
    // This can be optimized once ensureFuture() switch to use ParSeq's scheduleToRun() implementation,
    // so that both completionStage' tasks will be added to the same plan. In the same plan, tasks are executed
    // in serial order, therefore one can cancel another to ensure only one executes.
    final AtomicBoolean[] sync = { new AtomicBoolean(false) };
    return nextStageByComposingTask(Task.async(taskName, () -> {
        final SettablePromise<U> result = Promises.settable();
        Stream.of(_task, that).map(task -> task.onFailure(throwable -> {
            // Note this behavior, according to the {@link CompletionStage} documentation is undefined.
            if (sync[0].compareAndSet(false, true)) {
                // If any failed, try to fail the promise (failfast)
                result.fail(throwable);
            }
        }).andThen((t) -> {
            if (sync[0].compareAndSet(false, true)) {
                try {
                    result.done(fn.apply(t));
                } catch (Throwable throwable) {
                    result.fail(throwable);
                }
            }
        })).forEach(this::ensureFuture);
        return result;
    }));
}
Also used : Engine(com.linkedin.parseq.Engine) Promises(com.linkedin.parseq.promise.Promises) Executor(java.util.concurrent.Executor) BiFunction(java.util.function.BiFunction) Success(com.linkedin.parseq.function.Success) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) CompletableFuture(java.util.concurrent.CompletableFuture) CompletionException(java.util.concurrent.CompletionException) Function(java.util.function.Function) Supplier(java.util.function.Supplier) Consumer(java.util.function.Consumer) SettablePromise(com.linkedin.parseq.promise.SettablePromise) Future(java.util.concurrent.Future) CompletionStage(java.util.concurrent.CompletionStage) Stream(java.util.stream.Stream) ForkJoinPool(java.util.concurrent.ForkJoinPool) Failure(com.linkedin.parseq.function.Failure) BiConsumer(java.util.function.BiConsumer) Task(com.linkedin.parseq.Task) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) SettablePromise(com.linkedin.parseq.promise.SettablePromise)

Example 9 with Task

use of com.linkedin.parseq.Task in project rest.li by linkedin.

the class GreetingsResourceCodeGenerator method printMethodBody.

private void printMethodBody(final PrintStream out, final Method method) {
    final Type returnType = method.getGenericReturnType();
    switch(_type) {
        case CALLBACK:
            out.println("final Runnable requestHandler = new Runnable() {");
            out.println("public void run () {");
            out.println("try {");
            if (returnType == void.class) {
                printImplCall(out, method);
                out.println(";");
                out.println("callback.onSuccess(null);");
            } else {
                out.print("callback.onSuccess(");
                printImplCall(out, method);
                out.println(");");
            }
            out.println("} catch (final Throwable throwable) {");
            out.println("callback.onError(throwable);");
            // try catch
            out.println("}");
            // run
            out.println("}");
            // runnable
            out.println("};");
            out.printf("_scheduler.schedule(requestHandler, DELAY, %s.MILLISECONDS);", className(TimeUnit.class));
            break;
        case PROMISE:
            if (_useParSeqCtx) {
                out.printf("final %s result = %s.settable();%n", genericWrapper(SettablePromise.class, returnType), className(Promises.class));
                out.println("final Runnable requestHandler = new Runnable() {");
                out.println("public void run () {");
                out.println("try {");
                if (returnType == void.class) {
                    printImplCall(out, method);
                    out.println(";");
                    out.println("result.done(null);");
                } else {
                    out.print("result.done(");
                    printImplCall(out, method);
                    out.println(");");
                }
                out.println("} catch (final Throwable throwable) {");
                out.println("result.fail(throwable);");
                // try catch
                out.println("}");
                // run
                out.println("}");
                // runnable
                out.println("};");
                out.printf("psContext.run(%s.action(\"restli-%s\", requestHandler::run));%n", className(Task.class), method.getName());
                out.println("return result;");
            } else {
                out.printf("final %s result = %s.settable();%n", genericWrapper(SettablePromise.class, returnType), className(Promises.class));
                out.println("final Runnable requestHandler = new Runnable() {");
                out.println("public void run () {");
                out.println("try {");
                if (returnType == void.class) {
                    printImplCall(out, method);
                    out.println(";");
                    out.println("result.done(null);");
                } else {
                    out.print("result.done(");
                    printImplCall(out, method);
                    out.println(");");
                }
                out.println("} catch (final Throwable throwable) {");
                out.println("result.fail(throwable);");
                // try catch
                out.println("}");
                // run
                out.println("}");
                // runnable
                out.println("};");
                out.printf("_scheduler.schedule(requestHandler, DELAY, %s.MILLISECONDS);", className(TimeUnit.class));
                out.println("return result;");
            }
            break;
        case SYNC:
            if (!returnType.equals(void.class))
                out.print("return ");
            printImplCall(out, method);
            out.println(";");
            break;
        case TASK:
            out.printf("return new %s()%n", genericWrapper(BaseTask.class, returnType));
            out.println("{");
            out.printf("protected %s run(final %s context) throws Exception%n", genericWrapper(Promise.class, returnType), className(Context.class));
            out.println("{");
            if (returnType.equals(void.class)) {
                printImplCall(out, method);
                out.println(";");
                out.printf("return %s.value(null);%n", className(Promises.class));
            } else {
                out.printf("return %s.value(", className(Promises.class));
                printImplCall(out, method);
                out.println(");");
            }
            out.println("}");
            out.println("};");
            break;
    }
}
Also used : Context(com.linkedin.parseq.Context) SettablePromise(com.linkedin.parseq.promise.SettablePromise) Promise(com.linkedin.parseq.promise.Promise) GenericArrayType(java.lang.reflect.GenericArrayType) InterfaceType(com.linkedin.restli.internal.server.model.ResourceMethodDescriptor.InterfaceType) ParameterizedType(java.lang.reflect.ParameterizedType) Type(java.lang.reflect.Type) BaseTask(com.linkedin.parseq.BaseTask) Task(com.linkedin.parseq.Task) Promises(com.linkedin.parseq.promise.Promises) BaseTask(com.linkedin.parseq.BaseTask) TimeUnit(java.util.concurrent.TimeUnit) SettablePromise(com.linkedin.parseq.promise.SettablePromise)

Example 10 with Task

use of com.linkedin.parseq.Task in project rest.li by linkedin.

the class GreetingsResourceCodeGenerator method printMethod.

private void printMethod(final PrintStream out, final Method method) {
    final Type returnType = method.getGenericReturnType();
    // method annotations
    final Annotation[] annos = method.getAnnotations();
    for (final Annotation anno : annos) {
        if (RestMethod.class.equals(anno.annotationType().getEnclosingClass()))
            if (!_templateClass.equals(KeyValueResource.class))
                continue;
        out.println(toStrAnnotation(anno));
    }
    // method header
    out.print("public ");
    // return type
    switch(_type) {
        case CALLBACK:
            out.print("void");
            break;
        case PROMISE:
            out.print(genericWrapper(Promise.class, returnType));
            break;
        case SYNC:
            out.print(toStrGenericType(returnType));
            break;
        case TASK:
            out.print(genericWrapper(Task.class, returnType));
            break;
    }
    out.printf(" %s(", method.getName());
    printArgumentList(out, method);
    out.print(")");
    printThrowsClause(out, method);
    out.println();
    // begin method body
    out.println("{");
    printMethodBody(out, method);
    // end method
    out.println("}");
    out.println();
}
Also used : SettablePromise(com.linkedin.parseq.promise.SettablePromise) Promise(com.linkedin.parseq.promise.Promise) GenericArrayType(java.lang.reflect.GenericArrayType) InterfaceType(com.linkedin.restli.internal.server.model.ResourceMethodDescriptor.InterfaceType) ParameterizedType(java.lang.reflect.ParameterizedType) Type(java.lang.reflect.Type) BaseTask(com.linkedin.parseq.BaseTask) Task(com.linkedin.parseq.Task) Annotation(java.lang.annotation.Annotation)

Aggregations

Task (com.linkedin.parseq.Task)13 BaseTask (com.linkedin.parseq.BaseTask)4 SettablePromise (com.linkedin.parseq.promise.SettablePromise)4 BaseEngineTest (com.linkedin.parseq.BaseEngineTest)3 Promises (com.linkedin.parseq.promise.Promises)3 CountDownLatch (java.util.concurrent.CountDownLatch)3 Function (java.util.function.Function)3 Test (org.testng.annotations.Test)3 ByteString (com.linkedin.data.ByteString)2 Engine (com.linkedin.parseq.Engine)2 Task.withRetryPolicy (com.linkedin.parseq.Task.withRetryPolicy)2 Failure (com.linkedin.parseq.function.Failure)2 Success (com.linkedin.parseq.function.Success)2 Promise (com.linkedin.parseq.promise.Promise)2 TerminationPolicy (com.linkedin.parseq.retry.termination.TerminationPolicy)2 RestRequest (com.linkedin.r2.message.rest.RestRequest)2 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)2 RestResponse (com.linkedin.r2.message.rest.RestResponse)2 InterfaceType (com.linkedin.restli.internal.server.model.ResourceMethodDescriptor.InterfaceType)2 IOException (java.io.IOException)2