All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.interceptors.BaseAsyncInterceptor Maven / Gradle / Ivy

There is a newer version: 9.1.7.Final
Show newest version
package org.infinispan.interceptors;

import java.util.Collection;
import java.util.concurrent.CompletableFuture;

import org.infinispan.commands.VisitableCommand;
import org.infinispan.commons.util.Experimental;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.context.InvocationContext;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.interceptors.impl.SimpleAsyncInvocationStage;

/**
 * Base class for an interceptor in the new asynchronous invocation chain.
 *
 * @author Dan Berindei
 * @since 9.0
 */
@Experimental
public abstract class BaseAsyncInterceptor implements AsyncInterceptor {
   private final InvocationSuccessFunction invokeNextFunction = (rCtx, rCommand, rv) -> invokeNext(rCtx, rCommand);

   protected Configuration cacheConfiguration;
   private AsyncInterceptor nextInterceptor;
   private DDAsyncInterceptor nextDDInterceptor;

   @Inject
   public void inject(Configuration cacheConfiguration) {
      this.cacheConfiguration = cacheConfiguration;
   }

   /**
    * Used internally to set up the interceptor.
    */
   @Override
   public final void setNextInterceptor(AsyncInterceptor nextInterceptor) {
      this.nextInterceptor = nextInterceptor;
      this.nextDDInterceptor =
            nextInterceptor instanceof DDAsyncInterceptor ? (DDAsyncInterceptor) nextInterceptor : null;
   }

