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

net.tascalate.concurrent.var.ContextTrampoline Maven / Gradle / Ivy

Go to download

Implementation of blocking (IO-Bound) cancellable java.util.concurrent.CompletionStage and related extensions to java.util.concurrent.ExecutorService-s

There is a newer version: 0.9.8
Show newest version
/**
 * Copyright 2015-2020 Valery Silaev (http://vsilaev.com)
 *
 * Licensed 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 net.tascalate.concurrent.var;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import java.util.stream.Collectors;

import net.tascalate.concurrent.DependentPromise;
import net.tascalate.concurrent.Promise;
import net.tascalate.concurrent.TaskExecutorService;
import net.tascalate.concurrent.decorators.CustomizableDependentPromiseDecorator;
import net.tascalate.concurrent.decorators.CustomizablePromiseDecorator;
import net.tascalate.concurrent.decorators.PromiseCustomizer;

public class ContextTrampoline {

    /**
     * Defines a strategy how context variables are propagated to the execution thread
     * @author vsilaev
     *
     */
    public static enum Propagation {
        /**
         * Default propagation option that is optimized for performance
         * 

The logic is the following:

*
    *
  1. Apply context variables from the snapshot
  2. *
  3. Execute code
  4. *
  5. Reset context variables
  6. *
*/ OPTIMIZED, /** * Pessimistic propagation option for rare cases when thread might have * its own default values of the context variables and they must be restored. *

The logic is the following:

*
    *
  1. Save context variables from the current thread
  2. *
  3. Apply context variables from the snapshot
  4. *
  5. Execute code
  6. *
  7. Restore context variables saved in the step [1]
  8. *
*/ STRICT; } private final List> contextVars; private ContextTrampoline(List> contextVars) { this.contextVars = contextVars == null ? Collections.emptyList() : Collections.unmodifiableList(contextVars); } public Function, Promise> boundPromises() { return boundPromises(Propagation.OPTIMIZED); } public Function, Promise> boundPromises(Propagation propagation) { PromiseCustomizer customizer = new ContextualPromiseCustomizer( contextVars, propagation, captureContext(contextVars) ); return p -> p instanceof DependentPromise ? new CustomizableDependentPromiseDecorator<>((DependentPromise)p, customizer) : new CustomizablePromiseDecorator<>(p, customizer); } public Executor bind(Executor executor) { return bind(executor, Propagation.OPTIMIZED); } public Executor bind(Executor executor, Propagation propagation) { return bindExecutor(executor, propagation, ContextualExecutor::new); } public ExecutorService bind(ExecutorService executorService) { return bind(executorService, Propagation.OPTIMIZED); } public ExecutorService bind(ExecutorService executorService, Propagation propagation) { return bindExecutor(executorService, propagation, ContextualExecutorService::new); } public TaskExecutorService bind(TaskExecutorService executorService) { return bind(executorService, Propagation.OPTIMIZED); } public TaskExecutorService bind(TaskExecutorService executorService, Propagation propagation) { return bindExecutor(executorService, propagation, ContextualTaskExecutorService::new); } public ScheduledExecutorService bind(ScheduledExecutorService executorService) { return bind(executorService, Propagation.OPTIMIZED); } public ScheduledExecutorService bind(ScheduledExecutorService executorService, Propagation propagation) { return bindExecutor(executorService, propagation, ContextualScheduledExecutorService::new); } public static ContextTrampoline relay(ContextVar contextVar) { return new ContextTrampoline(Collections.singletonList(contextVar)); } public static ContextTrampoline relay(ThreadLocal threadLocal) { return relay(ContextVar.from(threadLocal)); } public static ContextTrampoline relay(ContextVar... contextVars) { return new ContextTrampoline(Arrays.asList(contextVars)); } public static ContextTrampoline relay(ThreadLocal... threadLocals) { return new ContextTrampoline(Arrays.stream(threadLocals).map(ContextVar::from).collect(Collectors.toList())); } public static ContextTrampoline relay(List> contextVars) { if (null == contextVars || contextVars.isEmpty()) { return NOP; } else { return new ContextTrampoline(new ArrayList<>(contextVars)); } } public static ContextTrampoline relayThreadLocals(List> threadLocals) { if (null == threadLocals || threadLocals.isEmpty()) { return NOP; } else { return relay( threadLocals.stream() .map(tl -> ContextVar.from((ThreadLocal)tl)) .collect(Collectors.toList()) ); } } static List captureContext(List> contextVars) { return contextVars.stream().map(v -> v.get()).collect(Collectors.toList()); } private D bindExecutor(D delegate, Propagation propagation, ContextualExecutorConstructor ctr) { return ctr.apply(delegate, contextVars, propagation, captureContext(contextVars)); } private static interface ContextualExecutorConstructor { D apply(D delegate, List> contextVars, Propagation propagation, List capturedContext); } static String generateVarName() { return ""; } private static final AtomicLong COUNTER = new AtomicLong(); private static final ContextTrampoline NOP = new ContextTrampoline(null) { @Override public Function, Promise> boundPromises() { return Function.identity(); } @Override public Function, Promise> boundPromises(Propagation propagation) { return Function.identity(); } @Override public Executor bind(Executor executor) { return executor; } @Override public Executor bind(Executor executor, Propagation propagation) { return executor; } @Override public ExecutorService bind(ExecutorService executorService) { return executorService; } @Override public ExecutorService bind(ExecutorService executorService, Propagation propagation) { return executorService; } @Override public TaskExecutorService bind(TaskExecutorService executorService) { return executorService; } @Override public TaskExecutorService bind(TaskExecutorService executorService, Propagation propagation) { return executorService; } @Override public ScheduledExecutorService bind(ScheduledExecutorService executorService) { return executorService; } @Override public ScheduledExecutorService bind(ScheduledExecutorService executorService, Propagation propagation) { return executorService; } }; }