   /**
    * Invoke the next interceptor, possibly with a new command.
    *
    * 

Use {@link #invokeNextThenApply(InvocationContext, VisitableCommand, InvocationSuccessFunction)} * or {@link #invokeNextThenAccept(InvocationContext, VisitableCommand, InvocationSuccessAction)} instead * if you need to process the return value of the next interceptor.

* *

Note: {@code invokeNext(ctx, command)} does not throw exceptions. In order to handle exceptions from the * next interceptors, you must use * {@link #invokeNextAndHandle(InvocationContext, VisitableCommand, InvocationFinallyFunction)}, * {@link #invokeNextAndFinally(InvocationContext, VisitableCommand, InvocationFinallyAction)}, * or {@link #invokeNextAndExceptionally(InvocationContext, VisitableCommand, InvocationExceptionFunction)}.

*/ public final Object invokeNext(InvocationContext ctx, VisitableCommand command) { try { if (nextDDInterceptor != null) { return command.acceptVisitor(ctx, nextDDInterceptor); } else { return nextInterceptor.visitCommand(ctx, command); } } catch (Throwable throwable) { return new SimpleAsyncInvocationStage(throwable); } } /** * Invoke the next interceptor, possibly with a new command, and execute an {@link InvocationCallback} * after all the interceptors have finished successfully. * *

You need to wrap the result with {@link #makeStage(Object)} if you need to add another handler.

*/ public final Object invokeNextThenApply(InvocationContext ctx, VisitableCommand command, InvocationSuccessFunction function) { try { Object rv; if (nextDDInterceptor != null) { rv = command.acceptVisitor(ctx, nextDDInterceptor); } else { rv = nextInterceptor.visitCommand(ctx, command); } if (rv instanceof InvocationStage) { return ((InvocationStage) rv).thenApply(ctx, command, function); } return function.apply(ctx, command, rv); } catch (Throwable throwable) { return new SimpleAsyncInvocationStage(throwable); } } /** * Invoke the next interceptor, possibly with a new command, and execute an {@link InvocationCallback} * after all the interceptors have finished successfully. * *

You need to wrap the result with {@link #makeStage(Object)} if you need to add another handler.

*/ public final Object invokeNextThenAccept(InvocationContext ctx, VisitableCommand command, InvocationSuccessAction action) { try { Object rv; if (nextDDInterceptor != null) { rv = command.acceptVisitor(ctx, nextDDInterceptor); } else { rv = nextInterceptor.visitCommand(ctx, command); } if (rv instanceof InvocationStage) { return ((InvocationStage) rv).thenAccept(ctx, command, action); } action.accept(ctx, command, rv); return rv; } catch (Throwable throwable) { return new SimpleAsyncInvocationStage(throwable); } } /** * Invoke the next interceptor, possibly with a new command, and execute an {@link InvocationCallback} * after all the interceptors have finished with an exception. * *

You need to wrap the result with {@link #makeStage(Object)} if you need to add another handler.

*/ public final Object invokeNextAndExceptionally(InvocationContext ctx, VisitableCommand command, InvocationExceptionFunction function) { try { Object rv; if (nextDDInterceptor != null) { rv = command.acceptVisitor(ctx, nextDDInterceptor); } else { rv = nextInterceptor.visitCommand(ctx, command); } if (rv instanceof InvocationStage) { return ((InvocationStage) rv).andExceptionally(ctx, command, function); } // No exception return rv; } catch (Throwable throwable) { return new SimpleAsyncInvocationStage(throwable); } } /** * Invoke the next interceptor, possibly with a new command, and execute an {@link InvocationCallback} * after all the interceptors have finished, with or without an exception. * *

You need to wrap the result with {@link #makeStage(Object)} if you need to add another handler.

*/ public final Object invokeNextAndFinally(InvocationContext ctx, VisitableCommand command, InvocationFinallyAction action) { try { Object rv; Throwable throwable; try { if (nextDDInterceptor != null) { rv = command.acceptVisitor(ctx, nextDDInterceptor); } else { rv = nextInterceptor.visitCommand(ctx, command); } throwable = null; if (rv instanceof InvocationStage) { return ((InvocationStage) rv).andFinally(ctx, command, action); } } catch (Throwable t) { rv = null; throwable = t; } action.accept(ctx, command, rv, throwable); return throwable == null ? rv : new SimpleAsyncInvocationStage(throwable); } catch (Throwable t) { return new SimpleAsyncInvocationStage(t); } } /** * Invoke the next interceptor, possibly with a new command, and execute an {@link InvocationCallback} * after all the interceptors have finished, with or without an exception. * *

You need to wrap the result with {@link #makeStage(Object)} if you need to add another handler.

*/ public final Object invokeNextAndHandle(InvocationContext ctx, VisitableCommand command, InvocationFinallyFunction function) { try { Object rv; Throwable throwable; try { if (nextDDInterceptor != null) { rv = command.acceptVisitor(ctx, nextDDInterceptor); } else { rv = nextInterceptor.visitCommand(ctx, command); } throwable = null; if (rv instanceof InvocationStage) { return ((InvocationStage) rv).andHandle(ctx, command, function); } } catch (Throwable t) { rv = null; throwable = t; } return function.apply(ctx, command, rv, throwable); } catch (Throwable throwable) { return new SimpleAsyncInvocationStage(throwable); } } /** * Suspend the invocation until {@code valueFuture} completes, then return its result without running * the remaining interceptors. * *

The caller can add a callback that will run when {@code valueFuture} completes, e.g. * {@code asyncValue(v).thenApply(ctx, command, (rCtx, rCommand, rv, t) -> invokeNext(rCtx, rCommand))}. * For this particular scenario, however, it's simpler to use * {@link #asyncInvokeNext(InvocationContext, VisitableCommand, CompletableFuture)}.

*/ public static InvocationStage asyncValue(CompletableFuture valueFuture) { return new SimpleAsyncInvocationStage(valueFuture); } /** * Suspend the invocation until {@code delay} completes, then if successful invoke the next interceptor. * *

If {@code delay} completes exceptionally, skip the next interceptor and continue with the exception.

* *

You need to wrap the result with {@link #makeStage(Object)} if you need to add another handler.

*/ public final Object asyncInvokeNext(InvocationContext ctx, VisitableCommand command, CompletableFuture delay) { return asyncValue(delay).thenApply(ctx, command, invokeNextFunction); } /** * Suspend invocation until all {@code delays} complete, then if successful invoke the next interceptor. * If the list is empty or null, invoke the next interceptor immediately. * *

If any of {@code delays} completes exceptionally, skip the next interceptor and continue with the exception.

* *

You need to wrap the result with {@link #makeStage(Object)} if you need to add another handler.

*/ public final Object asyncInvokeNext(InvocationContext ctx, VisitableCommand command, Collection> delays) { if (delays == null || delays.isEmpty()) { return invokeNext(ctx, command); } else if (delays.size() == 1) { return asyncInvokeNext(ctx, command, delays.iterator().next()); } else { return asyncInvokeNext(ctx, command, CompletableFuture.allOf(delays.toArray(new CompletableFuture[delays.size()]))); } } /** * Return the value if {@code throwable != null}, throw the exception otherwise. */ public static Object valueOrException(Object rv, Throwable throwable) throws Throwable { if (throwable == null) { return rv; } else { throw throwable; } } /** * Encode the result of an {@link #invokeNext(InvocationContext, VisitableCommand)} in an {@link InvocationStage}. * *

May not create a new instance, if the result is already an {@code InvocationStage}. */ public static InvocationStage makeStage(Object rv) { if (rv instanceof InvocationStage) { return (InvocationStage) rv; } else { return new SyncInvocationStage(rv); } } protected static boolean isSuccessfullyDone(Object maybeStage) { if (maybeStage instanceof InvocationStage) { InvocationStage stage = (InvocationStage) maybeStage; return stage.isDone() && !stage.toCompletableFuture().isCompletedExceptionally(); } return true; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy