From 41fa48ec77bb626d4b8e010586428761a6582c38 Mon Sep 17 00:00:00 2001 From: Elijah Date: Fri, 4 Sep 2020 16:58:46 +0800 Subject: [PATCH 1/8] =?UTF-8?q?DEC-14578=20=E5=BC=95=E5=85=A5com.alibaba:t?= =?UTF-8?q?ransmittable-thread-local?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fine-transmittable-thread-local/pom.xml | 41 + .../alibaba/ttl/TransmittableThreadLocal.java | 754 ++++++++++++++++++ .../com/fr/third/alibaba/ttl/TtlCallable.java | 262 ++++++ .../com/fr/third/alibaba/ttl/TtlCopier.java | 29 + .../com/fr/third/alibaba/ttl/TtlEnhanced.java | 15 + .../third/alibaba/ttl/TtlRecursiveAction.java | 63 ++ .../third/alibaba/ttl/TtlRecursiveTask.java | 72 ++ .../com/fr/third/alibaba/ttl/TtlRunnable.java | 262 ++++++ .../fr/third/alibaba/ttl/TtlTimerTask.java | 193 +++++ .../com/fr/third/alibaba/ttl/TtlUnwrap.java | 70 ++ .../com/fr/third/alibaba/ttl/TtlWrappers.java | 342 ++++++++ .../fr/third/alibaba/ttl/package-info.java | 9 + .../third/alibaba/ttl/spi/TtlAttachments.java | 39 + .../ttl/spi/TtlAttachmentsDelegate.java | 31 + .../fr/third/alibaba/ttl/spi/TtlEnhanced.java | 20 + .../fr/third/alibaba/ttl/spi/TtlWrapper.java | 26 + .../third/alibaba/ttl/spi/package-info.java | 9 + ...nheritableForkJoinWorkerThreadFactory.java | 21 + ...bleForkJoinWorkerThreadFactoryWrapper.java | 58 ++ .../DisableInheritableThreadFactory.java | 22 + ...isableInheritableThreadFactoryWrapper.java | 56 ++ .../threadpool/ExecutorServiceTtlWrapper.java | 101 +++ .../ttl/threadpool/ExecutorTtlWrapper.java | 56 ++ .../ScheduledExecutorServiceTtlWrapper.java | 61 ++ .../alibaba/ttl/threadpool/TtlExecutors.java | 171 ++++ .../ttl/threadpool/TtlForkJoinPoolHelper.java | 73 ++ .../ttl/threadpool/agent/TtlAgent.java | 245 ++++++ .../ttl/threadpool/agent/TtlTransformer.java | 73 ++ .../agent/internal/logging/Logger.java | 80 ++ .../internal/transformlet/ClassInfo.java | 66 ++ .../transformlet/JavassistTransformlet.java | 17 + .../impl/TtlExecutorTransformlet.java | 164 ++++ .../impl/TtlForkJoinTransformlet.java | 85 ++ .../impl/TtlTimerTaskTransformlet.java | 71 ++ .../internal/transformlet/impl/Utils.java | 119 +++ .../internal/transformlet/package-info.java | 7 + .../ttl/threadpool/agent/package-info.java | 8 + .../alibaba/ttl/threadpool/package-info.java | 6 + 38 files changed, 3797 insertions(+) create mode 100644 fine-transmittable-thread-local/pom.xml create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TransmittableThreadLocal.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCallable.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCopier.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlEnhanced.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRecursiveAction.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRecursiveTask.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRunnable.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlTimerTask.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlUnwrap.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlWrappers.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/package-info.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachments.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachmentsDelegate.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlEnhanced.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlWrapper.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/package-info.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorServiceTtlWrapper.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorTtlWrapper.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ScheduledExecutorServiceTtlWrapper.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlExecutors.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlForkJoinPoolHelper.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlAgent.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlTransformer.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/logging/Logger.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/ClassInfo.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/JavassistTransformlet.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlExecutorTransformlet.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlForkJoinTransformlet.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlTimerTaskTransformlet.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/Utils.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/package-info.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/package-info.java create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/package-info.java diff --git a/fine-transmittable-thread-local/pom.xml b/fine-transmittable-thread-local/pom.xml new file mode 100644 index 000000000..4d324253f --- /dev/null +++ b/fine-transmittable-thread-local/pom.xml @@ -0,0 +1,41 @@ + + 4.0.0 + + + com.fr.third + step8 + 10.0-FEATURE-SNAPSHOT + ../base-third-project/base-third-step8 + + + fine-transmittable-thread-local + ${revision} + + + + + + com.fr.third + fine-javassist + ${revision} + + + + com.fr.third + fine-jetbrains + ${revision} + + + + + diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TransmittableThreadLocal.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TransmittableThreadLocal.java new file mode 100644 index 000000000..f4d423503 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TransmittableThreadLocal.java @@ -0,0 +1,754 @@ +package com.fr.third.alibaba.ttl; + +import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; +import com.fr.third.alibaba.ttl.threadpool.TtlForkJoinPoolHelper; +import com.fr.third.alibaba.ttl.threadpool.agent.TtlAgent; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.Callable; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * {@link TransmittableThreadLocal} can transmit value from the thread of submitting task to the thread of executing task. + *

+ * Note:
+ * {@link TransmittableThreadLocal} extends {@link InheritableThreadLocal}, + * so {@link TransmittableThreadLocal} first is a {@link InheritableThreadLocal}.
+ * If the inheritable ability from {@link InheritableThreadLocal} has potential leaking problem, + * you can disable the inheritable ability: + *

+ * ❶ by wrapping thread factory using method + * {@link TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)} / + * {@link TtlForkJoinPoolHelper#getDefaultDisableInheritableForkJoinWorkerThreadFactory()} + * for thread pooling components({@link java.util.concurrent.ThreadPoolExecutor}, {@link java.util.concurrent.ForkJoinPool}). + * Inheritable feature in thread pooling components should never happen, + * because threads in thread pooling components is pre-created and pooled, these threads is neutral for biz logic/data. + *
+ * You can turn on "disable inheritable for thread pool" by {@link TtlAgent} + * so as to wrap thread factory for thread pooling components ({@link java.util.concurrent.ThreadPoolExecutor}, + * {@link java.util.concurrent.ForkJoinPool}) automatically and transparently. + *

+ * ❷ or by overriding method {@link #childValue(Object)}. + * Whether the value should be inheritable or not can be controlled by the data owner, + * disable it carefully when data owner have a clear idea. + *

 {@code TransmittableThreadLocal transmittableThreadLocal = new TransmittableThreadLocal() {
+ *     protected String childValue(String parentValue) {
+ *         return initialValue();
+ *     }
+ * }}
+ *

+ * More discussion about "disable the inheritable ability" + * see + * issue #100: disable Inheritable when it's not necessary and buggy. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @author Yang Fang (snoop dot fy at gmail dot com) + * @see TtlRunnable + * @see TtlCallable + * @see TtlExecutors + * @see TtlExecutors#getTtlExecutor(java.util.concurrent.Executor) + * @see TtlExecutors#getTtlExecutorService(java.util.concurrent.ExecutorService) + * @see TtlExecutors#getTtlScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) + * @see TtlExecutors#getDefaultDisableInheritableThreadFactory() + * @see TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory) + * @see TtlForkJoinPoolHelper + * @see TtlForkJoinPoolHelper#getDefaultDisableInheritableForkJoinWorkerThreadFactory() + * @see TtlForkJoinPoolHelper#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory) + * @see TtlAgent + * @since 0.10.0 + */ +public class TransmittableThreadLocal extends InheritableThreadLocal implements TtlCopier { + private static final Logger logger = Logger.getLogger(TransmittableThreadLocal.class.getName()); + + private final boolean disableIgnoreNullValueSemantics; + + /** + * Default constructor. + *

+ * Create a {@link TransmittableThreadLocal} instance with "Ignore-Null-Value Semantics". + * About "Ignore-Null-Value Semantics": + *

+ *

    + *
  1. If value is {@code null}(check by {@link #get()} method), do NOT transmit this {@code ThreadLocal}.
  2. + *
  3. If set {@code null} value, also remove value(invoke {@link #remove()} method).
  4. + *
+ *

+ * This is a pragmatic design decision: + *

    + *
  1. use explicit value type rather than {@code null} to biz intent.
  2. + *
  3. more safe(avoid {@code NPE}) and gc friendly.
  4. + *
+ *

+ * So it's not recommended to use {@code null} value. + *

+ * But the behavior of "Ignore-Null-Value Semantics" is NOT compatible with + * {@link ThreadLocal} and {@link InheritableThreadLocal}, + * you can disable this behavior/semantics via using constructor {@link #TransmittableThreadLocal(boolean)} + * and set parameter {@code disableIgnoreNullValueSemantics} instead. + *

+ * More info see Issue #157. + * + * @see #TransmittableThreadLocal(boolean) + */ + public TransmittableThreadLocal() { + this(false); + } + + /** + * Constructor, create a {@link TransmittableThreadLocal} with parameter {@code disableIgnoreNullValueSemantics} + * to control "Ignore-Null-Value Semantics". + * + * @param disableIgnoreNullValueSemantics disable "Ignore-Null-Value Semantics" + * @see #TransmittableThreadLocal() + * @since 2.11.3 + */ + public TransmittableThreadLocal(boolean disableIgnoreNullValueSemantics) { + this.disableIgnoreNullValueSemantics = disableIgnoreNullValueSemantics; + } + + /** + * Computes the value for this transmittable thread-local variable + * as a function of the source thread's value at the time the task + * Object is created. + *

+ * This method is called from {@link TtlRunnable} or + * {@link TtlCallable} when it create, before the task is started. + *

+ * This method merely returns reference of its source thread value(the shadow copy), + * and should be overridden if a different behavior is desired. + * + * @since 1.0.0 + */ + public T copy(T parentValue) { + return parentValue; + } + + /** + * Callback method before task object({@link TtlRunnable}/{@link TtlCallable}) execute. + *

+ * Default behavior is to do nothing, and should be overridden + * if a different behavior is desired. + *

+ * Do not throw any exception, just ignored. + * + * @since 1.2.0 + */ + protected void beforeExecute() { + } + + /** + * Callback method after task object({@link TtlRunnable}/{@link TtlCallable}) execute. + *

+ * Default behavior is to do nothing, and should be overridden + * if a different behavior is desired. + *

+ * Do not throw any exception, just ignored. + * + * @since 1.2.0 + */ + protected void afterExecute() { + } + + /** + * see {@link InheritableThreadLocal#get()} + */ + @Override + public final T get() { + T value = super.get(); + if (disableIgnoreNullValueSemantics || null != value) addThisToHolder(); + return value; + } + + /** + * see {@link InheritableThreadLocal#set} + */ + @Override + public final void set(T value) { + if (!disableIgnoreNullValueSemantics && null == value) { + // may set null to remove value + remove(); + } else { + super.set(value); + addThisToHolder(); + } + } + + /** + * see {@link InheritableThreadLocal#remove()} + */ + @Override + public final void remove() { + removeThisFromHolder(); + super.remove(); + } + + private void superRemove() { + super.remove(); + } + + private T copyValue() { + return copy(get()); + } + + // Note about the holder: + // 1. holder self is a InheritableThreadLocal(a *ThreadLocal*). + // 2. The type of value in the holder is WeakHashMap, ?>. + // 2.1 but the WeakHashMap is used as a *Set*: + // - the value of WeakHashMap is *always null, + // - and be never used. + // 2.2 WeakHashMap support *null* value. + private static InheritableThreadLocal, ?>> holder = + new InheritableThreadLocal, ?>>() { + @Override + protected WeakHashMap, ?> initialValue() { + return new WeakHashMap, Object>(); + } + + @Override + protected WeakHashMap, ?> childValue(WeakHashMap, ?> parentValue) { + return new WeakHashMap, Object>(parentValue); + } + }; + + @SuppressWarnings("unchecked") + private void addThisToHolder() { + if (!holder.get().containsKey(this)) { + holder.get().put((TransmittableThreadLocal) this, null); // WeakHashMap supports null value. + } + } + + private void removeThisFromHolder() { + holder.get().remove(this); + } + + private static void doExecuteCallback(boolean isBefore) { + for (TransmittableThreadLocal threadLocal : holder.get().keySet()) { + try { + if (isBefore) threadLocal.beforeExecute(); + else threadLocal.afterExecute(); + } catch (Throwable t) { + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, "TTL exception when " + (isBefore ? "beforeExecute" : "afterExecute") + ", cause: " + t.toString(), t); + } + } + } + } + + /** + * Debug only method! + */ + static void dump(@Nullable String title) { + if (title != null && title.length() > 0) { + System.out.printf("Start TransmittableThreadLocal[%s] Dump...%n", title); + } else { + System.out.println("Start TransmittableThreadLocal Dump..."); + } + + for (TransmittableThreadLocal threadLocal : holder.get().keySet()) { + System.out.println(threadLocal.get()); + } + System.out.println("TransmittableThreadLocal Dump end!"); + } + + /** + * Debug only method! + */ + static void dump() { + dump(null); + } + + /** + * {@link Transmitter} transmit all {@link TransmittableThreadLocal} + * and registered {@link ThreadLocal}(registered by {@link Transmitter#registerThreadLocal}) + * values of the current thread to other thread by static methods + * {@link #capture()} => {@link #replay(Object)} => {@link #restore(Object)} (aka {@code CRR} operation). + *

+ * {@link Transmitter} is internal manipulation api for framework/middleware integration; + * In general, you will never use it in the biz/application code! + * + *

Framework/Middleware integration to TTL transmittance

+ * Below is the example code: + * + *

+     * ///////////////////////////////////////////////////////////////////////////
+     * // in thread A, capture all TransmittableThreadLocal values of thread A
+     * ///////////////////////////////////////////////////////////////////////////
+     *
+     * Object captured = Transmitter.capture(); // (1)
+     *
+     * ///////////////////////////////////////////////////////////////////////////
+     * // in thread B
+     * ///////////////////////////////////////////////////////////////////////////
+     *
+     * // replay all TransmittableThreadLocal values from thread A
+     * Object backup = Transmitter.replay(captured); // (2)
+     * try {
+     *     // your biz logic, run with the TransmittableThreadLocal values of thread B
+     *     System.out.println("Hello");
+     *     // ...
+     *     return "World";
+     * } finally {
+     *     // restore the TransmittableThreadLocal of thread B when replay
+     *     Transmitter.restore(backup); (3)
+     * }
+     * 
+ *

+ * see the implementation code of {@link TtlRunnable} and {@link TtlCallable} for more actual code sample. + *

+ * Of course, {@link #replay(Object)} and {@link #restore(Object)} operation can be simplified by util methods + * {@link #runCallableWithCaptured(Object, Callable)} or {@link #runSupplierWithCaptured(Object, Supplier)} + * and the adorable {@code Java 8 lambda syntax}. + *

+ * Below is the example code: + * + *


+     * ///////////////////////////////////////////////////////////////////////////
+     * // in thread A, capture all TransmittableThreadLocal values of thread A
+     * ///////////////////////////////////////////////////////////////////////////
+     *
+     * Object captured = Transmitter.capture(); // (1)
+     *
+     * ///////////////////////////////////////////////////////////////////////////
+     * // in thread B
+     * ///////////////////////////////////////////////////////////////////////////
+     *
+     * String result = runSupplierWithCaptured(captured, () -> {
+     *      // your biz logic, run with the TransmittableThreadLocal values of thread A
+     *      System.out.println("Hello");
+     *      ...
+     *      return "World";
+     * }); // (2) + (3)
+     * 
+ *

+ * The reason of providing 2 util methods is the different {@code throws Exception} type + * so as to satisfy your biz logic({@code lambda}): + *

    + *
  1. {@link #runCallableWithCaptured(Object, Callable)}: {@code throws Exception}
  2. + *
  3. {@link #runSupplierWithCaptured(Object, Supplier)}: No {@code throws}
  4. + *
+ *

+ * If you need the different {@code throws Exception} type, + * you can define your own util method(function interface({@code lambda})) with your own {@code throws Exception} type. + * + *

ThreadLocal Integration

+ * If you can not rewrite the existed code which use {@link ThreadLocal} to {@link TransmittableThreadLocal}, + * register the {@link ThreadLocal} instances via the methods + * {@link #registerThreadLocal(ThreadLocal, TtlCopier)}/{@link #registerThreadLocalWithShadowCopier(ThreadLocal)} + * to enhance the Transmittable ability for the existed {@link ThreadLocal} instances. + *

+ * Below is the example code: + * + *


+     * // the value of this ThreadLocal instance will be transmitted after registered
+     * Transmitter.registerThreadLocal(aThreadLocal, copyLambda);
+     *
+     * // Then the value of this ThreadLocal instance will not be transmitted after unregistered
+     * Transmitter.unregisterThreadLocal(aThreadLocal);
+     * 
+ * + * Caution:
+ * If the registered {@link ThreadLocal} instance is not {@link InheritableThreadLocal}, + * the instance can NOT {@code inherit} value from parent thread(aka. the inheritable ability)! + * + * @author Yang Fang (snoop dot fy at gmail dot com) + * @author Jerry Lee (oldratlee at gmail dot com) + * @see TtlRunnable + * @see TtlCallable + * @since 2.3.0 + */ + public static class Transmitter { + /** + * Capture all {@link TransmittableThreadLocal} and registered {@link ThreadLocal} values in the current thread. + * + * @return the captured {@link TransmittableThreadLocal} values + * @since 2.3.0 + */ + @NotNull + public static Object capture() { + return new Snapshot(captureTtlValues(), captureThreadLocalValues()); + } + + private static HashMap, Object> captureTtlValues() { + HashMap, Object> ttl2Value = new HashMap, Object>(); + for (TransmittableThreadLocal threadLocal : holder.get().keySet()) { + ttl2Value.put(threadLocal, threadLocal.copyValue()); + } + return ttl2Value; + } + + private static HashMap, Object> captureThreadLocalValues() { + final HashMap, Object> threadLocal2Value = new HashMap, Object>(); + for (Map.Entry, TtlCopier> entry : threadLocalHolder.entrySet()) { + final ThreadLocal threadLocal = entry.getKey(); + final TtlCopier copier = entry.getValue(); + + threadLocal2Value.put(threadLocal, copier.copy(threadLocal.get())); + } + return threadLocal2Value; + } + + /** + * Replay the captured {@link TransmittableThreadLocal} and registered {@link ThreadLocal} values from {@link #capture()}, + * and return the backup {@link TransmittableThreadLocal} values in the current thread before replay. + * + * @param captured captured {@link TransmittableThreadLocal} values from other thread from {@link #capture()} + * @return the backup {@link TransmittableThreadLocal} values before replay + * @see #capture() + * @since 2.3.0 + */ + @NotNull + public static Object replay(@NotNull Object captured) { + final Snapshot capturedSnapshot = (Snapshot) captured; + return new Snapshot(replayTtlValues(capturedSnapshot.ttl2Value), replayThreadLocalValues(capturedSnapshot.threadLocal2Value)); + } + + @NotNull + private static HashMap, Object> replayTtlValues(@NotNull HashMap, Object> captured) { + HashMap, Object> backup = new HashMap, Object>(); + + for (final Iterator> iterator = holder.get().keySet().iterator(); iterator.hasNext(); ) { + TransmittableThreadLocal threadLocal = iterator.next(); + + // backup + backup.put(threadLocal, threadLocal.get()); + + // clear the TTL values that is not in captured + // avoid the extra TTL values after replay when run task + if (!captured.containsKey(threadLocal)) { + iterator.remove(); + threadLocal.superRemove(); + } + } + + // set TTL values to captured + setTtlValuesTo(captured); + + // call beforeExecute callback + doExecuteCallback(true); + + return backup; + } + + private static HashMap, Object> replayThreadLocalValues(@NotNull HashMap, Object> captured) { + final HashMap, Object> backup = new HashMap, Object>(); + + for (Map.Entry, Object> entry : captured.entrySet()) { + final ThreadLocal threadLocal = entry.getKey(); + backup.put(threadLocal, threadLocal.get()); + + final Object value = entry.getValue(); + if (value == threadLocalClearMark) threadLocal.remove(); + else threadLocal.set(value); + } + + return backup; + } + + /** + * Clear all {@link TransmittableThreadLocal} and registered {@link ThreadLocal} values in the current thread, + * and return the backup {@link TransmittableThreadLocal} values in the current thread before clear. + * + * @return the backup {@link TransmittableThreadLocal} values before clear + * @since 2.9.0 + */ + @NotNull + public static Object clear() { + final HashMap, Object> ttl2Value = new HashMap, Object>(); + + final HashMap, Object> threadLocal2Value = new HashMap, Object>(); + for (Map.Entry, TtlCopier> entry : threadLocalHolder.entrySet()) { + final ThreadLocal threadLocal = entry.getKey(); + threadLocal2Value.put(threadLocal, threadLocalClearMark); + } + + return replay(new Snapshot(ttl2Value, threadLocal2Value)); + } + + /** + * Restore the backup {@link TransmittableThreadLocal} and + * registered {@link ThreadLocal} values from {@link #replay(Object)}/{@link #clear()}. + * + * @param backup the backup {@link TransmittableThreadLocal} values from {@link #replay(Object)}/{@link #clear()} + * @see #replay(Object) + * @see #clear() + * @since 2.3.0 + */ + public static void restore(@NotNull Object backup) { + final Snapshot backupSnapshot = (Snapshot) backup; + restoreTtlValues(backupSnapshot.ttl2Value); + restoreThreadLocalValues(backupSnapshot.threadLocal2Value); + } + + private static void restoreTtlValues(@NotNull HashMap, Object> backup) { + // call afterExecute callback + doExecuteCallback(false); + + for (final Iterator> iterator = holder.get().keySet().iterator(); iterator.hasNext(); ) { + TransmittableThreadLocal threadLocal = iterator.next(); + + // clear the TTL values that is not in backup + // avoid the extra TTL values after restore + if (!backup.containsKey(threadLocal)) { + iterator.remove(); + threadLocal.superRemove(); + } + } + + // restore TTL values + setTtlValuesTo(backup); + } + + private static void setTtlValuesTo(@NotNull HashMap, Object> ttlValues) { + for (Map.Entry, Object> entry : ttlValues.entrySet()) { + TransmittableThreadLocal threadLocal = entry.getKey(); + threadLocal.set(entry.getValue()); + } + } + + private static void restoreThreadLocalValues(@NotNull HashMap, Object> backup) { + for (Map.Entry, Object> entry : backup.entrySet()) { + final ThreadLocal threadLocal = entry.getKey(); + threadLocal.set(entry.getValue()); + } + } + + private static class Snapshot { + final HashMap, Object> ttl2Value; + final HashMap, Object> threadLocal2Value; + + private Snapshot(HashMap, Object> ttl2Value, HashMap, Object> threadLocal2Value) { + this.ttl2Value = ttl2Value; + this.threadLocal2Value = threadLocal2Value; + } + } + + /** + * Util method for simplifying {@link #replay(Object)} and {@link #restore(Object)} operation. + * + * @param captured captured {@link TransmittableThreadLocal} values from other thread from {@link #capture()} + * @param bizLogic biz logic + * @param the return type of biz logic + * @return the return value of biz logic + * @see #capture() + * @see #replay(Object) + * @see #restore(Object) + * @since 2.3.1 + */ + public static R runSupplierWithCaptured(@NotNull Object captured, @NotNull Supplier bizLogic) { + Object backup = replay(captured); + try { + return bizLogic.get(); + } finally { + restore(backup); + } + } + + /** + * Util method for simplifying {@link #clear()} and {@link #restore(Object)} operation. + * + * @param bizLogic biz logic + * @param the return type of biz logic + * @return the return value of biz logic + * @see #clear() + * @see #restore(Object) + * @since 2.9.0 + */ + public static R runSupplierWithClear(@NotNull Supplier bizLogic) { + Object backup = clear(); + try { + return bizLogic.get(); + } finally { + restore(backup); + } + } + + /** + * Util method for simplifying {@link #replay(Object)} and {@link #restore(Object)} operation. + * + * @param captured captured {@link TransmittableThreadLocal} values from other thread from {@link #capture()} + * @param bizLogic biz logic + * @param the return type of biz logic + * @return the return value of biz logic + * @throws Exception exception threw by biz logic + * @see #capture() + * @see #replay(Object) + * @see #restore(Object) + * @since 2.3.1 + */ + public static R runCallableWithCaptured(@NotNull Object captured, @NotNull Callable bizLogic) throws Exception { + Object backup = replay(captured); + try { + return bizLogic.call(); + } finally { + restore(backup); + } + } + + /** + * Util method for simplifying {@link #clear()} and {@link #restore(Object)} operation. + * + * @param bizLogic biz logic + * @param the return type of biz logic + * @return the return value of biz logic + * @throws Exception exception threw by biz logic + * @see #clear() + * @see #restore(Object) + * @since 2.9.0 + */ + public static R runCallableWithClear(@NotNull Callable bizLogic) throws Exception { + Object backup = clear(); + try { + return bizLogic.call(); + } finally { + restore(backup); + } + } + + private static volatile WeakHashMap, TtlCopier> threadLocalHolder = new WeakHashMap, TtlCopier>(); + private static final Object threadLocalHolderUpdateLock = new Object(); + private static final Object threadLocalClearMark = new Object(); + + /** + * Register the {@link ThreadLocal}(including subclass {@link InheritableThreadLocal}) instances + * to enhance the Transmittable ability for the existed {@link ThreadLocal} instances. + *

+ * If the registered {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}. + * since a {@link TransmittableThreadLocal} instance itself has the {@code Transmittable} ability, + * it is unnecessary to register a {@link TransmittableThreadLocal} instance. + * + * @param threadLocal the {@link ThreadLocal} instance that to enhance the Transmittable ability + * @param copier the {@link TtlCopier} + * @return {@code true} if register the {@link ThreadLocal} instance and set {@code copier}, otherwise {@code false} + * @see #registerThreadLocal(ThreadLocal, TtlCopier, boolean) + * @since 2.11.0 + */ + public static boolean registerThreadLocal(@NotNull ThreadLocal threadLocal, @NotNull TtlCopier copier) { + return registerThreadLocal(threadLocal, copier, false); + } + + /** + * Register the {@link ThreadLocal}(including subclass {@link InheritableThreadLocal}) instances + * to enhance the Transmittable ability for the existed {@link ThreadLocal} instances. + *

+ * Use the shadow copier(transmit the reference directly), + * and should use {@link #registerThreadLocal(ThreadLocal, TtlCopier)} to pass a {@link TtlCopier} explicitly + * if a different behavior is desired. + *

+ * If the registered {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}. + * since a {@link TransmittableThreadLocal} instance itself has the {@code Transmittable} ability, + * it is unnecessary to register a {@link TransmittableThreadLocal} instance. + * + * @param threadLocal the {@link ThreadLocal} instance that to enhance the Transmittable ability + * @return {@code true} if register the {@link ThreadLocal} instance and set {@code copier}, otherwise {@code false} + * @see #registerThreadLocal(ThreadLocal, TtlCopier) + * @see #registerThreadLocal(ThreadLocal, TtlCopier, boolean) + * @since 2.11.0 + */ + @SuppressWarnings("unchecked") + public static boolean registerThreadLocalWithShadowCopier(@NotNull ThreadLocal threadLocal) { + return registerThreadLocal(threadLocal, (TtlCopier) shadowCopier, false); + } + + /** + * Register the {@link ThreadLocal}(including subclass {@link InheritableThreadLocal}) instances + * to enhance the Transmittable ability for the existed {@link ThreadLocal} instances. + *

+ * If the registered {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}. + * since a {@link TransmittableThreadLocal} instance itself has the {@code Transmittable} ability, + * it is unnecessary to register a {@link TransmittableThreadLocal} instance. + * + * @param threadLocal the {@link ThreadLocal} instance that to enhance the Transmittable ability + * @param copier the {@link TtlCopier} + * @param force if {@code true}, update {@code copier} to {@link ThreadLocal} instance + * when a {@link ThreadLocal} instance is already registered; otherwise, ignore. + * @return {@code true} if register the {@link ThreadLocal} instance and set {@code copier}, otherwise {@code false} + * @see #registerThreadLocal(ThreadLocal, TtlCopier) + * @since 2.11.0 + */ + @SuppressWarnings("unchecked") + public static boolean registerThreadLocal(@NotNull ThreadLocal threadLocal, @NotNull TtlCopier copier, boolean force) { + if (threadLocal instanceof TransmittableThreadLocal) { + logger.warning("register a TransmittableThreadLocal instance, this is unnecessary!"); + return true; + } + + synchronized (threadLocalHolderUpdateLock) { + if (!force && threadLocalHolder.containsKey(threadLocal)) return false; + + WeakHashMap, TtlCopier> newHolder = new WeakHashMap, TtlCopier>(threadLocalHolder); + newHolder.put((ThreadLocal) threadLocal, (TtlCopier) copier); + threadLocalHolder = newHolder; + return true; + } + } + + /** + * Register the {@link ThreadLocal}(including subclass {@link InheritableThreadLocal}) instances + * to enhance the Transmittable ability for the existed {@link ThreadLocal} instances. + *

+ * Use the shadow copier(transmit the reference directly), + * and should use {@link #registerThreadLocal(ThreadLocal, TtlCopier, boolean)} to pass a {@link TtlCopier} explicitly + * if a different behavior is desired. + *

+ * If the registered {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}. + * since a {@link TransmittableThreadLocal} instance itself has the {@code Transmittable} ability, + * it is unnecessary to register a {@link TransmittableThreadLocal} instance. + * + * @param threadLocal the {@link ThreadLocal} instance that to enhance the Transmittable ability + * @param force if {@code true}, update {@code copier} to {@link ThreadLocal} instance + * when a {@link ThreadLocal} instance is already registered; otherwise, ignore. + * @return {@code true} if register the {@link ThreadLocal} instance and set {@code copier}, otherwise {@code false} + * @see #registerThreadLocal(ThreadLocal, TtlCopier) + * @see #registerThreadLocal(ThreadLocal, TtlCopier, boolean) + * @since 2.11.0 + */ + @SuppressWarnings("unchecked") + public static boolean registerThreadLocalWithShadowCopier(@NotNull ThreadLocal threadLocal, boolean force) { + return registerThreadLocal(threadLocal, (TtlCopier) shadowCopier, force); + } + + /** + * Unregister the {@link ThreadLocal} instances + * to remove the Transmittable ability for the {@link ThreadLocal} instances. + *

+ * If the {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}. + * + * @see #registerThreadLocal(ThreadLocal, TtlCopier) + * @see #registerThreadLocalWithShadowCopier(ThreadLocal) + * @since 2.11.0 + */ + public static boolean unregisterThreadLocal(@NotNull ThreadLocal threadLocal) { + if (threadLocal instanceof TransmittableThreadLocal) { + logger.warning("unregister a TransmittableThreadLocal instance, this is unnecessary!"); + return true; + } + + synchronized (threadLocalHolderUpdateLock) { + if (!threadLocalHolder.containsKey(threadLocal)) return false; + + WeakHashMap, TtlCopier> newHolder = new WeakHashMap, TtlCopier>(threadLocalHolder); + newHolder.remove(threadLocal); + threadLocalHolder = newHolder; + return true; + } + } + + private static final TtlCopier shadowCopier = new TtlCopier() { + @Override + public Object copy(Object parentValue) { + return parentValue; + } + }; + + private Transmitter() { + throw new InstantiationError("Must not instantiate this class"); + } + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCallable.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCallable.java new file mode 100644 index 000000000..c4c937216 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCallable.java @@ -0,0 +1,262 @@ +package com.fr.third.alibaba.ttl; + +import com.fr.third.alibaba.ttl.spi.TtlAttachments; +import com.fr.third.alibaba.ttl.spi.TtlAttachmentsDelegate; +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import com.fr.third.alibaba.ttl.spi.TtlWrapper; +import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicReference; + +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.*; + +/** + * {@link TtlCallable} decorate {@link Callable}, so as to get {@link TransmittableThreadLocal} + * and transmit it to the time of {@link Callable} execution, needed when use {@link Callable} to thread pool. + *

+ * Use factory method {@link #get(Callable)} to get decorated instance. + *

+ * Other TTL Wrapper for common {@code Functional Interface} see {@link TtlWrappers}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see TtlExecutors + * @see TtlWrappers + * @see java.util.concurrent.Executor + * @see java.util.concurrent.ExecutorService + * @see java.util.concurrent.ThreadPoolExecutor + * @see java.util.concurrent.ScheduledThreadPoolExecutor + * @see java.util.concurrent.Executors + * @see java.util.concurrent.CompletionService + * @see java.util.concurrent.ExecutorCompletionService + * @since 0.9.0 + */ +public final class TtlCallable implements Callable, TtlWrapper>, TtlEnhanced, TtlAttachments { + private final AtomicReference capturedRef; + private final Callable callable; + private final boolean releaseTtlValueReferenceAfterCall; + + private TtlCallable(@NotNull Callable callable, boolean releaseTtlValueReferenceAfterCall) { + this.capturedRef = new AtomicReference(capture()); + this.callable = callable; + this.releaseTtlValueReferenceAfterCall = releaseTtlValueReferenceAfterCall; + } + + /** + * wrap method {@link Callable#call()}. + */ + @Override + public V call() throws Exception { + Object captured = capturedRef.get(); + if (captured == null || releaseTtlValueReferenceAfterCall && !capturedRef.compareAndSet(captured, null)) { + throw new IllegalStateException("TTL value reference is released after call!"); + } + + Object backup = replay(captured); + try { + return callable.call(); + } finally { + restore(backup); + } + } + + /** + * return the original/underneath {@link Callable}. + */ + @NotNull + public Callable getCallable() { + return unwrap(); + } + + /** + * unwrap to the original/underneath {@link Callable}. + * + * @see TtlUnwrap#unwrap(Object) + * @since 2.11.4 + */ + @NotNull + @Override + public Callable unwrap() { + return callable; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TtlCallable that = (TtlCallable) o; + + return callable.equals(that.callable); + } + + @Override + public int hashCode() { + return callable.hashCode(); + } + + @Override + public String toString() { + return this.getClass().getName() + " - " + callable.toString(); + } + + /** + * Factory method, wrap input {@link Callable} to {@link TtlCallable}. + *

+ * This method is idempotent. + * + * @param callable input {@link Callable} + * @return Wrapped {@link Callable} + */ + @Nullable + public static TtlCallable get(@Nullable Callable callable) { + return get(callable, false); + } + + + /** + * Factory method, wrap input {@link Callable} to {@link TtlCallable}. + *

+ * This method is idempotent. + * + * @param callable input {@link Callable} + * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred. + * @return Wrapped {@link Callable} + */ + @Nullable + public static TtlCallable get(@Nullable Callable callable, boolean releaseTtlValueReferenceAfterCall) { + return get(callable, releaseTtlValueReferenceAfterCall, false); + } + + /** + * Factory method, wrap input {@link Callable} to {@link TtlCallable}. + *

+ * This method is idempotent. + * + * @param callable input {@link Callable} + * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred. + * @param idempotent is idempotent or not. {@code true} will cover up bugs! DO NOT set, only when you know why. + * @return Wrapped {@link Callable} + */ + @Nullable + public static TtlCallable get(@Nullable Callable callable, boolean releaseTtlValueReferenceAfterCall, boolean idempotent) { + if (null == callable) return null; + + if (callable instanceof TtlEnhanced) { + // avoid redundant decoration, and ensure idempotency + if (idempotent) return (TtlCallable) callable; + else throw new IllegalStateException("Already TtlCallable!"); + } + return new TtlCallable(callable, releaseTtlValueReferenceAfterCall); + } + + /** + * wrap input {@link Callable} Collection to {@link TtlCallable} Collection. + * + * @param tasks task to be wrapped + * @return Wrapped {@link Callable} + */ + @NotNull + public static List> gets(@Nullable Collection> tasks) { + return gets(tasks, false, false); + } + + /** + * wrap input {@link Callable} Collection to {@link TtlCallable} Collection. + * + * @param tasks task to be wrapped + * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred. + * @return Wrapped {@link Callable} + */ + @NotNull + public static List> gets(@Nullable Collection> tasks, boolean releaseTtlValueReferenceAfterCall) { + return gets(tasks, releaseTtlValueReferenceAfterCall, false); + } + + /** + * wrap input {@link Callable} Collection to {@link TtlCallable} Collection. + * + * @param tasks task to be wrapped + * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred. + * @param idempotent is idempotent or not. {@code true} will cover up bugs! DO NOT set, only when you know why. + * @return Wrapped {@link Callable} + */ + @NotNull + public static List> gets(@Nullable Collection> tasks, boolean releaseTtlValueReferenceAfterCall, boolean idempotent) { + if (null == tasks) return Collections.emptyList(); + + List> copy = new ArrayList>(); + for (Callable task : tasks) { + copy.add(TtlCallable.get(task, releaseTtlValueReferenceAfterCall, idempotent)); + } + return copy; + } + + /** + * Unwrap {@link TtlCallable} to the original/underneath one. + *

+ * this method is {@code null}-safe, when input {@code Callable} parameter is {@code null}, return {@code null}; + * if input {@code Callable} parameter is not a {@link TtlCallable} just return input {@code Callable}. + *

+ * so {@code TtlCallable.unwrap(TtlCallable.get(callable))} will always return the same input {@code callable} object. + * + * @see #get(Callable) + * @since 2.10.2 + */ + @Nullable + public static Callable unwrap(@Nullable Callable callable) { + if (!(callable instanceof TtlCallable)) return callable; + else return ((TtlCallable) callable).getCallable(); + } + + /** + * Unwrap {@link TtlCallable} to the original/underneath one. + *

+ * Invoke {@link #unwrap(Callable)} for each element in input collection. + *

+ * This method is {@code null}-safe, when input {@code Callable} parameter is {@code null}, return a empty list. + * + * @see #gets(Collection) + * @see #unwrap(Callable) + * @since 2.10.2 + */ + @NotNull + public static List> unwraps(@Nullable Collection> tasks) { + if (null == tasks) return Collections.emptyList(); + + List> copy = new ArrayList>(); + for (Callable task : tasks) { + if (!(task instanceof TtlCallable)) copy.add(task); + else copy.add(((TtlCallable) task).getCallable()); + } + return copy; + } + + private final TtlAttachmentsDelegate ttlAttachment = new TtlAttachmentsDelegate(); + + /** + * see {@link TtlAttachments#setTtlAttachment(String, Object)} + * + * @since 2.11.0 + */ + @Override + public void setTtlAttachment(@NotNull String key, Object value) { + ttlAttachment.setTtlAttachment(key, value); + } + + /** + * see {@link TtlAttachments#getTtlAttachment(String)} + * + * @since 2.11.0 + */ + @Override + public T getTtlAttachment(@NotNull String key) { + return ttlAttachment.getTtlAttachment(key); + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCopier.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCopier.java new file mode 100644 index 000000000..6135a2531 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCopier.java @@ -0,0 +1,29 @@ +package com.fr.third.alibaba.ttl; + +/** + * TtlCopier creates the value when {@link TransmittableThreadLocal.Transmitter#capture()}, + * use the created value when {@link TransmittableThreadLocal.Transmitter#replay(Object)} + * + * @see TransmittableThreadLocal.Transmitter + * @see TransmittableThreadLocal.Transmitter#capture() + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.11.0 + */ +@FunctionalInterface +public interface TtlCopier { + /** + * Computes the value for {@link TransmittableThreadLocal} + * or registered {@link ThreadLocal}(registered by {@link TransmittableThreadLocal.Transmitter#registerThreadLocal}) + * as a function of the source thread's value at the time the task + * Object is created. + *

+ * This method is called from {@link TtlRunnable} or + * {@link TtlCallable} when it create, before the task is started + * (aka. called when {@link TransmittableThreadLocal.Transmitter#capture()}). + * + * @see TransmittableThreadLocal.Transmitter#registerThreadLocal(ThreadLocal, TtlCopier) + * @see TransmittableThreadLocal.Transmitter#registerThreadLocalWithShadowCopier(ThreadLocal) + * @see TransmittableThreadLocal.Transmitter#unregisterThreadLocal + */ + T copy(T parentValue); +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlEnhanced.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlEnhanced.java new file mode 100644 index 000000000..9849dadcf --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlEnhanced.java @@ -0,0 +1,15 @@ +package com.fr.third.alibaba.ttl; + +import com.fr.third.alibaba.ttl.spi.TtlAttachments; + + +/** + * @see TtlAttachments + * @deprecated Use {@link com.fr.third.alibaba.ttl.spi.TtlEnhanced} instead. + */ +@Deprecated + +// [ERROR] The class name com.alibaba.ttl.TtlEnhanced shadows +// the simple name of implemented interface com.alibaba.ttl.spi.TtlEnhanced [com.alibaba.ttl.TtlEnhanced] +public interface TtlEnhanced extends com.fr.third.alibaba.ttl.spi.TtlEnhanced { +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRecursiveAction.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRecursiveAction.java new file mode 100644 index 000000000..4b0b392a1 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRecursiveAction.java @@ -0,0 +1,63 @@ +package com.fr.third.alibaba.ttl; + +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import com.fr.third.alibaba.ttl.threadpool.TtlForkJoinPoolHelper; +import com.fr.third.alibaba.ttl.threadpool.agent.TtlAgent; + +import java.util.concurrent.ForkJoinTask; + +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.*; + +/** + * A recursive resultless {@link ForkJoinTask} enhanced by {@link TransmittableThreadLocal}. + *

+ * Recommend to use {@link TtlAgent}; + * Specially for {@code Java 8} {@link java.util.stream.Stream} and {@link java.util.concurrent.CompletableFuture}, + * these async task are executed by {@link java.util.concurrent.ForkJoinPool} via {@link ForkJoinTask} at the bottom. + * + * @author LNAmp + * @see java.util.concurrent.RecursiveAction + * @see TtlForkJoinPoolHelper + * @see TtlAgent + * @since 2.4.0 + */ +public abstract class TtlRecursiveAction extends ForkJoinTask implements TtlEnhanced { + + private static final long serialVersionUID = -5753568484583412377L; + + private final Object captured = capture(); + + protected TtlRecursiveAction() { + } + + /** + * The main computation performed by this task. + */ + protected abstract void compute(); + + /** + * see {@link ForkJoinTask#getRawResult()} + */ + public final Void getRawResult() { + return null; + } + + /** + * see {@link ForkJoinTask#setRawResult(Object)} + */ + protected final void setRawResult(Void mustBeNull) { + } + + /** + * Implements execution conventions for RecursiveActions. + */ + protected final boolean exec() { + Object backup = replay(captured); + try { + compute(); + return true; + } finally { + restore(backup); + } + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRecursiveTask.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRecursiveTask.java new file mode 100644 index 000000000..6869c9aba --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRecursiveTask.java @@ -0,0 +1,72 @@ +package com.fr.third.alibaba.ttl; + +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import com.fr.third.alibaba.ttl.threadpool.TtlForkJoinPoolHelper; +import com.fr.third.alibaba.ttl.threadpool.agent.TtlAgent; + +import java.util.concurrent.ForkJoinTask; + +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.*; + +/** + * A recursive result-bearing {@link ForkJoinTask} enhanced by {@link TransmittableThreadLocal}. + *

+ * Recommend to use {@link TtlAgent}; + * Specially for {@code Java 8} {@link java.util.stream.Stream} and {@link java.util.concurrent.CompletableFuture}, + * these async task are executed by {@link java.util.concurrent.ForkJoinPool} via {@link ForkJoinTask} at the bottom. + * + * @author LNAmp + * @see java.util.concurrent.RecursiveTask + * @see TtlForkJoinPoolHelper + * @see TtlAgent + * @since 2.4.0 + */ +public abstract class TtlRecursiveTask extends ForkJoinTask implements TtlEnhanced { + + private static final long serialVersionUID = 1814679366926362436L; + + private final Object captured = capture(); + + protected TtlRecursiveTask() { + } + + /** + * The result of the computation. + */ + V result; + + /** + * The main computation performed by this task. + * + * @return the result of the computation + */ + protected abstract V compute(); + + /** + * see {@link ForkJoinTask#getRawResult()} + */ + public final V getRawResult() { + return result; + } + + /** + * see {@link ForkJoinTask#setRawResult(Object)} + */ + protected final void setRawResult(V value) { + result = value; + } + + /** + * Implements execution conventions for RecursiveTask. + */ + protected final boolean exec() { + Object backup = replay(captured); + try { + result = compute(); + return true; + } finally { + restore(backup); + } + } + +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRunnable.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRunnable.java new file mode 100644 index 000000000..e859150dd --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRunnable.java @@ -0,0 +1,262 @@ +package com.fr.third.alibaba.ttl; + +import com.fr.third.alibaba.ttl.spi.TtlAttachments; +import com.fr.third.alibaba.ttl.spi.TtlAttachmentsDelegate; +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import com.fr.third.alibaba.ttl.spi.TtlWrapper; +import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.*; + +/** + * {@link TtlRunnable} decorate {@link Runnable}, so as to get {@link TransmittableThreadLocal} + * and transmit it to the time of {@link Runnable} execution, needed when use {@link Runnable} to thread pool. + *

+ * Use factory methods {@link #get} / {@link #gets} to create instance. + *

+ * Other TTL Wrapper for common {@code Functional Interface} see {@link TtlWrappers}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see TtlExecutors + * @see TtlWrappers + * @see java.util.concurrent.Executor + * @see java.util.concurrent.ExecutorService + * @see java.util.concurrent.ThreadPoolExecutor + * @see java.util.concurrent.ScheduledThreadPoolExecutor + * @see java.util.concurrent.Executors + * @since 0.9.0 + */ +public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnhanced, TtlAttachments { + private final AtomicReference capturedRef; + private final Runnable runnable; + private final boolean releaseTtlValueReferenceAfterRun; + + private TtlRunnable(@NotNull Runnable runnable, boolean releaseTtlValueReferenceAfterRun) { + this.capturedRef = new AtomicReference(capture()); + this.runnable = runnable; + this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun; + } + + /** + * wrap method {@link Runnable#run()}. + */ + @Override + public void run() { + Object captured = capturedRef.get(); + if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) { + throw new IllegalStateException("TTL value reference is released after run!"); + } + + Object backup = replay(captured); + try { + runnable.run(); + } finally { + restore(backup); + } + } + + /** + * return original/unwrapped {@link Runnable}. + */ + @NotNull + public Runnable getRunnable() { + return unwrap(); + } + + /** + * unwrap to original/unwrapped {@link Runnable}. + * + * @see TtlUnwrap#unwrap(Object) + * @since 2.11.4 + */ + @NotNull + @Override + public Runnable unwrap() { + return runnable; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TtlRunnable that = (TtlRunnable) o; + + return runnable.equals(that.runnable); + } + + @Override + public int hashCode() { + return runnable.hashCode(); + } + + @Override + public String toString() { + return this.getClass().getName() + " - " + runnable.toString(); + } + + /** + * Factory method, wrap input {@link Runnable} to {@link TtlRunnable}. + * + * @param runnable input {@link Runnable}. if input is {@code null}, return {@code null}. + * @return Wrapped {@link Runnable} + * @throws IllegalStateException when input is {@link TtlRunnable} already. + */ + @Nullable + public static TtlRunnable get(@Nullable Runnable runnable) { + return get(runnable, false, false); + } + + /** + * Factory method, wrap input {@link Runnable} to {@link TtlRunnable}. + * + * @param runnable input {@link Runnable}. if input is {@code null}, return {@code null}. + * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred. + * @return Wrapped {@link Runnable} + * @throws IllegalStateException when input is {@link TtlRunnable} already. + */ + @Nullable + public static TtlRunnable get(@Nullable Runnable runnable, boolean releaseTtlValueReferenceAfterRun) { + return get(runnable, releaseTtlValueReferenceAfterRun, false); + } + + /** + * Factory method, wrap input {@link Runnable} to {@link TtlRunnable}. + * + * @param runnable input {@link Runnable}. if input is {@code null}, return {@code null}. + * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred. + * @param idempotent is idempotent mode or not. if {@code true}, just return input {@link Runnable} when it's {@link TtlRunnable}, + * otherwise throw {@link IllegalStateException}. + * Caution: {@code true} will cover up bugs! DO NOT set, only when you know why. + * @return Wrapped {@link Runnable} + * @throws IllegalStateException when input is {@link TtlRunnable} already and not idempotent. + */ + @Nullable + public static TtlRunnable get(@Nullable Runnable runnable, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) { + if (null == runnable) return null; + + if (runnable instanceof TtlEnhanced) { + // avoid redundant decoration, and ensure idempotency + if (idempotent) return (TtlRunnable) runnable; + else throw new IllegalStateException("Already TtlRunnable!"); + } + return new TtlRunnable(runnable, releaseTtlValueReferenceAfterRun); + } + + /** + * wrap input {@link Runnable} Collection to {@link TtlRunnable} Collection. + * + * @param tasks task to be wrapped. if input is {@code null}, return {@code null}. + * @return wrapped tasks + * @throws IllegalStateException when input is {@link TtlRunnable} already. + */ + @NotNull + public static List gets(@Nullable Collection tasks) { + return gets(tasks, false, false); + } + + /** + * wrap input {@link Runnable} Collection to {@link TtlRunnable} Collection. + * + * @param tasks task to be wrapped. if input is {@code null}, return {@code null}. + * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred. + * @return wrapped tasks + * @throws IllegalStateException when input is {@link TtlRunnable} already. + */ + @NotNull + public static List gets(@Nullable Collection tasks, boolean releaseTtlValueReferenceAfterRun) { + return gets(tasks, releaseTtlValueReferenceAfterRun, false); + } + + /** + * wrap input {@link Runnable} Collection to {@link TtlRunnable} Collection. + * + * @param tasks task to be wrapped. if input is {@code null}, return {@code null}. + * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred. + * @param idempotent is idempotent mode or not. if {@code true}, just return input {@link Runnable} when it's {@link TtlRunnable}, + * otherwise throw {@link IllegalStateException}. + * Caution: {@code true} will cover up bugs! DO NOT set, only when you know why. + * @return wrapped tasks + * @throws IllegalStateException when input is {@link TtlRunnable} already and not idempotent. + */ + @NotNull + public static List gets(@Nullable Collection tasks, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) { + if (null == tasks) return Collections.emptyList(); + + List copy = new ArrayList(); + for (Runnable task : tasks) { + copy.add(TtlRunnable.get(task, releaseTtlValueReferenceAfterRun, idempotent)); + } + return copy; + } + + /** + * Unwrap {@link TtlRunnable} to the original/underneath one. + *

+ * this method is {@code null}-safe, when input {@code Runnable} parameter is {@code null}, return {@code null}; + * if input {@code Runnable} parameter is not a {@link TtlRunnable} just return input {@code Runnable}. + *

+ * so {@code TtlRunnable.unwrap(TtlRunnable.get(runnable))} will always return the same input {@code runnable} object. + * + * @see #get(Runnable) + * @since 2.10.2 + */ + @Nullable + public static Runnable unwrap(@Nullable Runnable runnable) { + if (!(runnable instanceof TtlRunnable)) return runnable; + else return ((TtlRunnable) runnable).getRunnable(); + } + + /** + * Unwrap {@link TtlRunnable} to the original/underneath one for collection. + *

+ * Invoke {@link #unwrap(Runnable)} for each element in input collection. + *

+ * This method is {@code null}-safe, when input {@code Runnable} parameter is {@code null}, return a empty list. + * + * @see #gets(Collection) + * @see #unwrap(Runnable) + * @since 2.10.2 + */ + @NotNull + public static List unwraps(@Nullable Collection tasks) { + if (null == tasks) return Collections.emptyList(); + + List copy = new ArrayList(); + for (Runnable task : tasks) { + if (!(task instanceof TtlRunnable)) copy.add(task); + else copy.add(((TtlRunnable) task).getRunnable()); + } + return copy; + } + + private final TtlAttachmentsDelegate ttlAttachment = new TtlAttachmentsDelegate(); + + /** + * see {@link TtlAttachments#setTtlAttachment(String, Object)} + * + * @since 2.11.0 + */ + @Override + public void setTtlAttachment(@NotNull String key, Object value) { + ttlAttachment.setTtlAttachment(key, value); + } + + /** + * see {@link TtlAttachments#getTtlAttachment(String)} + * + * @since 2.11.0 + */ + @Override + public T getTtlAttachment(@NotNull String key) { + return ttlAttachment.getTtlAttachment(key); + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlTimerTask.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlTimerTask.java new file mode 100644 index 000000000..448c8ff12 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlTimerTask.java @@ -0,0 +1,193 @@ +package com.fr.third.alibaba.ttl; + +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import com.fr.third.alibaba.ttl.spi.TtlWrapper; +import com.fr.third.alibaba.ttl.threadpool.agent.TtlAgent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.*; + +/** + * {@link TtlTimerTask} decorate {@link TimerTask}, so as to get {@link TransmittableThreadLocal} + * and transmit it to the time of {@link TtlTimerTask} execution, needed when use {@link TtlTimerTask} to {@link java.util.TimerTask}. + *

+ * Use factory method {@link #get(TimerTask)} to create instance. + *

+ * NOTE: + * The {@link TtlTimerTask} make the method {@link TimerTask#scheduledExecutionTime()} in + * the origin {@link TimerTask} lose effectiveness! Use {@link TtlAgent} instead. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see java.util.Timer + * @see TimerTask + * @see Alibaba Java Coding Guidelines - Concurrency - Item 10: [Mandatory] Run multiple TimeTask by using ScheduledExecutorService rather than Timer because Timer will kill all running threads in case of failing to catch exceptions. + * @see TtlAgent + * @since 0.9.1 + * @deprecated Use {@link TtlRunnable}, {@link java.util.concurrent.ScheduledExecutorService} instead of {@link java.util.Timer}, {@link java.util.TimerTask}. + */ +@Deprecated +public final class TtlTimerTask extends TimerTask implements TtlWrapper, com.fr.third.alibaba.ttl.spi.TtlEnhanced { + private final AtomicReference capturedRef; + private final TimerTask timerTask; + private final boolean releaseTtlValueReferenceAfterRun; + + private TtlTimerTask(@NotNull TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun) { + this.capturedRef = new AtomicReference(capture()); + this.timerTask = timerTask; + this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun; + } + + /** + * wrap method {@link TimerTask#run()}. + */ + @Override + public void run() { + Object captured = capturedRef.get(); + if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) { + throw new IllegalStateException("TTL value reference is released after run!"); + } + + Object backup = replay(captured); + try { + timerTask.run(); + } finally { + restore(backup); + } + } + + @Override + public boolean cancel() { + timerTask.cancel(); + return super.cancel(); + } + + /** + * return original/unwrapped {@link TimerTask}. + */ + @NotNull + public TimerTask getTimerTask() { + return unwrap(); + } + + /** + * unwrap to original/unwrapped {@link TimerTask}. + * + * @see TtlUnwrap#unwrap(Object) + * @since 2.11.4 + */ + @NotNull + @Override + public TimerTask unwrap() { + return timerTask; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TtlTimerTask that = (TtlTimerTask) o; + + return timerTask.equals(that.timerTask); + } + + @Override + public int hashCode() { + return timerTask != null ? timerTask.hashCode() : 0; + } + + @Override + public String toString() { + return this.getClass().getName() + " - " + timerTask.toString(); + } + + /** + * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}. + *

+ * This method is idempotent. + * + * @param timerTask input {@link TimerTask} + * @return Wrapped {@link TimerTask} + */ + @Nullable + public static TtlTimerTask get(@Nullable TimerTask timerTask) { + return get(timerTask, false, false); + } + + /** + * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}. + *

+ * This method is idempotent. + * + * @param timerTask input {@link TimerTask} + * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlTimerTask} is referred. + * @return Wrapped {@link TimerTask} + */ + @Nullable + public static TtlTimerTask get(@Nullable TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun) { + return get(timerTask, releaseTtlValueReferenceAfterRun, false); + } + + /** + * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}. + *

+ * This method is idempotent. + * + * @param timerTask input {@link TimerTask} + * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlTimerTask} is referred. + * @param idempotent is idempotent or not. {@code true} will cover up bugs! DO NOT set, only when you know why. + * @return Wrapped {@link TimerTask} + */ + @Nullable + public static TtlTimerTask get(@Nullable TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) { + if (null == timerTask) return null; + + if (timerTask instanceof TtlEnhanced) { + // avoid redundant decoration, and ensure idempotency + if (idempotent) return (TtlTimerTask) timerTask; + else throw new IllegalStateException("Already TtlTimerTask!"); + } + return new TtlTimerTask(timerTask, releaseTtlValueReferenceAfterRun); + } + + /** + * Unwrap {@link TtlTimerTask} to the original/underneath one. + *

+ * this method is {@code null}-safe, when input {@code TimerTask} parameter is {@code null}, return {@code null}; + * if input {@code TimerTask} parameter is not a {@link TtlTimerTask} just return input {@code TimerTask}. + * + * @see #get(TimerTask) + * @since 2.10.2 + */ + @Nullable + public static TimerTask unwrap(@Nullable TimerTask timerTask) { + if (!(timerTask instanceof TtlTimerTask)) return timerTask; + else return ((TtlTimerTask) timerTask).getTimerTask(); + } + + /** + * Unwrap {@link TtlTimerTask} to the original/underneath one. + *

+ * Invoke {@link #unwrap(TimerTask)} for each element in input collection. + *

+ * This method is {@code null}-safe, when input {@code TimerTask} parameter is {@code null}, return a empty list. + * + * @see #unwrap(TimerTask) + * @since 2.10.2 + */ + @NotNull + public static List unwraps(@Nullable Collection tasks) { + if (null == tasks) return Collections.emptyList(); + + List copy = new ArrayList(); + for (TimerTask task : tasks) { + if (!(task instanceof TtlTimerTask)) copy.add(task); + else copy.add(((TtlTimerTask) task).getTimerTask()); + } + return copy; + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlUnwrap.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlUnwrap.java new file mode 100644 index 000000000..82a87b63c --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlUnwrap.java @@ -0,0 +1,70 @@ +package com.fr.third.alibaba.ttl; + +import com.fr.third.alibaba.ttl.spi.TtlWrapper; +import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; +import com.fr.third.alibaba.ttl.threadpool.TtlForkJoinPoolHelper; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.Callable; + +/** + * Util methods for TTL Wrapper: unwrap TTL Wrapper and check TTL Wrapper. + *

+ * Note: + * all methods is {@code null}-safe, when input parameter is {@code null}, return {@code null}. + *

+ * Implementation Note: + * The util methods in this class should have been inside {@link TtlWrappers}.
+ * But for {@code Java 6} support, it's required splitting the util methods + * which involved {@code Java 8} from {@link TtlWrappers}. + * In order to avoid loading {@code Java 8} class (eg: {@link java.util.function.Consumer}, {@link java.util.function.Supplier}), + * when invoking any methods of {@link TtlWrappers}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see TtlWrappers + * @see TtlWrapper + * @see TtlRunnable + * @see TtlCallable + * @since 2.11.4 + */ +public class TtlUnwrap { + /** + * Generic unwrap method, unwrap {@code TtlWrapper} to the original/underneath one. + *

+ * this method is {@code null}-safe, when input {@code BiFunction} parameter is {@code null}, return {@code null}; + * if input parameter is not a {@code TtlWrapper} just return input. + *

+ * so {@code unwrap} will always return the same input object. + * + * @see TtlWrappers#wrap(java.util.function.Supplier) + * @see TtlWrappers#wrap(java.util.function.Consumer) + * @see TtlWrappers#wrap(java.util.function.BiConsumer) + * @see TtlWrappers#wrap(java.util.function.Function) + * @see TtlWrappers#wrap(java.util.function.BiFunction) + * @see TtlRunnable#unwrap(Runnable) + * @see TtlCallable#unwrap(Callable) + * @see TtlExecutors#unwrap(java.util.concurrent.Executor) + * @see TtlExecutors#unwrap(java.util.concurrent.ThreadFactory) + * @see TtlForkJoinPoolHelper#unwrap(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory) + * @since 2.11.4 + */ + @Nullable + @SuppressWarnings("unchecked") + public static T unwrap(@Nullable T obj) { + if (!isWrapper(obj)) return obj; + else return ((TtlWrapper) obj).unwrap(); + } + + /** + * check the input object is a {@code TtlWrapper} or not. + * + * @since 2.11.4 + */ + public static boolean isWrapper(@Nullable T obj) { + return obj instanceof TtlWrapper; + } + + private TtlUnwrap() { + throw new InstantiationError("Must not instantiate this class"); + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlWrappers.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlWrappers.java new file mode 100644 index 000000000..d932c3568 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlWrappers.java @@ -0,0 +1,342 @@ +package com.fr.third.alibaba.ttl; + +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import com.fr.third.alibaba.ttl.spi.TtlWrapper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.*; + +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.*; + +/** + * Util methods for TTL Wrapper: wrap common {@code Functional Interface}. + *

+ * Note: + *

    + *
  • all methods is {@code null}-safe, when input parameter is {@code null}, return {@code null}.
  • + *
  • all wrap method skip wrap (aka. just return input parameter), when input parameter is already wrapped.
  • + *
+ * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see TtlRunnable + * @see TtlCallable + * @see TtlUnwrap + * @see TtlWrapper + * @since 2.11.4 + */ +public class TtlWrappers { + /** + * wrap input {@link Supplier} to TTL wrapper. + * + * @param supplier input {@link Supplier} + * @return Wrapped {@link Supplier} + * @see TtlUnwrap#unwrap(Object) + * @since 2.11.4 + */ + @Nullable + public static Supplier wrap(@Nullable Supplier supplier) { + if (supplier == null) return null; + else if (supplier instanceof TtlEnhanced) return supplier; + else return new TtlSupplier(supplier); + } + + private static class TtlSupplier implements Supplier, TtlWrapper>, TtlEnhanced { + final Supplier supplier; + final Object captured; + + TtlSupplier(@NotNull Supplier supplier) { + this.supplier = supplier; + this.captured = capture(); + } + + @Override + public T get() { + final Object backup = replay(captured); + try { + return supplier.get(); + } finally { + restore(backup); + } + } + + @NotNull + @Override + public Supplier unwrap() { + return supplier; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TtlSupplier that = (TtlSupplier) o; + + return supplier.equals(that.supplier); + } + + @Override + public int hashCode() { + return supplier.hashCode(); + } + + @Override + public String toString() { + return this.getClass().getName() + " - " + supplier.toString(); + } + } + + + /** + * wrap input {@link Consumer} to TTL wrapper. + * + * @param consumer input {@link Consumer} + * @return Wrapped {@link Consumer} + * @see TtlUnwrap#unwrap(Object) + * @since 2.11.4 + */ + @Nullable + public static Consumer wrap(@Nullable Consumer consumer) { + if (consumer == null) return null; + else if (consumer instanceof TtlEnhanced) return consumer; + else return new TtlConsumer(consumer); + } + + private static class TtlConsumer implements Consumer, TtlWrapper>, TtlEnhanced { + final Consumer consumer; + final Object captured; + + TtlConsumer(@NotNull Consumer consumer) { + this.consumer = consumer; + this.captured = capture(); + } + + @Override + public void accept(T t) { + final Object backup = replay(captured); + try { + consumer.accept(t); + } finally { + restore(backup); + } + } + + @NotNull + @Override + public Consumer unwrap() { + return consumer; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TtlConsumer that = (TtlConsumer) o; + + return consumer.equals(that.consumer); + } + + @Override + public int hashCode() { + return consumer.hashCode(); + } + + @Override + public String toString() { + return this.getClass().getName() + " - " + consumer.toString(); + } + } + + + /** + * wrap input {@link BiConsumer} to TTL wrapper. + * + * @param consumer input {@link BiConsumer} + * @return Wrapped {@link BiConsumer} + * @see TtlUnwrap#unwrap(Object) + * @since 2.11.4 + */ + @Nullable + public static BiConsumer wrap(@Nullable BiConsumer consumer) { + if (consumer == null) return null; + else if (consumer instanceof TtlEnhanced) return consumer; + else return new TtlBiConsumer(consumer); + } + + private static class TtlBiConsumer implements BiConsumer, TtlWrapper>, TtlEnhanced { + final BiConsumer consumer; + final Object captured; + + TtlBiConsumer(@NotNull BiConsumer consumer) { + this.consumer = consumer; + this.captured = capture(); + } + + @Override + public void accept(T t, U u) { + final Object backup = replay(captured); + try { + consumer.accept(t, u); + } finally { + restore(backup); + } + } + + @NotNull + @Override + public BiConsumer unwrap() { + return consumer; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TtlBiConsumer that = (TtlBiConsumer) o; + + return consumer.equals(that.consumer); + } + + @Override + public int hashCode() { + return consumer.hashCode(); + } + + @Override + public String toString() { + return this.getClass().getName() + " - " + consumer.toString(); + } + } + + + /** + * wrap input {@link Function} to TTL wrapper. + * + * @param fn input {@link Function} + * @return Wrapped {@link Function} + * @see TtlUnwrap#unwrap(Object) + * @since 2.11.4 + */ + @Nullable + public static Function wrap(@Nullable Function fn) { + if (fn == null) return null; + else if (fn instanceof TtlEnhanced) return fn; + else return new TtlFunction(fn); + } + + private static class TtlFunction implements Function, TtlWrapper>, TtlEnhanced { + final Function fn; + final Object captured; + + TtlFunction(@NotNull Function fn) { + this.fn = fn; + this.captured = capture(); + } + + @Override + public R apply(T t) { + final Object backup = replay(captured); + try { + return fn.apply(t); + } finally { + restore(backup); + } + } + + @NotNull + @Override + public Function unwrap() { + return fn; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TtlFunction that = (TtlFunction) o; + + return fn.equals(that.fn); + } + + @Override + public int hashCode() { + return fn.hashCode(); + } + + @Override + public String toString() { + return this.getClass().getName() + " - " + fn.toString(); + } + } + + + /** + * wrap input {@link BiFunction} to TTL wrapper. + * + * @param fn input {@link BiFunction} + * @return Wrapped {@link BiFunction} + * @see TtlUnwrap#unwrap(Object) + * @since 2.11.4 + */ + @Nullable + public static BiFunction wrap(@Nullable BiFunction fn) { + if (fn == null) return null; + else if (fn instanceof TtlEnhanced) return fn; + else return new TtlBiFunction(fn); + } + + private static class TtlBiFunction implements BiFunction, TtlWrapper>, TtlEnhanced { + final BiFunction fn; + final Object captured; + + TtlBiFunction(@NotNull BiFunction fn) { + this.fn = fn; + this.captured = capture(); + } + + @Override + public R apply(T t, U u) { + final Object backup = replay(captured); + try { + return fn.apply(t, u); + } finally { + restore(backup); + } + } + + @NotNull + @Override + public BiFunction unwrap() { + return fn; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TtlBiFunction that = (TtlBiFunction) o; + + return fn.equals(that.fn); + } + + @Override + public int hashCode() { + return fn.hashCode(); + } + + @Override + public String toString() { + return this.getClass().getName() + " - " + fn.toString(); + } + } + + + private TtlWrappers() { + throw new InstantiationError("Must not instantiate this class"); + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/package-info.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/package-info.java new file mode 100644 index 000000000..d842d0a01 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/package-info.java @@ -0,0 +1,9 @@ +/** + * TTL API. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see com.fr.third.alibaba.ttl.TransmittableThreadLocal + * @see com.fr.third.alibaba.ttl.TtlRunnable + * @see com.fr.third.alibaba.ttl.TtlCallable + */ +package com.fr.third.alibaba.ttl; diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachments.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachments.java new file mode 100644 index 000000000..d3f83bff2 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachments.java @@ -0,0 +1,39 @@ +package com.fr.third.alibaba.ttl.spi; + +import com.fr.third.alibaba.ttl.TtlCallable; +import com.fr.third.alibaba.ttl.TtlRunnable; +import org.jetbrains.annotations.NotNull; + +/** + * The TTL attachments for TTL tasks, eg: {@link TtlRunnable}, {@link TtlCallable}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.11.0 + */ +public interface TtlAttachments extends TtlEnhanced { + /** + * set the TTL attachments for TTL tasks + * + * @param key attachment key + * @param value attachment value + * @since 2.11.0 + */ + void setTtlAttachment(@NotNull String key, Object value); + + /** + * get the TTL attachment for TTL tasks + * + * @param key attachment key + * @since 2.11.0 + */ + T getTtlAttachment(@NotNull String key); + + /** + * The attachment key of TTL task, weather this task is a auto wrapper task. + *

+ * so the value of this attachment is a {@code boolean}. + * + * @since 2.11.0 + */ + String KEY_IS_AUTO_WRAPPER = "ttl.is.auto.wrapper"; +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachmentsDelegate.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachmentsDelegate.java new file mode 100644 index 000000000..fb50ea218 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachmentsDelegate.java @@ -0,0 +1,31 @@ +package com.fr.third.alibaba.ttl.spi; + +import com.fr.third.alibaba.ttl.TtlCallable; +import com.fr.third.alibaba.ttl.TtlRunnable; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * {@link TtlAttachments} delegate/implementation. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see TtlRunnable + * @see TtlCallable + * @since 2.11.0 + */ +public class TtlAttachmentsDelegate implements TtlAttachments { + private final ConcurrentMap attachments = new ConcurrentHashMap(); + + @Override + public void setTtlAttachment(@NotNull String key, Object value) { + attachments.put(key, value); + } + + @Override + @SuppressWarnings("unchecked") + public T getTtlAttachment(@NotNull String key) { + return (T) attachments.get(key); + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlEnhanced.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlEnhanced.java new file mode 100644 index 000000000..2fe90b789 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlEnhanced.java @@ -0,0 +1,20 @@ +package com.fr.third.alibaba.ttl.spi; + +import com.fr.third.alibaba.ttl.TtlCallable; +import com.fr.third.alibaba.ttl.TtlRecursiveAction; +import com.fr.third.alibaba.ttl.TtlRecursiveTask; +import com.fr.third.alibaba.ttl.TtlRunnable; + +/** + * a Ttl marker/tag interface, for ttl enhanced class, for example {@code TTL wrapper} like {@link TtlRunnable}, {@link TtlCallable}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see TtlRunnable + * @see TtlCallable + * @see TtlRecursiveAction + * @see TtlRecursiveTask + * @see TtlAttachments + * @since 2.11.0 + */ +public interface TtlEnhanced { +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlWrapper.java new file mode 100644 index 000000000..5fd32b1ed --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlWrapper.java @@ -0,0 +1,26 @@ +package com.fr.third.alibaba.ttl.spi; + +import com.fr.third.alibaba.ttl.TtlUnwrap; +import org.jetbrains.annotations.NotNull; + +/** + * Ttl Wrapper interface. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see TtlUnwrap#unwrap + * @since 2.11.4 + */ +public interface TtlWrapper extends TtlEnhanced { + /** + * unwrap {@link TtlWrapper} to the original/underneath one. + *

+ * this method is {@code null}-safe, when input {@code BiFunction} parameter is {@code null}, return {@code null}; + * if input parameter is not a {@code TtlWrapper} just return input. + *

+ * so {@code unwrap} will always return the same input object. + * + * @see TtlUnwrap#unwrap(Object) + */ + @NotNull + T unwrap(); +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/package-info.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/package-info.java new file mode 100644 index 000000000..50919ee22 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/package-info.java @@ -0,0 +1,9 @@ +/** + * TTL SPI + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see com.fr.third.alibaba.ttl.spi.TtlEnhanced + * @see com.fr.third.alibaba.ttl.spi.TtlAttachments + * @since 2.11.0 + */ +package com.fr.third.alibaba.ttl.spi; diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java new file mode 100644 index 000000000..44a508b99 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java @@ -0,0 +1,21 @@ +package com.fr.third.alibaba.ttl.threadpool; + +import com.fr.third.alibaba.ttl.spi.TtlWrapper; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory; + +/** + * Disable inheritable {@link ForkJoinWorkerThreadFactory}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.10.1 + */ +public interface DisableInheritableForkJoinWorkerThreadFactory extends ForkJoinWorkerThreadFactory, TtlWrapper { + /** + * Unwrap {@link DisableInheritableThreadFactory} to the original/underneath one. + */ + @Override + @NotNull + ForkJoinWorkerThreadFactory unwrap(); +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java new file mode 100644 index 000000000..d96b8282a --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java @@ -0,0 +1,58 @@ +package com.fr.third.alibaba.ttl.threadpool; + +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory; +import java.util.concurrent.ForkJoinWorkerThread; + +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.clear; +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.restore; + +/** + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.10.1 + */ +class DisableInheritableForkJoinWorkerThreadFactoryWrapper implements DisableInheritableForkJoinWorkerThreadFactory { + private final ForkJoinWorkerThreadFactory threadFactory; + + DisableInheritableForkJoinWorkerThreadFactoryWrapper(@NotNull ForkJoinWorkerThreadFactory threadFactory) { + this.threadFactory = threadFactory; + } + + @Override + public ForkJoinWorkerThread newThread(ForkJoinPool pool) { + final Object backup = clear(); + try { + return threadFactory.newThread(pool); + } finally { + restore(backup); + } + } + + @Override + @NotNull + public ForkJoinWorkerThreadFactory unwrap() { + return threadFactory; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DisableInheritableForkJoinWorkerThreadFactoryWrapper that = (DisableInheritableForkJoinWorkerThreadFactoryWrapper) o; + + return threadFactory.equals(that.threadFactory); + } + + @Override + public int hashCode() { + return threadFactory.hashCode(); + } + + @Override + public String toString() { + return this.getClass().getName() + " - " + threadFactory.toString(); + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java new file mode 100644 index 000000000..90049cc3e --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java @@ -0,0 +1,22 @@ +package com.fr.third.alibaba.ttl.threadpool; + +import com.fr.third.alibaba.ttl.spi.TtlWrapper; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.ThreadFactory; + +/** + * Disable inheritable {@link ThreadFactory}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see ThreadFactory + * @since 2.10.0 + */ +public interface DisableInheritableThreadFactory extends ThreadFactory, TtlWrapper { + /** + * Unwrap {@link DisableInheritableThreadFactory} to the original/underneath one. + */ + @Override + @NotNull + ThreadFactory unwrap(); +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java new file mode 100644 index 000000000..5ecf93cb0 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java @@ -0,0 +1,56 @@ +package com.fr.third.alibaba.ttl.threadpool; + +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.ThreadFactory; + +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.clear; +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.restore; + +/** + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.10.0 + */ +class DisableInheritableThreadFactoryWrapper implements DisableInheritableThreadFactory { + private final ThreadFactory threadFactory; + + DisableInheritableThreadFactoryWrapper(@NotNull ThreadFactory threadFactory) { + this.threadFactory = threadFactory; + } + + @Override + public Thread newThread(@NotNull Runnable r) { + final Object backup = clear(); + try { + return threadFactory.newThread(r); + } finally { + restore(backup); + } + } + + @NotNull + @Override + public ThreadFactory unwrap() { + return threadFactory; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DisableInheritableThreadFactoryWrapper that = (DisableInheritableThreadFactoryWrapper) o; + + return threadFactory.equals(that.threadFactory); + } + + @Override + public int hashCode() { + return threadFactory.hashCode(); + } + + @Override + public String toString() { + return this.getClass().getName() + " - " + threadFactory.toString(); + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorServiceTtlWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorServiceTtlWrapper.java new file mode 100644 index 000000000..ebb4ea482 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorServiceTtlWrapper.java @@ -0,0 +1,101 @@ +package com.fr.third.alibaba.ttl.threadpool; + +import com.fr.third.alibaba.ttl.TransmittableThreadLocal; +import com.fr.third.alibaba.ttl.TtlCallable; +import com.fr.third.alibaba.ttl.TtlRunnable; +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.*; + +/** + * {@link TransmittableThreadLocal} Wrapper of {@link ExecutorService}, + * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link Callable} + * to the execution time of {@link Runnable} or {@link Callable}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 0.9.0 + */ +class ExecutorServiceTtlWrapper extends ExecutorTtlWrapper implements ExecutorService, TtlEnhanced { + private final ExecutorService executorService; + + ExecutorServiceTtlWrapper(@NotNull ExecutorService executorService) { + super(executorService); + this.executorService = executorService; + } + + @Override + public void shutdown() { + executorService.shutdown(); + } + + @NotNull + @Override + public List shutdownNow() { + return executorService.shutdownNow(); + } + + @Override + public boolean isShutdown() { + return executorService.isShutdown(); + } + + @Override + public boolean isTerminated() { + return executorService.isTerminated(); + } + + @Override + public boolean awaitTermination(long timeout, @NotNull TimeUnit unit) throws InterruptedException { + return executorService.awaitTermination(timeout, unit); + } + + @NotNull + @Override + public Future submit(@NotNull Callable task) { + return executorService.submit(TtlCallable.get(task)); + } + + @NotNull + @Override + public Future submit(@NotNull Runnable task, T result) { + return executorService.submit(TtlRunnable.get(task), result); + } + + @NotNull + @Override + public Future submit(@NotNull Runnable task) { + return executorService.submit(TtlRunnable.get(task)); + } + + @NotNull + @Override + public List> invokeAll(@NotNull Collection> tasks) throws InterruptedException { + return executorService.invokeAll(TtlCallable.gets(tasks)); + } + + @NotNull + @Override + public List> invokeAll(@NotNull Collection> tasks, long timeout, @NotNull TimeUnit unit) throws InterruptedException { + return executorService.invokeAll(TtlCallable.gets(tasks), timeout, unit); + } + + @NotNull + @Override + public T invokeAny(@NotNull Collection> tasks) throws InterruptedException, ExecutionException { + return executorService.invokeAny(TtlCallable.gets(tasks)); + } + + @Override + public T invokeAny(@NotNull Collection> tasks, long timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return executorService.invokeAny(TtlCallable.gets(tasks), timeout, unit); + } + + @NotNull + @Override + public ExecutorService unwrap() { + return executorService; + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorTtlWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorTtlWrapper.java new file mode 100644 index 000000000..87aabac2d --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorTtlWrapper.java @@ -0,0 +1,56 @@ +package com.fr.third.alibaba.ttl.threadpool; + +import com.fr.third.alibaba.ttl.TransmittableThreadLocal; +import com.fr.third.alibaba.ttl.TtlRunnable; +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import com.fr.third.alibaba.ttl.spi.TtlWrapper; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.Executor; + +/** + * {@link TransmittableThreadLocal} Wrapper of {@link Executor}, + * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} + * to the execution time of {@link Runnable}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 0.9.0 + */ +class ExecutorTtlWrapper implements Executor, TtlWrapper, TtlEnhanced { + private final Executor executor; + + ExecutorTtlWrapper(@NotNull Executor executor) { + this.executor = executor; + } + + @Override + public void execute(@NotNull Runnable command) { + executor.execute(TtlRunnable.get(command)); + } + + @Override + @NotNull + public Executor unwrap() { + return executor; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ExecutorTtlWrapper that = (ExecutorTtlWrapper) o; + + return executor.equals(that.executor); + } + + @Override + public int hashCode() { + return executor.hashCode(); + } + + @Override + public String toString() { + return this.getClass().getName() + " - " + executor.toString(); + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ScheduledExecutorServiceTtlWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ScheduledExecutorServiceTtlWrapper.java new file mode 100644 index 000000000..dd1ea268e --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ScheduledExecutorServiceTtlWrapper.java @@ -0,0 +1,61 @@ +package com.fr.third.alibaba.ttl.threadpool; + +import com.fr.third.alibaba.ttl.TransmittableThreadLocal; +import com.fr.third.alibaba.ttl.TtlCallable; +import com.fr.third.alibaba.ttl.TtlRunnable; +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import org.jetbrains.annotations.NotNull; + + +import java.util.concurrent.Callable; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + * {@link TransmittableThreadLocal} Wrapper of {@link ScheduledExecutorService}, + * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link Callable} + * to the execution time of {@link Runnable} or {@link Callable}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 0.9.0 + */ + +class ScheduledExecutorServiceTtlWrapper extends ExecutorServiceTtlWrapper implements ScheduledExecutorService, TtlEnhanced { + final ScheduledExecutorService scheduledExecutorService; + + public ScheduledExecutorServiceTtlWrapper(@NotNull ScheduledExecutorService scheduledExecutorService) { + super(scheduledExecutorService); + this.scheduledExecutorService = scheduledExecutorService; + } + + @NotNull + @Override + public ScheduledFuture schedule(@NotNull Runnable command, long delay, @NotNull TimeUnit unit) { + return scheduledExecutorService.schedule(TtlRunnable.get(command), delay, unit); + } + + @NotNull + @Override + public ScheduledFuture schedule(@NotNull Callable callable, long delay, @NotNull TimeUnit unit) { + return scheduledExecutorService.schedule(TtlCallable.get(callable), delay, unit); + } + + @NotNull + @Override + public ScheduledFuture scheduleAtFixedRate(@NotNull Runnable command, long initialDelay, long period, @NotNull TimeUnit unit) { + return scheduledExecutorService.scheduleAtFixedRate(TtlRunnable.get(command), initialDelay, period, unit); + } + + @NotNull + @Override + public ScheduledFuture scheduleWithFixedDelay(@NotNull Runnable command, long initialDelay, long delay, @NotNull TimeUnit unit) { + return scheduledExecutorService.scheduleWithFixedDelay(TtlRunnable.get(command), initialDelay, delay, unit); + } + + @Override + @NotNull + public ScheduledExecutorService unwrap() { + return scheduledExecutorService; + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlExecutors.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlExecutors.java new file mode 100644 index 000000000..39a273155 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlExecutors.java @@ -0,0 +1,171 @@ +package com.fr.third.alibaba.ttl.threadpool; + +import com.fr.third.alibaba.ttl.TransmittableThreadLocal; +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import com.fr.third.alibaba.ttl.threadpool.agent.TtlAgent; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.*; + +/** + * Util methods for TTL wrapper of jdk executors. + * + *

    + *
  1. Factory methods to get TTL wrapper from jdk executors.
  2. + *
  3. unwrap/check methods for TTL wrapper of jdk executors.
  4. + *
  5. wrap/unwrap/check methods to disable Inheritable for {@link ThreadFactory}.
  6. + *
+ *

+ * Note: + *

    + *
  • all method is {@code null}-safe, when input {@code executor} parameter is {@code null}, return {@code null}.
  • + *
  • skip wrap/decoration thread pool/{@code executor}(aka. just return input {@code executor}) + * when ttl agent is loaded, Or when input {@code executor} is already wrapped/decorated.
  • + *
+ * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see java.util.concurrent.Executor + * @see java.util.concurrent.ExecutorService + * @see java.util.concurrent.ThreadPoolExecutor + * @see java.util.concurrent.ScheduledThreadPoolExecutor + * @see java.util.concurrent.Executors + * @see java.util.concurrent.CompletionService + * @see java.util.concurrent.ExecutorCompletionService + * @see ThreadFactory + * @see Executors#defaultThreadFactory() + * @since 0.9.0 + */ +public final class TtlExecutors { + /** + * {@link TransmittableThreadLocal} Wrapper of {@link Executor}, + * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} + * to the execution time of {@link Runnable}. + */ + @Nullable + public static Executor getTtlExecutor(@Nullable Executor executor) { + if (TtlAgent.isTtlAgentLoaded() || null == executor || executor instanceof TtlEnhanced) { + return executor; + } + return new ExecutorTtlWrapper(executor); + } + + /** + * {@link TransmittableThreadLocal} Wrapper of {@link ExecutorService}, + * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link java.util.concurrent.Callable} + * to the execution time of {@link Runnable} or {@link java.util.concurrent.Callable}. + */ + @Nullable + public static ExecutorService getTtlExecutorService(@Nullable ExecutorService executorService) { + if (TtlAgent.isTtlAgentLoaded() || executorService == null || executorService instanceof TtlEnhanced) { + return executorService; + } + return new ExecutorServiceTtlWrapper(executorService); + } + + /** + * {@link TransmittableThreadLocal} Wrapper of {@link ScheduledExecutorService}, + * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link java.util.concurrent.Callable} + * to the execution time of {@link Runnable} or {@link java.util.concurrent.Callable}. + */ + @Nullable + public static ScheduledExecutorService getTtlScheduledExecutorService(@Nullable ScheduledExecutorService scheduledExecutorService) { + if (TtlAgent.isTtlAgentLoaded() || scheduledExecutorService == null || scheduledExecutorService instanceof TtlEnhanced) { + return scheduledExecutorService; + } + return new ScheduledExecutorServiceTtlWrapper(scheduledExecutorService); + } + + /** + * check the executor is TTL wrapper executor or not. + *

+ * if the parameter executor is TTL wrapper, return {@code true}, otherwise {@code false}. + *

+ * NOTE: if input executor is {@code null}, return {@code false}. + * + * @param executor input executor + * @param Executor type + * @see #getTtlExecutor(Executor) + * @see #getTtlExecutorService(ExecutorService) + * @see #getTtlScheduledExecutorService(ScheduledExecutorService) + * @see #unwrap(Executor) + * @since 2.8.0 + */ + public static boolean isTtlWrapper(@Nullable T executor) { + return executor instanceof TtlEnhanced; + } + + /** + * Unwrap TTL wrapper executor to the original/underneath one. + *

+ * if the parameter executor is TTL wrapper, return the original/underneath executor; + * otherwise, just return the input parameter executor. + *

+ * NOTE: if input executor is {@code null}, return {@code null}. + * + * @param executor input executor + * @param Executor type + * @see #getTtlExecutor(Executor) + * @see #getTtlExecutorService(ExecutorService) + * @see #getTtlScheduledExecutorService(ScheduledExecutorService) + * @see #isTtlWrapper(Executor) + * @since 2.8.0 + */ + @Nullable + @SuppressWarnings("unchecked") + public static T unwrap(@Nullable T executor) { + if (!isTtlWrapper(executor)) return executor; + + return (T) ((ExecutorTtlWrapper) executor).unwrap(); + } + + /** + * Wrapper of {@link ThreadFactory}, disable inheritable. + * + * @param threadFactory input thread factory + * @see DisableInheritableThreadFactory + * @since 2.10.0 + */ + @Nullable + public static ThreadFactory getDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) { + if (threadFactory == null || isDisableInheritableThreadFactory(threadFactory)) return threadFactory; + + return new DisableInheritableThreadFactoryWrapper(threadFactory); + } + + /** + * Wrapper of {@link Executors#defaultThreadFactory()}, disable inheritable. + * + * @see #getDisableInheritableThreadFactory(ThreadFactory) + * @since 2.10.0 + */ + @Nullable + public static ThreadFactory getDefaultDisableInheritableThreadFactory() { + return getDisableInheritableThreadFactory(Executors.defaultThreadFactory()); + } + + /** + * check the {@link ThreadFactory} is {@link DisableInheritableThreadFactory} or not. + * + * @see DisableInheritableThreadFactory + * @since 2.10.0 + */ + public static boolean isDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) { + return threadFactory instanceof DisableInheritableThreadFactory; + } + + /** + * Unwrap {@link DisableInheritableThreadFactory} to the original/underneath one. + * + * @see DisableInheritableThreadFactory + * @since 2.10.0 + */ + @Nullable + public static ThreadFactory unwrap(@Nullable ThreadFactory threadFactory) { + if (!isDisableInheritableThreadFactory(threadFactory)) return threadFactory; + + return ((DisableInheritableThreadFactory) threadFactory).unwrap(); + } + + private TtlExecutors() { + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlForkJoinPoolHelper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlForkJoinPoolHelper.java new file mode 100644 index 000000000..10b862d1f --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlForkJoinPoolHelper.java @@ -0,0 +1,73 @@ +package com.fr.third.alibaba.ttl.threadpool; + +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory; + +/** + * Util methods to wrap/unwrap/check methods to disable Inheritable for {@link ForkJoinWorkerThreadFactory}. + *

+ * Note: + *

+ * all method is {@code null}-safe, when input parameter(eg: {@link ForkJoinWorkerThreadFactory}) is {@code null}, return {@code null}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see ForkJoinPool + * @see ForkJoinWorkerThreadFactory + * @see ForkJoinPool#defaultForkJoinWorkerThreadFactory + * @since 2.10.1 + */ +public class TtlForkJoinPoolHelper { + /** + * Wrapper of {@link ForkJoinWorkerThreadFactory}, disable inheritable. + * + * @param threadFactory input thread factory + * @see DisableInheritableForkJoinWorkerThreadFactory + * @since 2.10.1 + */ + @Nullable + public static ForkJoinWorkerThreadFactory getDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) { + if (threadFactory == null || isDisableInheritableForkJoinWorkerThreadFactory(threadFactory)) + return threadFactory; + + return new DisableInheritableForkJoinWorkerThreadFactoryWrapper(threadFactory); + } + + /** + * Wrapper of {@link ForkJoinPool#defaultForkJoinWorkerThreadFactory}, disable inheritable. + * + * @see #getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory) + * @since 2.10.1 + */ + @Nullable + public static ForkJoinWorkerThreadFactory getDefaultDisableInheritableForkJoinWorkerThreadFactory() { + return getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinPool.defaultForkJoinWorkerThreadFactory); + } + + /** + * check the {@link ForkJoinWorkerThreadFactory} is {@link DisableInheritableForkJoinWorkerThreadFactory} or not. + * + * @see DisableInheritableForkJoinWorkerThreadFactory + * @since 2.10.1 + */ + public static boolean isDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) { + return threadFactory instanceof DisableInheritableForkJoinWorkerThreadFactory; + } + + /** + * Unwrap {@link DisableInheritableForkJoinWorkerThreadFactory} to the original/underneath one. + * + * @see DisableInheritableForkJoinWorkerThreadFactory + * @since 2.10.1 + */ + @Nullable + public static ForkJoinWorkerThreadFactory unwrap(@Nullable ForkJoinWorkerThreadFactory threadFactory) { + if (!isDisableInheritableForkJoinWorkerThreadFactory(threadFactory)) return threadFactory; + + return ((DisableInheritableForkJoinWorkerThreadFactory) threadFactory).unwrap(); + } + + private TtlForkJoinPoolHelper() { + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlAgent.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlAgent.java new file mode 100644 index 000000000..f1e5bb783 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlAgent.java @@ -0,0 +1,245 @@ +package com.fr.third.alibaba.ttl.threadpool.agent; + +import com.fr.third.alibaba.ttl.TransmittableThreadLocal; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.logging.Logger; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlExecutorTransformlet; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlForkJoinTransformlet; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlTimerTaskTransformlet; + +import com.fr.third.alibaba.ttl.threadpool.DisableInheritableForkJoinWorkerThreadFactory; +import com.fr.third.alibaba.ttl.threadpool.DisableInheritableThreadFactory; +import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; +import com.fr.third.alibaba.ttl.threadpool.TtlForkJoinPoolHelper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.Instrumentation; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; + +/** + * TTL Java Agent. + *

+ * The configuration/arguments for agent see the javadoc of {@link #premain(String, Instrumentation)} + *

+ * NOTE:
+ * Since {@code v2.6.0}, TTL agent jar will auto add self to {@code boot classpath}. + * But you should NOT modify the downloaded TTL jar file name in the maven repo(eg: {@code transmittable-thread-local-2.x.x.jar}).
+ * if you modified the downloaded TTL agent jar file name(eg: {@code ttl-foo-name-changed.jar}), + * you must add TTL agent jar to {@code boot classpath} manually + * by java option {@code -Xbootclasspath/a:path/to/ttl-foo-name-changed.jar}. + *

+ * The implementation of auto adding self agent jar to {@code boot classpath} use + * the {@code Boot-Class-Path} property of manifest file({@code META-INF/MANIFEST.MF}) in the TTL Java Agent Jar: + *

+ *
+ *
Boot-Class-Path
+ *
+ * A list of paths to be searched by the bootstrap class loader. Paths represent directories or libraries (commonly referred to as JAR or zip libraries on many platforms). + * These paths are searched by the bootstrap class loader after the platform specific mechanisms of locating a class have failed. Paths are searched in the order listed. + *
+ *
+ *
+ *

+ * More info about {@code Boot-Class-Path} see + * The mechanism for instrumentation. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see TransmittableThreadLocal + * @see Instrumentation + * @see The mechanism for instrumentation + * @see JAR File Specification - JAR Manifest + * @see Working with Manifest Files - The Java™ TutorialsHide + * @since 0.9.0 + */ +public final class TtlAgent { + /** + * Entrance method of TTL Java Agent. + * + *

TTL Agent configuration

+ * Configure TTL agent via agent arguments, format is {@code k1:v1,k2:v2}. Below is available configuration keys. + * + *

Disable inheritable for thread pool

+ *

+ * Enable "disable inheritable" for thread pool, config by key {@code ttl.agent.disable.inheritable.for.thread.pool}. + * When no configuration for this key, default does not enabled. Since version {@code 2.10.1}. + * + *

    + *
  • rewrite the {@link java.util.concurrent.ThreadFactory} constructor parameter + * of {@link java.util.concurrent.ThreadPoolExecutor} + * to {@link DisableInheritableThreadFactory} + * by util method {@link TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)}. + *
  • + *
  • rewrite the {@link java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory} constructor parameter + * of {@link java.util.concurrent.ForkJoinPool} + * to {@link DisableInheritableForkJoinWorkerThreadFactory} + * by util method {@link TtlForkJoinPoolHelper#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory)}. + *
  • + *
+ * More info about "disable inheritable" see {@link TransmittableThreadLocal}. + *

+ * Configuration example:
+ * {@code -javaagent:/path/to/transmittable-thread-local-2.x.x.jar=ttl.agent.disable.inheritable.for.thread.pool:true} + * + *

The log configuration

+ * The log of TTL Java Agent is config by key {@code ttl.agent.logger}. Since version {@code 2.6.0}. + * + *
    + *
  • {@code ttl.agent.logger : STDERR}
    + * only log to {@code stderr} when error. + * This is default, when no/unrecognized configuration for key {@code ttl.agent.logger}.
  • + *
  • {@code ttl.agent.logger : STDOUT}
    + * Log to {@code stdout}, more info than {@code ttl.agent.logger:STDERR}; This is needed when developing.
  • + *
+ *

+ * configuration example: + *

    + *
  • {@code -javaagent:/path/to/transmittable-thread-local-2.x.x.jar}
  • + *
  • {@code -javaagent:/path/to/transmittable-thread-local-2.x.x.jar=ttl.agent.logger:STDOUT}
  • + *
+ * + *

Enable/disable TimerTask class decoration

+ * Enable/disable TimerTask class decoration is config by key {@code ttl.agent.enable.timer.task}. + * Since version {@code 2.7.0}. + *

+ * When no configuration for this key, default is enabled.
+ * Note: Since version {@code 2.11.2} the default value is {@code true}(enable TimerTask class decoration); + * Before version {@code 2.11.1} default value is {@code false}. + *

+ * Configuration example: + *

    + *
  • {@code -javaagent:/path/to/transmittable-thread-local-2.x.x.jar=ttl.agent.enable.timer.task:false}
  • + *
  • {@code -javaagent:/path/to/transmittable-thread-local-2.x.x.jar=ttl.agent.enable.timer.task:true}
  • + *
+ * + *

Multi key configuration example

+ * {@code -javaagent:/path/to/transmittable-thread-local-2.x.x.jar=ttl.agent.logger:STDOUT,ttl.agent.disable.inheritable.for.thread.pool:true} + * + * @see java.util.concurrent.ThreadPoolExecutor + * @see java.util.concurrent.ScheduledThreadPoolExecutor + * @see java.util.concurrent.ForkJoinPool + * @see java.util.TimerTask + * @see Logger + * @see Logger#TTL_AGENT_LOGGER_KEY + * @see Logger#STDERR + * @see Logger#STDOUT + */ + public static void premain(String agentArgs, @NotNull Instrumentation inst) { + kvs = splitCommaColonStringToKV(agentArgs); + + Logger.setLoggerImplType(getLogImplTypeFromAgentArgs(kvs)); + final Logger logger = Logger.getLogger(TtlAgent.class); + + try { + logger.info("[TtlAgent.premain] begin, agentArgs: " + agentArgs + ", Instrumentation: " + inst); + final boolean disableInheritableForThreadPool = isDisableInheritableForThreadPool(); + + final List transformletList = new ArrayList(); + transformletList.add(new TtlExecutorTransformlet(disableInheritableForThreadPool)); + transformletList.add(new TtlForkJoinTransformlet(disableInheritableForThreadPool)); + if (isEnableTimerTask()) transformletList.add(new TtlTimerTaskTransformlet()); + + final ClassFileTransformer transformer = new TtlTransformer(transformletList); + inst.addTransformer(transformer, true); + logger.info("[TtlAgent.premain] addTransformer " + transformer.getClass() + " success"); + + logger.info("[TtlAgent.premain] end"); + + ttlAgentLoaded = true; + } catch (Exception e) { + String msg = "Fail to load TtlAgent , cause: " + e.toString(); + logger.log(Level.SEVERE, msg, e); + throw new IllegalStateException(msg, e); + } + } + + private static String getLogImplTypeFromAgentArgs(@NotNull final Map kvs) { + return kvs.get(Logger.TTL_AGENT_LOGGER_KEY); + } + + private static volatile Map kvs; + + private static volatile boolean ttlAgentLoaded = false; + + /** + * Whether TTL agent is loaded. + * + * @since 2.9.0 + */ + public static boolean isTtlAgentLoaded() { + return ttlAgentLoaded; + } + + private static final String TTL_AGENT_ENABLE_TIMER_TASK_KEY = "ttl.agent.enable.timer.task"; + + private static final String TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL = "ttl.agent.disable.inheritable.for.thread.pool"; + + /** + * Whether disable inheritable for thread pool is enhanced by ttl agent, check {@link #isTtlAgentLoaded()} first. + * + * @see TtlExecutors#getDefaultDisableInheritableThreadFactory() + * @see TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory) + * @see DisableInheritableThreadFactory + * @see TtlForkJoinPoolHelper#getDefaultDisableInheritableForkJoinWorkerThreadFactory() + * @see TtlForkJoinPoolHelper#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory) + * @see DisableInheritableForkJoinWorkerThreadFactory + * @since 2.10.1 + */ + public static boolean isDisableInheritableForThreadPool() { + return isOptionSetOrFalse(kvs, TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL); + } + + /** + * Whether timer task is enhanced by ttl agent, check {@link #isTtlAgentLoaded()} first. + * + * @since 2.10.1 + */ + public static boolean isEnableTimerTask() { + return isOptionSetOrTrue(kvs, TTL_AGENT_ENABLE_TIMER_TASK_KEY); + } + + private static boolean isOptionSetOrFalse(@Nullable final Map kvs, @NotNull String key) { + return isOptionSetOrFalse(kvs, key, false); + } + + private static boolean isOptionSetOrTrue(@Nullable final Map kvs, @NotNull String key) { + return isOptionSetOrFalse(kvs, key, true); + } + + private static boolean isOptionSetOrFalse(@Nullable final Map kvs, @NotNull String key, boolean defaultValue) { + if (null == kvs) return defaultValue; + + final boolean hasEnableKey = kvs.containsKey(key); + if (!hasEnableKey) return defaultValue; + + return !"false".equalsIgnoreCase(kvs.get(key)); + } + + /** + * Split to {@code json} like String({@code "k1:v1,k2:v2"}) to KV map({@code "k1"->"v1", "k2"->"v2"}). + */ + @NotNull + static Map splitCommaColonStringToKV(@Nullable String commaColonString) { + Map ret = new HashMap(); + if (commaColonString == null || commaColonString.trim().length() == 0) return ret; + + final String[] splitKvArray = commaColonString.trim().split("\\s*,\\s*"); + for (String kvString : splitKvArray) { + final String[] kv = kvString.trim().split("\\s*:\\s*"); + if (kv.length == 0) continue; + + if (kv.length == 1) ret.put(kv[0], ""); + else ret.put(kv[0], kv[1]); + } + + return ret; + } + + private TtlAgent() { + throw new InstantiationError("Must not instantiate this class"); + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlTransformer.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlTransformer.java new file mode 100644 index 000000000..4f8d3ea34 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlTransformer.java @@ -0,0 +1,73 @@ +package com.fr.third.alibaba.ttl.threadpool.agent; + +import com.fr.third.alibaba.ttl.threadpool.agent.internal.logging.Logger; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.ClassInfo; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + + +import java.lang.instrument.ClassFileTransformer; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; + +/** + * TTL {@link ClassFileTransformer} of Java Agent + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see ClassFileTransformer + * @see The mechanism for instrumentation + * @since 0.9.0 + */ +public class TtlTransformer implements ClassFileTransformer { + private static final Logger logger = Logger.getLogger(TtlTransformer.class); + + /** + * "null if no transform is performed", + * see {@code @return} of {@link ClassFileTransformer#transform(ClassLoader, String, Class, ProtectionDomain, byte[])} + */ + + // [ERROR] com.alibaba.ttl.threadpool.agent.TtlTransformer.transform(ClassLoader, String, Class, ProtectionDomain, byte[]) + // may expose internal representation by returning TtlTransformer.NO_TRANSFORM + // the value is null, so there is NO "EI_EXPOSE_REP" problem actually. + private static final byte[] NO_TRANSFORM = null; + + private final List transformletList = new ArrayList(); + + TtlTransformer(List transformletList) { + for (JavassistTransformlet transformlet : transformletList) { + this.transformletList.add(transformlet); + logger.info("[TtlTransformer] add Transformlet " + transformlet.getClass() + " success"); + } + } + + @Override + public final byte[] transform(@Nullable final ClassLoader loader, @Nullable final String classFile, final Class classBeingRedefined, + final ProtectionDomain protectionDomain, @NotNull final byte[] classFileBuffer) { + try { + // Lambda has no class file, no need to transform, just return. + if (classFile == null) return NO_TRANSFORM; + + final String className = toClassName(classFile); + + ClassInfo classInfo = new ClassInfo(className, classFileBuffer, loader); + + for (JavassistTransformlet transformlet : transformletList) { + transformlet.doTransform(classInfo); + if (classInfo.isModified()) return classInfo.getCtClass().toBytecode(); + } + } catch (Throwable t) { + String msg = "Fail to transform class " + classFile + ", cause: " + t.toString(); + logger.log(Level.SEVERE, msg, t); + throw new IllegalStateException(msg, t); + } + + return NO_TRANSFORM; + } + + private static String toClassName(@NotNull final String classFile) { + return classFile.replace('/', '.'); + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/logging/Logger.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/logging/Logger.java new file mode 100644 index 000000000..74a11957b --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/logging/Logger.java @@ -0,0 +1,80 @@ +package com.fr.third.alibaba.ttl.threadpool.agent.internal.logging; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.Level; + +/** + * logger adaptor for ttl java agent, internal use for ttl usage only! + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.6.0 + */ +public abstract class Logger { + public static final String TTL_AGENT_LOGGER_KEY = "ttl.agent.logger"; + public static final String STDOUT = "STDOUT"; + public static final String STDERR = "STDERR"; + + private static volatile int loggerImplType = -1; + + public static void setLoggerImplType(String type) { + if (loggerImplType != -1) { + throw new IllegalStateException("TTL logger implementation type is already set! type = " + loggerImplType); + } + + if (STDERR.equalsIgnoreCase(type)) loggerImplType = 0; + else if (STDOUT.equalsIgnoreCase(type)) loggerImplType = 1; + else loggerImplType = 0; + } + + public static Logger getLogger(Class clazz) { + if (loggerImplType == -1) throw new IllegalStateException("TTL logger implementation type is NOT set!"); + + switch (loggerImplType) { + case 1: + return new StdOutLogger(clazz); + default: + return new StdErrorLogger(clazz); + } + } + + final Class logClass; + + private Logger(Class logClass) { + this.logClass = logClass; + } + + public void info(String msg) { + log(Level.INFO, msg, null); + } + + public abstract void log(Level level, String msg, Throwable thrown); + + private static class StdErrorLogger extends Logger { + StdErrorLogger(Class clazz) { + super(clazz); + } + + @Override + public void log(Level level, String msg, Throwable thrown) { + if (level == Level.SEVERE) { + final String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); + System.err.printf("%s %s [%s] %s: %s%n", time, level, Thread.currentThread().getName(), logClass.getSimpleName(), msg); + if (thrown != null) thrown.printStackTrace(); + } + } + } + + private static class StdOutLogger extends Logger { + StdOutLogger(Class clazz) { + super(clazz); + } + + @Override + public void log(Level level, String msg, Throwable thrown) { + final String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); + System.out.printf("%s %s [%s] %s: %s%n", time, level, Thread.currentThread().getName(), logClass.getSimpleName(), msg); + if (thrown != null) thrown.printStackTrace(System.out); + } + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/ClassInfo.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/ClassInfo.java new file mode 100644 index 000000000..8d656e5c6 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/ClassInfo.java @@ -0,0 +1,66 @@ +package com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet; + +import com.fr.third.javassist.CtClass; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import com.fr.third.javassist.ClassPool; +import com.fr.third.javassist.CtClass; +import com.fr.third.javassist.LoaderClassPath; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +/** + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.11.0 + */ +public class ClassInfo { + private final String className; + private final byte[] classFileBuffer; + private final ClassLoader loader; + + // SuppressFBWarnings for classFileBuffer parameter: + // [ERROR] new com.alibaba.ttl.threadpool.agent.internal.transformlet.ClassInfo(String, byte[], ClassLoader) + // may expose internal representation by storing an externally mutable object + // into ClassInfo.classFileBuffer + public ClassInfo(@NotNull String className, byte[] classFileBuffer, @Nullable ClassLoader loader) { + this.className = className; + this.classFileBuffer = classFileBuffer; + this.loader = loader; + } + + @NotNull + public String getClassName() { + return className; + } + + private CtClass ctClass; + + @NotNull + public CtClass getCtClass() throws IOException { + if (ctClass != null) return ctClass; + + final ClassPool classPool = new ClassPool(true); + if (loader == null) { + classPool.appendClassPath(new LoaderClassPath(ClassLoader.getSystemClassLoader())); + } else { + classPool.appendClassPath(new LoaderClassPath(loader)); + } + + final CtClass clazz = classPool.makeClass(new ByteArrayInputStream(classFileBuffer), false); + clazz.defrost(); + + this.ctClass = clazz; + return clazz; + } + + private boolean modified = false; + + public boolean isModified() { + return modified; + } + + public void setModified() { + this.modified = true; + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/JavassistTransformlet.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/JavassistTransformlet.java new file mode 100644 index 000000000..b88102889 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/JavassistTransformlet.java @@ -0,0 +1,17 @@ +package com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet; + +import org.jetbrains.annotations.NotNull; +import com.fr.third.javassist.CannotCompileException; +import com.fr.third.javassist.NotFoundException; + +import java.io.IOException; + +/** + * TTL {@code Transformlet} by {@code Javassist}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.5.1 + */ +public interface JavassistTransformlet { + void doTransform(@NotNull ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException; +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlExecutorTransformlet.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlExecutorTransformlet.java new file mode 100644 index 000000000..603e4c5dd --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlExecutorTransformlet.java @@ -0,0 +1,164 @@ +package com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl; + +import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.logging.Logger; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.ClassInfo; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet; +import com.fr.third.alibaba.ttl.TtlCallable; +import com.fr.third.alibaba.ttl.TtlRunnable; +import org.jetbrains.annotations.NotNull; +import com.fr.third.javassist.*; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; + +/** + * TTL {@link JavassistTransformlet} for {@link java.util.concurrent.Executor}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @author wuwen5 (wuwen.55 at aliyun dot com) + * @see java.util.concurrent.Executor + * @see java.util.concurrent.ExecutorService + * @see java.util.concurrent.ThreadPoolExecutor + * @see java.util.concurrent.ScheduledThreadPoolExecutor + * @see java.util.concurrent.Executors + * @since 2.5.1 + */ +public class TtlExecutorTransformlet implements JavassistTransformlet { + private static final Logger logger = Logger.getLogger(TtlExecutorTransformlet.class); + + private static Set EXECUTOR_CLASS_NAMES = new HashSet(); + private static final Map PARAM_TYPE_NAME_TO_DECORATE_METHOD_CLASS = new HashMap(); + + private static final String THREAD_POOL_EXECUTOR_CLASS_NAME = "java.util.concurrent.ThreadPoolExecutor"; + private static final String RUNNABLE_CLASS_NAME = "java.lang.Runnable"; + + static { + EXECUTOR_CLASS_NAMES.add(THREAD_POOL_EXECUTOR_CLASS_NAME); + EXECUTOR_CLASS_NAMES.add("java.util.concurrent.ScheduledThreadPoolExecutor"); + + PARAM_TYPE_NAME_TO_DECORATE_METHOD_CLASS.put(RUNNABLE_CLASS_NAME, "com.alibaba.ttl.TtlRunnable"); + PARAM_TYPE_NAME_TO_DECORATE_METHOD_CLASS.put("java.util.concurrent.Callable", "com.alibaba.ttl.TtlCallable"); + } + + private static final String THREAD_FACTORY_CLASS_NAME = "java.util.concurrent.ThreadFactory"; + + private final boolean disableInheritableForThreadPool; + + public TtlExecutorTransformlet(boolean disableInheritableForThreadPool) { + this.disableInheritableForThreadPool = disableInheritableForThreadPool; + } + + @Override + public void doTransform(@NotNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException { + if (EXECUTOR_CLASS_NAMES.contains(classInfo.getClassName())) { + final CtClass clazz = classInfo.getCtClass(); + + for (CtMethod method : clazz.getDeclaredMethods()) { + updateSubmitMethodsOfExecutorClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(method); + } + + if (disableInheritableForThreadPool) updateConstructorDisableInheritable(clazz); + + classInfo.setModified(); + } else { + final CtClass clazz = classInfo.getCtClass(); + + if (clazz.isPrimitive() || clazz.isArray() || clazz.isInterface() || clazz.isAnnotation()) { + return; + } + if (!clazz.subclassOf(clazz.getClassPool().get(THREAD_POOL_EXECUTOR_CLASS_NAME))) return; + + logger.info("Transforming class " + classInfo.getClassName()); + + final boolean modified = updateBeforeAndAfterExecuteMethodOfExecutorSubclass(clazz); + if (modified) classInfo.setModified(); + } + } + + /** + * @see TtlRunnable#get(Runnable, boolean, boolean) + * @see TtlCallable#get(Callable, boolean, boolean) + * @see Utils#setAutoWrapperAttachment(Object) + */ + // [ERROR] Format string should use %n rather than \n + private void updateSubmitMethodsOfExecutorClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(@NotNull final CtMethod method) throws NotFoundException, CannotCompileException { + final int modifiers = method.getModifiers(); + if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers)) return; + + CtClass[] parameterTypes = method.getParameterTypes(); + StringBuilder insertCode = new StringBuilder(); + for (int i = 0; i < parameterTypes.length; i++) { + final String paramTypeName = parameterTypes[i].getName(); + if (PARAM_TYPE_NAME_TO_DECORATE_METHOD_CLASS.containsKey(paramTypeName)) { + String code = String.format( + // decorate to TTL wrapper, + // and then set AutoWrapper attachment/Tag + "$%d = %s.get($%d, false, true);" + + "\ncom.alibaba.ttl.threadpool.agent.internal.transformlet.impl.Utils.setAutoWrapperAttachment($% 0) method.insertBefore(insertCode.toString()); + } + + /** + * @see TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory) + */ + private void updateConstructorDisableInheritable(@NotNull final CtClass clazz) throws NotFoundException, CannotCompileException { + for (CtConstructor constructor : clazz.getDeclaredConstructors()) { + final CtClass[] parameterTypes = constructor.getParameterTypes(); + final StringBuilder insertCode = new StringBuilder(); + for (int i = 0; i < parameterTypes.length; i++) { + final String paramTypeName = parameterTypes[i].getName(); + if (THREAD_FACTORY_CLASS_NAME.equals(paramTypeName)) { + String code = String.format("$%d = com.alibaba.ttl.threadpool.TtlExecutors.getDisableInheritableThreadFactory($% 0) constructor.insertBefore(insertCode.toString()); + } + } + + /** + * @see Utils#unwrapIfIsAutoWrapper(Runnable) + */ + private boolean updateBeforeAndAfterExecuteMethodOfExecutorSubclass(@NotNull final CtClass clazz) throws NotFoundException, CannotCompileException { + final CtClass runnableClass = clazz.getClassPool().get(RUNNABLE_CLASS_NAME); + final CtClass threadClass = clazz.getClassPool().get("java.lang.Thread"); + final CtClass throwableClass = clazz.getClassPool().get("java.lang.Throwable"); + boolean modified = false; + + try { + final CtMethod beforeExecute = clazz.getDeclaredMethod("beforeExecute", new CtClass[]{threadClass, runnableClass}); + // unwrap runnable if IsAutoWrapper + String code = "$2 = com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.Utils.unwrapIfIsAutoWrapper($2);"; + logger.info("insert code before method " + Utils.signatureOfMethod(beforeExecute) + " of class " + beforeExecute.getDeclaringClass().getName() + ": " + code); + beforeExecute.insertBefore(code); + modified = true; + } catch (NotFoundException e) { + // clazz does not override beforeExecute method, do nothing. + } + + try { + final CtMethod afterExecute = clazz.getDeclaredMethod("afterExecute", new CtClass[]{runnableClass, throwableClass}); + // unwrap runnable if IsAutoWrapper + String code = "$1 = com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.Utils.unwrapIfIsAutoWrapper($1);"; + logger.info("insert code before method " + Utils.signatureOfMethod(afterExecute) + " of class " + afterExecute.getDeclaringClass().getName() + ": " + code); + afterExecute.insertBefore(code); + modified = true; + } catch (NotFoundException e) { + // clazz does not override afterExecute method, do nothing. + } + + return modified; + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlForkJoinTransformlet.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlForkJoinTransformlet.java new file mode 100644 index 000000000..69e4b70a0 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlForkJoinTransformlet.java @@ -0,0 +1,85 @@ +package com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl; + +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.logging.Logger; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.ClassInfo; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet; +import org.jetbrains.annotations.NotNull; +import com.fr.third.javassist.*; + +import java.io.IOException; + +/** + * TTL {@link JavassistTransformlet} for {@link java.util.concurrent.ForkJoinTask}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @author wuwen5 (wuwen.55 at aliyun dot com) + * @see java.util.concurrent.ForkJoinPool + * @see java.util.concurrent.ForkJoinTask + * @since 2.5.1 + */ +public class TtlForkJoinTransformlet implements JavassistTransformlet { + private static final Logger logger = Logger.getLogger(TtlForkJoinTransformlet.class); + + private static final String FORK_JOIN_TASK_CLASS_NAME = "java.util.concurrent.ForkJoinTask"; + private static final String FORK_JOIN_POOL_CLASS_NAME = "java.util.concurrent.ForkJoinPool"; + private static final String FORK_JOIN_WORKER_THREAD_FACTORY_CLASS_NAME = "java.util.concurrent.ForkJoinPool$ForkJoinWorkerThreadFactory"; + + private final boolean disableInheritableForThreadPool; + + public TtlForkJoinTransformlet(boolean disableInheritableForThreadPool) { + this.disableInheritableForThreadPool = disableInheritableForThreadPool; + } + + @Override + public void doTransform(@NotNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException { + if (FORK_JOIN_TASK_CLASS_NAME.equals(classInfo.getClassName())) { + updateForkJoinTaskClass(classInfo.getCtClass()); + classInfo.setModified(); + } else if (disableInheritableForThreadPool && FORK_JOIN_POOL_CLASS_NAME.equals(classInfo.getClassName())) { + updateConstructorDisableInheritable(classInfo.getCtClass()); + classInfo.setModified(); + } + } + + /** + * @see Utils#doCaptureWhenNotTtlEnhanced(java.lang.Object) + */ + private void updateForkJoinTaskClass(@NotNull final CtClass clazz) throws CannotCompileException, NotFoundException { + final String className = clazz.getName(); + + // add new field + final String capturedFieldName = "captured$field$added$by$ttl"; + final CtField capturedField = CtField.make("private final Object " + capturedFieldName + ";", clazz); + clazz.addField(capturedField, "com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.Utils.doCaptureWhenNotTtlEnhanced(this);"); + logger.info("add new field " + capturedFieldName + " to class " + className); + + final CtMethod doExecMethod = clazz.getDeclaredMethod("doExec", new CtClass[0]); + final String doExec_renamed_method_name = Utils.renamedMethodNameByTtl(doExecMethod); + + final String beforeCode = "if (this instanceof " + TtlEnhanced.class.getName() + ") {\n" + // if the class is already TTL enhanced(eg: com.alibaba.ttl.TtlRecursiveTask) + " return " + doExec_renamed_method_name + "($$);\n" + // return directly/do nothing + "}\n" + + "Object backup = com.alibaba.ttl.TransmittableThreadLocal.Transmitter.replay(" + capturedFieldName + ");"; + + final String finallyCode = "com.alibaba.ttl.TransmittableThreadLocal.Transmitter.restore(backup);"; + + Utils.doTryFinallyForMethod(doExecMethod, doExec_renamed_method_name, beforeCode, finallyCode); + } + + private void updateConstructorDisableInheritable(@NotNull final CtClass clazz) throws NotFoundException, CannotCompileException { + for (CtConstructor constructor : clazz.getDeclaredConstructors()) { + final CtClass[] parameterTypes = constructor.getParameterTypes(); + final StringBuilder insertCode = new StringBuilder(); + for (int i = 0; i < parameterTypes.length; i++) { + final String paramTypeName = parameterTypes[i].getName(); + if (FORK_JOIN_WORKER_THREAD_FACTORY_CLASS_NAME.equals(paramTypeName)) { + String code = String.format("$%d = com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper.getDisableInheritableForkJoinWorkerThreadFactory($% 0) constructor.insertBefore(insertCode.toString()); + } + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlTimerTaskTransformlet.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlTimerTaskTransformlet.java new file mode 100644 index 000000000..0505d2434 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlTimerTaskTransformlet.java @@ -0,0 +1,71 @@ +package com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl; + +import com.fr.third.alibaba.ttl.threadpool.agent.internal.logging.Logger; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.ClassInfo; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet; +import org.jetbrains.annotations.NotNull; +import com.fr.third.javassist.*; + +import java.io.IOException; + +import static com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl.Utils.doTryFinallyForMethod; + +/** + * TTL {@link JavassistTransformlet} for {@link java.util.TimerTask}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @author wuwen5 (wuwen.55 at aliyun dot com) + * @see java.util.TimerTask + * @see java.util.Timer + * @since 2.7.0 + */ +public class TtlTimerTaskTransformlet implements JavassistTransformlet { + private static final Logger logger = Logger.getLogger(TtlTimerTaskTransformlet.class); + + private static final String TIMER_TASK_CLASS_NAME = "java.util.TimerTask"; + private static final String RUN_METHOD_NAME = "run"; + + @Override + public void doTransform(@NotNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException { + if (TIMER_TASK_CLASS_NAME.equals(classInfo.getClassName())) return; // No need transform TimerTask class + + final CtClass clazz = classInfo.getCtClass(); + + if (clazz.isPrimitive() || clazz.isArray() || clazz.isInterface() || clazz.isAnnotation()) { + return; + } + // class contains method `void run()` ? + try { + final CtMethod runMethod = clazz.getDeclaredMethod(RUN_METHOD_NAME, new CtClass[0]); + if (!CtClass.voidType.equals(runMethod.getReturnType())) return; + } catch (NotFoundException e) { + return; + } + if (!clazz.subclassOf(clazz.getClassPool().get(TIMER_TASK_CLASS_NAME))) return; + + logger.info("Transforming class " + classInfo.getClassName()); + + updateTimerTaskClass(clazz); + classInfo.setModified(); + } + + /** + * @see Utils#doCaptureWhenNotTtlEnhanced(java.lang.Object) + */ + private void updateTimerTaskClass(@NotNull final CtClass clazz) throws CannotCompileException, NotFoundException { + final String className = clazz.getName(); + + // add new field + final String capturedFieldName = "captured$field$added$by$ttl"; + final CtField capturedField = CtField.make("private final Object " + capturedFieldName + ";", clazz); + clazz.addField(capturedField, "com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.Utils.doCaptureWhenNotTtlEnhanced(this);"); + logger.info("add new field " + capturedFieldName + " to class " + className); + + final CtMethod runMethod = clazz.getDeclaredMethod(RUN_METHOD_NAME, new CtClass[0]); + + final String beforeCode = "Object backup = com.alibaba.ttl.TransmittableThreadLocal.Transmitter.replay(" + capturedFieldName + ");"; + final String finallyCode = "com.alibaba.ttl.TransmittableThreadLocal.Transmitter.restore(backup);"; + + Utils.doTryFinallyForMethod(runMethod, beforeCode, finallyCode); + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/Utils.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/Utils.java new file mode 100644 index 000000000..39340a96c --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/Utils.java @@ -0,0 +1,119 @@ +package com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl; + +import com.fr.third.alibaba.ttl.TtlRunnable; +import com.fr.third.alibaba.ttl.spi.TtlAttachments; +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; +import com.fr.third.alibaba.ttl.threadpool.agent.internal.logging.Logger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import com.fr.third.javassist.*; + +import java.lang.reflect.Modifier; + +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.capture; + +/** + * @author Jerry Lee (oldratlee at gmail dot com) + * @since 2.6.0 + */ +public class Utils { + private static final Logger logger = Logger.getLogger(Utils.class); + + /** + * String like {@code public ScheduledFuture scheduleAtFixedRate(Runnable, long, long, TimeUnit)} + * for {@link java.util.concurrent.ScheduledThreadPoolExecutor#scheduleAtFixedRate}. + * + * @param method method object + * @return method signature string + */ + @NotNull + static String signatureOfMethod(@NotNull final CtBehavior method) throws NotFoundException { + final StringBuilder stringBuilder = new StringBuilder(); + + stringBuilder.append(Modifier.toString(method.getModifiers())); + if (method instanceof CtMethod) { + final String returnType = ((CtMethod) method).getReturnType().getSimpleName(); + stringBuilder.append(" ").append(returnType); + } + stringBuilder.append(" ").append(method.getName()).append("("); + + final CtClass[] parameterTypes = method.getParameterTypes(); + for (int i = 0; i < parameterTypes.length; i++) { + CtClass parameterType = parameterTypes[i]; + if (i != 0) stringBuilder.append(", "); + stringBuilder.append(parameterType.getSimpleName()); + } + + stringBuilder.append(")"); + return stringBuilder.toString(); + } + + @NotNull + static String renamedMethodNameByTtl(@NotNull CtMethod method) { + return "original$" + method.getName() + "$method$renamed$by$ttl"; + } + + static void doTryFinallyForMethod(@NotNull CtMethod method, @NotNull String beforeCode, @NotNull String finallyCode) throws CannotCompileException, NotFoundException { + doTryFinallyForMethod(method, renamedMethodNameByTtl(method), beforeCode, finallyCode); + } + + static void doTryFinallyForMethod(@NotNull CtMethod method, @NotNull String renamedMethodName, @NotNull String beforeCode, @NotNull String finallyCode) throws CannotCompileException, NotFoundException { + final CtClass clazz = method.getDeclaringClass(); + final CtMethod newMethod = CtNewMethod.copy(method, clazz, null); + + // rename original method, and set to private method(avoid reflect out renamed method unexpectedly) + method.setName(renamedMethodName); + method.setModifiers(method.getModifiers() + & ~Modifier.PUBLIC /* remove public */ + & ~Modifier.PROTECTED /* remove protected */ + | Modifier.PRIVATE /* add private */); + + final String returnOp; + if (method.getReturnType() == CtClass.voidType) { + returnOp = ""; + } else { + returnOp = "return "; + } + // set new method implementation + final String code = "{\n" + + beforeCode + "\n" + + "try {\n" + + " " + returnOp + renamedMethodName + "($$);\n" + + "} finally {\n" + + " " + finallyCode + "\n" + + "} }"; + newMethod.setBody(code); + clazz.addMethod(newMethod); + logger.info("insert code around method " + signatureOfMethod(newMethod) + " of class " + clazz.getName() + ": " + code); + } + + @Nullable + public static Object doCaptureWhenNotTtlEnhanced(@Nullable Object obj) { + if (obj instanceof TtlEnhanced) return null; + else return capture(); + } + + public static void setAutoWrapperAttachment(@Nullable Object ttlAttachment) { + if (notTtlAttachments(ttlAttachment)) return; + ((TtlAttachments) ttlAttachment).setTtlAttachment(TtlAttachments.KEY_IS_AUTO_WRAPPER, true); + } + + @Nullable + public static Runnable unwrapIfIsAutoWrapper(@Nullable Runnable runnable) { + if (isAutoWrapper(runnable)) return TtlRunnable.unwrap(runnable); + else return runnable; + } + + private static boolean notTtlAttachments(@Nullable Object ttlAttachment) { + return !(ttlAttachment instanceof TtlAttachments); + } + + private static boolean isAutoWrapper(@Nullable Runnable ttlAttachments) { + if (notTtlAttachments(ttlAttachments)) return false; + + final Boolean value = ((TtlAttachments) ttlAttachments).getTtlAttachment(TtlAttachments.KEY_IS_AUTO_WRAPPER); + if (value == null) return false; + + return value; + } +} diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/package-info.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/package-info.java new file mode 100644 index 000000000..0705dc7db --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/package-info.java @@ -0,0 +1,7 @@ +/** + * TTL {@code Transformlet} implementations by {@code Javassist}. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet + */ +package com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet; diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/package-info.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/package-info.java new file mode 100644 index 000000000..b0a944813 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/package-info.java @@ -0,0 +1,8 @@ +/** + * TTL Agent. + * + * @author Jerry Lee (oldratlee at gmail dot com) + * @see com.fr.third.alibaba.ttl.threadpool.agent.TtlAgent + * @see The mechanism for instrumentation + */ +package com.fr.third.alibaba.ttl.threadpool.agent; diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/package-info.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/package-info.java new file mode 100644 index 000000000..ee37492d5 --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/package-info.java @@ -0,0 +1,6 @@ +/** + * Thread pool wrap/decoration utils. + * + * @author Jerry Lee (oldratlee at gmail dot com) + */ +package com.fr.third.alibaba.ttl.threadpool; From 8cad028623d000a2f393fe03995c903d2947f74d Mon Sep 17 00:00:00 2001 From: Elijah Date: Fri, 4 Sep 2020 16:59:41 +0800 Subject: [PATCH 2/8] =?UTF-8?q?DEC-14578=20=E6=89=93=E5=8C=85=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.third_step8-jdk11.gradle | 4 +++- build.third_step8.gradle | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build.third_step8-jdk11.gradle b/build.third_step8-jdk11.gradle index f320db709..3825698d4 100644 --- a/build.third_step8-jdk11.gradle +++ b/build.third_step8-jdk11.gradle @@ -26,6 +26,7 @@ sourceSets{ java{ srcDirs=[ "${srcDir}/fine-ehcache/src/main/java" + "${srcDir}/fine-transmittable-thread-local/src/main/java" ] } } @@ -33,7 +34,8 @@ sourceSets{ def resourceDirs = [ "${srcDir}/fine-ehcache/src/main/java", - "${srcDir}/fine-ehcache/src/main/recources" + "${srcDir}/fine-ehcache/src/main/recources", + "${srcDir}/fine-transmittable-thread-local/src/main/java" ] sourceSets.main.java.outputDir = file('build/classes/8') diff --git a/build.third_step8.gradle b/build.third_step8.gradle index f2112233b..8410bac6b 100644 --- a/build.third_step8.gradle +++ b/build.third_step8.gradle @@ -25,7 +25,8 @@ sourceSets{ main{ java{ srcDirs=[ - "${srcDir}/fine-ehcache/src/main/java" + "${srcDir}/fine-ehcache/src/main/java", + "${srcDir}/fine-transmittable-thread-local/src/main/java" ] } } @@ -70,6 +71,7 @@ task copyFiles(type:Copy,dependsOn:'compileJava'){ println "------------------------------------------------copyfiles" with dataContent.call("${srcDir}/fine-ehcache/src/main/java") with dataContent.call("${srcDir}/fine-ehcache/src/main/recources") + with dataContent.call("${srcDir}/fine-transmittable-thread-local/src/main/java") into "${classesDir}" } } From 327309208a946e2881f9ef8c5123044f963a6617 Mon Sep 17 00:00:00 2001 From: Echen Date: Mon, 14 Sep 2020 09:42:57 +0800 Subject: [PATCH 3/8] =?UTF-8?q?QFX-1737=20fix:=E6=95=B0=E6=8D=AE=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E4=B9=8B=E5=90=8E=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../openxml4j/opc/internal/PackagePropertiesPart.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fine-poi/src/main/java/com/fr/third/v2/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java b/fine-poi/src/main/java/com/fr/third/v2/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java index 661c1b080..4f9dbad37 100644 --- a/fine-poi/src/main/java/com/fr/third/v2/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java +++ b/fine-poi/src/main/java/com/fr/third/v2/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java @@ -571,10 +571,11 @@ public final class PackagePropertiesPart extends PackagePart implements df.setTimeZone(LocaleUtil.TIMEZONE_UTC); d = df.parse(dateTzStr, new ParsePosition(0)); } - if (d == null) { - throw new InvalidFormatException("Date " + dateTzStr + " not well formated, " - + "expected format " + DEFAULT_DATEFORMAT + " or " + ALTERNATIVE_DATEFORMAT); - } + // BI-72094 先解决问题 + // if (d == null) { + // throw new InvalidFormatException("Date " + dateTzStr + " not well formated, " + // + "expected format " + DEFAULT_DATEFORMAT + " or " + ALTERNATIVE_DATEFORMAT); + // } return new Nullable(d); } From 0dc7ada0462a8f8aa94e39c5fa7f8e1b78e83c91 Mon Sep 17 00:00:00 2001 From: Elijah Date: Wed, 16 Sep 2020 13:37:29 +0800 Subject: [PATCH 4/8] =?UTF-8?q?DEC-14578=20feat:=20=E5=8E=BB=E6=8E=89?= =?UTF-8?q?=E6=97=A0=E7=94=A8=E7=9A=84jetbrain.NotNull=E4=BE=9D=E8=B5=96,?= =?UTF-8?q?=20=E6=8B=86=E5=88=86Utils=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- base-third-project/base-third-step8/pom.xml | 4 +- fine-transmittable-thread-local/pom.xml | 5 -- .../alibaba/ttl/TransmittableThreadLocal.java | 44 ++++++++--------- .../com/fr/third/alibaba/ttl/TtlCallable.java | 44 ++++++++--------- .../com/fr/third/alibaba/ttl/TtlEnhanced.java | 4 +- .../com/fr/third/alibaba/ttl/TtlRunnable.java | 44 ++++++++--------- .../fr/third/alibaba/ttl/TtlTimerTask.java | 30 ++++++------ .../com/fr/third/alibaba/ttl/TtlUnwrap.java | 8 +-- .../com/fr/third/alibaba/ttl/TtlWrappers.java | 44 ++++++++--------- .../third/alibaba/ttl/spi/TtlAttachments.java | 5 +- .../ttl/spi/TtlAttachmentsDelegate.java | 5 +- .../fr/third/alibaba/ttl/spi/TtlWrapper.java | 3 +- ...nheritableForkJoinWorkerThreadFactory.java | 3 +- ...bleForkJoinWorkerThreadFactoryWrapper.java | 4 +- .../DisableInheritableThreadFactory.java | 3 +- ...isableInheritableThreadFactoryWrapper.java | 7 ++- .../threadpool/ExecutorServiceTtlWrapper.java | 35 +++++++------ .../ttl/threadpool/ExecutorTtlWrapper.java | 7 ++- .../ScheduledExecutorServiceTtlWrapper.java | 21 ++++---- .../alibaba/ttl/threadpool/TtlExecutors.java | 31 ++++++------ .../ttl/threadpool/TtlForkJoinPoolHelper.java | 13 +++-- .../alibaba/ttl/threadpool/TtlUtils.java | 39 +++++++++++++++ .../ttl/threadpool/agent/TtlAgent.java | 20 +++----- .../ttl/threadpool/agent/TtlTransformer.java | 10 ++-- .../internal/transformlet/ClassInfo.java | 27 +++++++--- .../transformlet/JavassistTransformlet.java | 3 +- .../impl/TtlExecutorTransformlet.java | 28 +++++------ .../impl/TtlForkJoinTransformlet.java | 20 ++++---- .../impl/TtlTimerTaskTransformlet.java | 15 +++--- .../internal/transformlet/impl/Utils.java | 49 +++---------------- .../ttl/threadpool/agent/package-info.java | 2 + 31 files changed, 276 insertions(+), 301 deletions(-) create mode 100644 fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlUtils.java diff --git a/base-third-project/base-third-step8/pom.xml b/base-third-project/base-third-step8/pom.xml index f863d94ce..af1c0c7cc 100644 --- a/base-third-project/base-third-step8/pom.xml +++ b/base-third-project/base-third-step8/pom.xml @@ -7,14 +7,16 @@ com.fr.third base-third - ${revision} + 10.0-FEATURE-SNAPSHOT step8 ${revision} + pom ../../fine-ehcache + ../../fine-transmittable-thread-local diff --git a/fine-transmittable-thread-local/pom.xml b/fine-transmittable-thread-local/pom.xml index 4d324253f..b8226410a 100644 --- a/fine-transmittable-thread-local/pom.xml +++ b/fine-transmittable-thread-local/pom.xml @@ -30,11 +30,6 @@ ${revision} - - com.fr.third - fine-jetbrains - ${revision} - diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TransmittableThreadLocal.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TransmittableThreadLocal.java index f4d423503..5ce678ed0 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TransmittableThreadLocal.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TransmittableThreadLocal.java @@ -3,8 +3,6 @@ package com.fr.third.alibaba.ttl; import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; import com.fr.third.alibaba.ttl.threadpool.TtlForkJoinPoolHelper; import com.fr.third.alibaba.ttl.threadpool.agent.TtlAgent; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Iterator; @@ -244,7 +242,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple /** * Debug only method! */ - static void dump(@Nullable String title) { + static void dump( String title) { if (title != null && title.length() > 0) { System.out.printf("Start TransmittableThreadLocal[%s] Dump...%n", title); } else { @@ -370,7 +368,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @return the captured {@link TransmittableThreadLocal} values * @since 2.3.0 */ - @NotNull + public static Object capture() { return new Snapshot(captureTtlValues(), captureThreadLocalValues()); } @@ -403,14 +401,14 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @see #capture() * @since 2.3.0 */ - @NotNull - public static Object replay(@NotNull Object captured) { + + public static Object replay(Object captured) { final Snapshot capturedSnapshot = (Snapshot) captured; return new Snapshot(replayTtlValues(capturedSnapshot.ttl2Value), replayThreadLocalValues(capturedSnapshot.threadLocal2Value)); } - @NotNull - private static HashMap, Object> replayTtlValues(@NotNull HashMap, Object> captured) { + + private static HashMap, Object> replayTtlValues(HashMap, Object> captured) { HashMap, Object> backup = new HashMap, Object>(); for (final Iterator> iterator = holder.get().keySet().iterator(); iterator.hasNext(); ) { @@ -436,7 +434,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple return backup; } - private static HashMap, Object> replayThreadLocalValues(@NotNull HashMap, Object> captured) { + private static HashMap, Object> replayThreadLocalValues(HashMap, Object> captured) { final HashMap, Object> backup = new HashMap, Object>(); for (Map.Entry, Object> entry : captured.entrySet()) { @@ -458,7 +456,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @return the backup {@link TransmittableThreadLocal} values before clear * @since 2.9.0 */ - @NotNull + public static Object clear() { final HashMap, Object> ttl2Value = new HashMap, Object>(); @@ -480,13 +478,13 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @see #clear() * @since 2.3.0 */ - public static void restore(@NotNull Object backup) { + public static void restore(Object backup) { final Snapshot backupSnapshot = (Snapshot) backup; restoreTtlValues(backupSnapshot.ttl2Value); restoreThreadLocalValues(backupSnapshot.threadLocal2Value); } - private static void restoreTtlValues(@NotNull HashMap, Object> backup) { + private static void restoreTtlValues(HashMap, Object> backup) { // call afterExecute callback doExecuteCallback(false); @@ -505,14 +503,14 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple setTtlValuesTo(backup); } - private static void setTtlValuesTo(@NotNull HashMap, Object> ttlValues) { + private static void setTtlValuesTo(HashMap, Object> ttlValues) { for (Map.Entry, Object> entry : ttlValues.entrySet()) { TransmittableThreadLocal threadLocal = entry.getKey(); threadLocal.set(entry.getValue()); } } - private static void restoreThreadLocalValues(@NotNull HashMap, Object> backup) { + private static void restoreThreadLocalValues(HashMap, Object> backup) { for (Map.Entry, Object> entry : backup.entrySet()) { final ThreadLocal threadLocal = entry.getKey(); threadLocal.set(entry.getValue()); @@ -541,7 +539,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @see #restore(Object) * @since 2.3.1 */ - public static R runSupplierWithCaptured(@NotNull Object captured, @NotNull Supplier bizLogic) { + public static R runSupplierWithCaptured(Object captured, Supplier bizLogic) { Object backup = replay(captured); try { return bizLogic.get(); @@ -560,7 +558,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @see #restore(Object) * @since 2.9.0 */ - public static R runSupplierWithClear(@NotNull Supplier bizLogic) { + public static R runSupplierWithClear(Supplier bizLogic) { Object backup = clear(); try { return bizLogic.get(); @@ -582,7 +580,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @see #restore(Object) * @since 2.3.1 */ - public static R runCallableWithCaptured(@NotNull Object captured, @NotNull Callable bizLogic) throws Exception { + public static R runCallableWithCaptured(Object captured, Callable bizLogic) throws Exception { Object backup = replay(captured); try { return bizLogic.call(); @@ -602,7 +600,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @see #restore(Object) * @since 2.9.0 */ - public static R runCallableWithClear(@NotNull Callable bizLogic) throws Exception { + public static R runCallableWithClear(Callable bizLogic) throws Exception { Object backup = clear(); try { return bizLogic.call(); @@ -629,7 +627,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @see #registerThreadLocal(ThreadLocal, TtlCopier, boolean) * @since 2.11.0 */ - public static boolean registerThreadLocal(@NotNull ThreadLocal threadLocal, @NotNull TtlCopier copier) { + public static boolean registerThreadLocal(ThreadLocal threadLocal, TtlCopier copier) { return registerThreadLocal(threadLocal, copier, false); } @@ -652,7 +650,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @since 2.11.0 */ @SuppressWarnings("unchecked") - public static boolean registerThreadLocalWithShadowCopier(@NotNull ThreadLocal threadLocal) { + public static boolean registerThreadLocalWithShadowCopier(ThreadLocal threadLocal) { return registerThreadLocal(threadLocal, (TtlCopier) shadowCopier, false); } @@ -673,7 +671,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @since 2.11.0 */ @SuppressWarnings("unchecked") - public static boolean registerThreadLocal(@NotNull ThreadLocal threadLocal, @NotNull TtlCopier copier, boolean force) { + public static boolean registerThreadLocal(ThreadLocal threadLocal, TtlCopier copier, boolean force) { if (threadLocal instanceof TransmittableThreadLocal) { logger.warning("register a TransmittableThreadLocal instance, this is unnecessary!"); return true; @@ -710,7 +708,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @since 2.11.0 */ @SuppressWarnings("unchecked") - public static boolean registerThreadLocalWithShadowCopier(@NotNull ThreadLocal threadLocal, boolean force) { + public static boolean registerThreadLocalWithShadowCopier(ThreadLocal threadLocal, boolean force) { return registerThreadLocal(threadLocal, (TtlCopier) shadowCopier, force); } @@ -724,7 +722,7 @@ public class TransmittableThreadLocal extends InheritableThreadLocal imple * @see #registerThreadLocalWithShadowCopier(ThreadLocal) * @since 2.11.0 */ - public static boolean unregisterThreadLocal(@NotNull ThreadLocal threadLocal) { + public static boolean unregisterThreadLocal(ThreadLocal threadLocal) { if (threadLocal instanceof TransmittableThreadLocal) { logger.warning("unregister a TransmittableThreadLocal instance, this is unnecessary!"); return true; diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCallable.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCallable.java index c4c937216..cb2c4b12d 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCallable.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlCallable.java @@ -5,8 +5,6 @@ import com.fr.third.alibaba.ttl.spi.TtlAttachmentsDelegate; import com.fr.third.alibaba.ttl.spi.TtlEnhanced; import com.fr.third.alibaba.ttl.spi.TtlWrapper; import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -42,7 +40,7 @@ public final class TtlCallable implements Callable, TtlWrapper private final Callable callable; private final boolean releaseTtlValueReferenceAfterCall; - private TtlCallable(@NotNull Callable callable, boolean releaseTtlValueReferenceAfterCall) { + private TtlCallable(Callable callable, boolean releaseTtlValueReferenceAfterCall) { this.capturedRef = new AtomicReference(capture()); this.callable = callable; this.releaseTtlValueReferenceAfterCall = releaseTtlValueReferenceAfterCall; @@ -69,7 +67,7 @@ public final class TtlCallable implements Callable, TtlWrapper /** * return the original/underneath {@link Callable}. */ - @NotNull + public Callable getCallable() { return unwrap(); } @@ -80,7 +78,7 @@ public final class TtlCallable implements Callable, TtlWrapper * @see TtlUnwrap#unwrap(Object) * @since 2.11.4 */ - @NotNull + @Override public Callable unwrap() { return callable; @@ -114,8 +112,8 @@ public final class TtlCallable implements Callable, TtlWrapper * @param callable input {@link Callable} * @return Wrapped {@link Callable} */ - @Nullable - public static TtlCallable get(@Nullable Callable callable) { + + public static TtlCallable get( Callable callable) { return get(callable, false); } @@ -129,8 +127,8 @@ public final class TtlCallable implements Callable, TtlWrapper * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred. * @return Wrapped {@link Callable} */ - @Nullable - public static TtlCallable get(@Nullable Callable callable, boolean releaseTtlValueReferenceAfterCall) { + + public static TtlCallable get( Callable callable, boolean releaseTtlValueReferenceAfterCall) { return get(callable, releaseTtlValueReferenceAfterCall, false); } @@ -144,8 +142,8 @@ public final class TtlCallable implements Callable, TtlWrapper * @param idempotent is idempotent or not. {@code true} will cover up bugs! DO NOT set, only when you know why. * @return Wrapped {@link Callable} */ - @Nullable - public static TtlCallable get(@Nullable Callable callable, boolean releaseTtlValueReferenceAfterCall, boolean idempotent) { + + public static TtlCallable get( Callable callable, boolean releaseTtlValueReferenceAfterCall, boolean idempotent) { if (null == callable) return null; if (callable instanceof TtlEnhanced) { @@ -162,8 +160,8 @@ public final class TtlCallable implements Callable, TtlWrapper * @param tasks task to be wrapped * @return Wrapped {@link Callable} */ - @NotNull - public static List> gets(@Nullable Collection> tasks) { + + public static List> gets( Collection> tasks) { return gets(tasks, false, false); } @@ -174,8 +172,8 @@ public final class TtlCallable implements Callable, TtlWrapper * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred. * @return Wrapped {@link Callable} */ - @NotNull - public static List> gets(@Nullable Collection> tasks, boolean releaseTtlValueReferenceAfterCall) { + + public static List> gets( Collection> tasks, boolean releaseTtlValueReferenceAfterCall) { return gets(tasks, releaseTtlValueReferenceAfterCall, false); } @@ -187,8 +185,8 @@ public final class TtlCallable implements Callable, TtlWrapper * @param idempotent is idempotent or not. {@code true} will cover up bugs! DO NOT set, only when you know why. * @return Wrapped {@link Callable} */ - @NotNull - public static List> gets(@Nullable Collection> tasks, boolean releaseTtlValueReferenceAfterCall, boolean idempotent) { + + public static List> gets( Collection> tasks, boolean releaseTtlValueReferenceAfterCall, boolean idempotent) { if (null == tasks) return Collections.emptyList(); List> copy = new ArrayList>(); @@ -209,8 +207,8 @@ public final class TtlCallable implements Callable, TtlWrapper * @see #get(Callable) * @since 2.10.2 */ - @Nullable - public static Callable unwrap(@Nullable Callable callable) { + + public static Callable unwrap( Callable callable) { if (!(callable instanceof TtlCallable)) return callable; else return ((TtlCallable) callable).getCallable(); } @@ -226,8 +224,8 @@ public final class TtlCallable implements Callable, TtlWrapper * @see #unwrap(Callable) * @since 2.10.2 */ - @NotNull - public static List> unwraps(@Nullable Collection> tasks) { + + public static List> unwraps( Collection> tasks) { if (null == tasks) return Collections.emptyList(); List> copy = new ArrayList>(); @@ -246,7 +244,7 @@ public final class TtlCallable implements Callable, TtlWrapper * @since 2.11.0 */ @Override - public void setTtlAttachment(@NotNull String key, Object value) { + public void setTtlAttachment(String key, Object value) { ttlAttachment.setTtlAttachment(key, value); } @@ -256,7 +254,7 @@ public final class TtlCallable implements Callable, TtlWrapper * @since 2.11.0 */ @Override - public T getTtlAttachment(@NotNull String key) { + public T getTtlAttachment(String key) { return ttlAttachment.getTtlAttachment(key); } } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlEnhanced.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlEnhanced.java index 9849dadcf..b4fca536d 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlEnhanced.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlEnhanced.java @@ -9,7 +9,7 @@ import com.fr.third.alibaba.ttl.spi.TtlAttachments; */ @Deprecated -// [ERROR] The class name com.alibaba.ttl.TtlEnhanced shadows -// the simple name of implemented interface com.alibaba.ttl.spi.TtlEnhanced [com.alibaba.ttl.TtlEnhanced] +// [ERROR] The class name com.fr.third.alibaba.ttl.TtlEnhanced shadows +// the simple name of implemented interface com.fr.third.alibaba.ttl.spi.TtlEnhanced [com.fr.third.alibaba.ttl.TtlEnhanced] public interface TtlEnhanced extends com.fr.third.alibaba.ttl.spi.TtlEnhanced { } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRunnable.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRunnable.java index e859150dd..cc581bfd1 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRunnable.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlRunnable.java @@ -5,8 +5,6 @@ import com.fr.third.alibaba.ttl.spi.TtlAttachmentsDelegate; import com.fr.third.alibaba.ttl.spi.TtlEnhanced; import com.fr.third.alibaba.ttl.spi.TtlWrapper; import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -39,7 +37,7 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh private final Runnable runnable; private final boolean releaseTtlValueReferenceAfterRun; - private TtlRunnable(@NotNull Runnable runnable, boolean releaseTtlValueReferenceAfterRun) { + private TtlRunnable(Runnable runnable, boolean releaseTtlValueReferenceAfterRun) { this.capturedRef = new AtomicReference(capture()); this.runnable = runnable; this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun; @@ -66,7 +64,7 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh /** * return original/unwrapped {@link Runnable}. */ - @NotNull + public Runnable getRunnable() { return unwrap(); } @@ -77,7 +75,7 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh * @see TtlUnwrap#unwrap(Object) * @since 2.11.4 */ - @NotNull + @Override public Runnable unwrap() { return runnable; @@ -110,8 +108,8 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh * @return Wrapped {@link Runnable} * @throws IllegalStateException when input is {@link TtlRunnable} already. */ - @Nullable - public static TtlRunnable get(@Nullable Runnable runnable) { + + public static TtlRunnable get( Runnable runnable) { return get(runnable, false, false); } @@ -123,8 +121,8 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh * @return Wrapped {@link Runnable} * @throws IllegalStateException when input is {@link TtlRunnable} already. */ - @Nullable - public static TtlRunnable get(@Nullable Runnable runnable, boolean releaseTtlValueReferenceAfterRun) { + + public static TtlRunnable get( Runnable runnable, boolean releaseTtlValueReferenceAfterRun) { return get(runnable, releaseTtlValueReferenceAfterRun, false); } @@ -139,8 +137,8 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh * @return Wrapped {@link Runnable} * @throws IllegalStateException when input is {@link TtlRunnable} already and not idempotent. */ - @Nullable - public static TtlRunnable get(@Nullable Runnable runnable, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) { + + public static TtlRunnable get( Runnable runnable, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) { if (null == runnable) return null; if (runnable instanceof TtlEnhanced) { @@ -158,8 +156,8 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh * @return wrapped tasks * @throws IllegalStateException when input is {@link TtlRunnable} already. */ - @NotNull - public static List gets(@Nullable Collection tasks) { + + public static List gets( Collection tasks) { return gets(tasks, false, false); } @@ -171,8 +169,8 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh * @return wrapped tasks * @throws IllegalStateException when input is {@link TtlRunnable} already. */ - @NotNull - public static List gets(@Nullable Collection tasks, boolean releaseTtlValueReferenceAfterRun) { + + public static List gets( Collection tasks, boolean releaseTtlValueReferenceAfterRun) { return gets(tasks, releaseTtlValueReferenceAfterRun, false); } @@ -187,8 +185,8 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh * @return wrapped tasks * @throws IllegalStateException when input is {@link TtlRunnable} already and not idempotent. */ - @NotNull - public static List gets(@Nullable Collection tasks, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) { + + public static List gets( Collection tasks, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) { if (null == tasks) return Collections.emptyList(); List copy = new ArrayList(); @@ -209,8 +207,8 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh * @see #get(Runnable) * @since 2.10.2 */ - @Nullable - public static Runnable unwrap(@Nullable Runnable runnable) { + + public static Runnable unwrap( Runnable runnable) { if (!(runnable instanceof TtlRunnable)) return runnable; else return ((TtlRunnable) runnable).getRunnable(); } @@ -226,8 +224,8 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh * @see #unwrap(Runnable) * @since 2.10.2 */ - @NotNull - public static List unwraps(@Nullable Collection tasks) { + + public static List unwraps( Collection tasks) { if (null == tasks) return Collections.emptyList(); List copy = new ArrayList(); @@ -246,7 +244,7 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh * @since 2.11.0 */ @Override - public void setTtlAttachment(@NotNull String key, Object value) { + public void setTtlAttachment(String key, Object value) { ttlAttachment.setTtlAttachment(key, value); } @@ -256,7 +254,7 @@ public final class TtlRunnable implements Runnable, TtlWrapper, TtlEnh * @since 2.11.0 */ @Override - public T getTtlAttachment(@NotNull String key) { + public T getTtlAttachment(String key) { return ttlAttachment.getTtlAttachment(key); } } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlTimerTask.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlTimerTask.java index 448c8ff12..2e3699a0a 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlTimerTask.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlTimerTask.java @@ -3,8 +3,8 @@ package com.fr.third.alibaba.ttl; import com.fr.third.alibaba.ttl.spi.TtlEnhanced; import com.fr.third.alibaba.ttl.spi.TtlWrapper; import com.fr.third.alibaba.ttl.threadpool.agent.TtlAgent; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; + + import java.util.*; import java.util.concurrent.atomic.AtomicReference; @@ -35,7 +35,7 @@ public final class TtlTimerTask extends TimerTask implements TtlWrapper(capture()); this.timerTask = timerTask; this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun; @@ -68,7 +68,7 @@ public final class TtlTimerTask extends TimerTask implements TtlWrapperDO NOT set, only when you know why. * @return Wrapped {@link TimerTask} */ - @Nullable - public static TtlTimerTask get(@Nullable TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) { + + public static TtlTimerTask get( TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) { if (null == timerTask) return null; if (timerTask instanceof TtlEnhanced) { @@ -163,8 +163,8 @@ public final class TtlTimerTask extends TimerTask implements TtlWrapper unwraps(@Nullable Collection tasks) { + + public static List unwraps( Collection tasks) { if (null == tasks) return Collections.emptyList(); List copy = new ArrayList(); diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlUnwrap.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlUnwrap.java index 82a87b63c..db8866bdc 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlUnwrap.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlUnwrap.java @@ -3,7 +3,7 @@ package com.fr.third.alibaba.ttl; import com.fr.third.alibaba.ttl.spi.TtlWrapper; import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; import com.fr.third.alibaba.ttl.threadpool.TtlForkJoinPoolHelper; -import org.jetbrains.annotations.Nullable; + import java.util.concurrent.Callable; @@ -48,9 +48,9 @@ public class TtlUnwrap { * @see TtlForkJoinPoolHelper#unwrap(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory) * @since 2.11.4 */ - @Nullable + @SuppressWarnings("unchecked") - public static T unwrap(@Nullable T obj) { + public static T unwrap( T obj) { if (!isWrapper(obj)) return obj; else return ((TtlWrapper) obj).unwrap(); } @@ -60,7 +60,7 @@ public class TtlUnwrap { * * @since 2.11.4 */ - public static boolean isWrapper(@Nullable T obj) { + public static boolean isWrapper( T obj) { return obj instanceof TtlWrapper; } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlWrappers.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlWrappers.java index d932c3568..79ceddbc0 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlWrappers.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/TtlWrappers.java @@ -2,8 +2,8 @@ package com.fr.third.alibaba.ttl; import com.fr.third.alibaba.ttl.spi.TtlEnhanced; import com.fr.third.alibaba.ttl.spi.TtlWrapper; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; + + import java.util.function.*; @@ -34,8 +34,8 @@ public class TtlWrappers { * @see TtlUnwrap#unwrap(Object) * @since 2.11.4 */ - @Nullable - public static Supplier wrap(@Nullable Supplier supplier) { + + public static Supplier wrap( Supplier supplier) { if (supplier == null) return null; else if (supplier instanceof TtlEnhanced) return supplier; else return new TtlSupplier(supplier); @@ -45,7 +45,7 @@ public class TtlWrappers { final Supplier supplier; final Object captured; - TtlSupplier(@NotNull Supplier supplier) { + TtlSupplier(Supplier supplier) { this.supplier = supplier; this.captured = capture(); } @@ -60,7 +60,7 @@ public class TtlWrappers { } } - @NotNull + @Override public Supplier unwrap() { return supplier; @@ -96,8 +96,8 @@ public class TtlWrappers { * @see TtlUnwrap#unwrap(Object) * @since 2.11.4 */ - @Nullable - public static Consumer wrap(@Nullable Consumer consumer) { + + public static Consumer wrap( Consumer consumer) { if (consumer == null) return null; else if (consumer instanceof TtlEnhanced) return consumer; else return new TtlConsumer(consumer); @@ -107,7 +107,7 @@ public class TtlWrappers { final Consumer consumer; final Object captured; - TtlConsumer(@NotNull Consumer consumer) { + TtlConsumer(Consumer consumer) { this.consumer = consumer; this.captured = capture(); } @@ -122,7 +122,7 @@ public class TtlWrappers { } } - @NotNull + @Override public Consumer unwrap() { return consumer; @@ -158,8 +158,8 @@ public class TtlWrappers { * @see TtlUnwrap#unwrap(Object) * @since 2.11.4 */ - @Nullable - public static BiConsumer wrap(@Nullable BiConsumer consumer) { + + public static BiConsumer wrap( BiConsumer consumer) { if (consumer == null) return null; else if (consumer instanceof TtlEnhanced) return consumer; else return new TtlBiConsumer(consumer); @@ -169,7 +169,7 @@ public class TtlWrappers { final BiConsumer consumer; final Object captured; - TtlBiConsumer(@NotNull BiConsumer consumer) { + TtlBiConsumer(BiConsumer consumer) { this.consumer = consumer; this.captured = capture(); } @@ -184,7 +184,7 @@ public class TtlWrappers { } } - @NotNull + @Override public BiConsumer unwrap() { return consumer; @@ -220,8 +220,8 @@ public class TtlWrappers { * @see TtlUnwrap#unwrap(Object) * @since 2.11.4 */ - @Nullable - public static Function wrap(@Nullable Function fn) { + + public static Function wrap( Function fn) { if (fn == null) return null; else if (fn instanceof TtlEnhanced) return fn; else return new TtlFunction(fn); @@ -231,7 +231,7 @@ public class TtlWrappers { final Function fn; final Object captured; - TtlFunction(@NotNull Function fn) { + TtlFunction(Function fn) { this.fn = fn; this.captured = capture(); } @@ -246,7 +246,7 @@ public class TtlWrappers { } } - @NotNull + @Override public Function unwrap() { return fn; @@ -282,8 +282,8 @@ public class TtlWrappers { * @see TtlUnwrap#unwrap(Object) * @since 2.11.4 */ - @Nullable - public static BiFunction wrap(@Nullable BiFunction fn) { + + public static BiFunction wrap( BiFunction fn) { if (fn == null) return null; else if (fn instanceof TtlEnhanced) return fn; else return new TtlBiFunction(fn); @@ -293,7 +293,7 @@ public class TtlWrappers { final BiFunction fn; final Object captured; - TtlBiFunction(@NotNull BiFunction fn) { + TtlBiFunction(BiFunction fn) { this.fn = fn; this.captured = capture(); } @@ -308,7 +308,7 @@ public class TtlWrappers { } } - @NotNull + @Override public BiFunction unwrap() { return fn; diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachments.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachments.java index d3f83bff2..73f527710 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachments.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachments.java @@ -2,7 +2,6 @@ package com.fr.third.alibaba.ttl.spi; import com.fr.third.alibaba.ttl.TtlCallable; import com.fr.third.alibaba.ttl.TtlRunnable; -import org.jetbrains.annotations.NotNull; /** * The TTL attachments for TTL tasks, eg: {@link TtlRunnable}, {@link TtlCallable}. @@ -18,7 +17,7 @@ public interface TtlAttachments extends TtlEnhanced { * @param value attachment value * @since 2.11.0 */ - void setTtlAttachment(@NotNull String key, Object value); + void setTtlAttachment(String key, Object value); /** * get the TTL attachment for TTL tasks @@ -26,7 +25,7 @@ public interface TtlAttachments extends TtlEnhanced { * @param key attachment key * @since 2.11.0 */ - T getTtlAttachment(@NotNull String key); + T getTtlAttachment(String key); /** * The attachment key of TTL task, weather this task is a auto wrapper task. diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachmentsDelegate.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachmentsDelegate.java index fb50ea218..9df5d2f85 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachmentsDelegate.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlAttachmentsDelegate.java @@ -2,7 +2,6 @@ package com.fr.third.alibaba.ttl.spi; import com.fr.third.alibaba.ttl.TtlCallable; import com.fr.third.alibaba.ttl.TtlRunnable; -import org.jetbrains.annotations.NotNull; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -19,13 +18,13 @@ public class TtlAttachmentsDelegate implements TtlAttachments { private final ConcurrentMap attachments = new ConcurrentHashMap(); @Override - public void setTtlAttachment(@NotNull String key, Object value) { + public void setTtlAttachment(String key, Object value) { attachments.put(key, value); } @Override @SuppressWarnings("unchecked") - public T getTtlAttachment(@NotNull String key) { + public T getTtlAttachment(String key) { return (T) attachments.get(key); } } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlWrapper.java index 5fd32b1ed..47da24daf 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlWrapper.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/spi/TtlWrapper.java @@ -1,7 +1,6 @@ package com.fr.third.alibaba.ttl.spi; import com.fr.third.alibaba.ttl.TtlUnwrap; -import org.jetbrains.annotations.NotNull; /** * Ttl Wrapper interface. @@ -21,6 +20,6 @@ public interface TtlWrapper extends TtlEnhanced { * * @see TtlUnwrap#unwrap(Object) */ - @NotNull + T unwrap(); } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java index 44a508b99..3e5655e57 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java @@ -1,7 +1,6 @@ package com.fr.third.alibaba.ttl.threadpool; import com.fr.third.alibaba.ttl.spi.TtlWrapper; -import org.jetbrains.annotations.NotNull; import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory; @@ -16,6 +15,6 @@ public interface DisableInheritableForkJoinWorkerThreadFactory extends ForkJoinW * Unwrap {@link DisableInheritableThreadFactory} to the original/underneath one. */ @Override - @NotNull + ForkJoinWorkerThreadFactory unwrap(); } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java index d96b8282a..4a5b11d63 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java @@ -1,6 +1,5 @@ package com.fr.third.alibaba.ttl.threadpool; -import org.jetbrains.annotations.NotNull; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory; @@ -16,7 +15,7 @@ import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.rest class DisableInheritableForkJoinWorkerThreadFactoryWrapper implements DisableInheritableForkJoinWorkerThreadFactory { private final ForkJoinWorkerThreadFactory threadFactory; - DisableInheritableForkJoinWorkerThreadFactoryWrapper(@NotNull ForkJoinWorkerThreadFactory threadFactory) { + DisableInheritableForkJoinWorkerThreadFactoryWrapper(ForkJoinWorkerThreadFactory threadFactory) { this.threadFactory = threadFactory; } @@ -31,7 +30,6 @@ class DisableInheritableForkJoinWorkerThreadFactoryWrapper implements DisableInh } @Override - @NotNull public ForkJoinWorkerThreadFactory unwrap() { return threadFactory; } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java index 90049cc3e..6b25fe898 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java @@ -1,7 +1,6 @@ package com.fr.third.alibaba.ttl.threadpool; import com.fr.third.alibaba.ttl.spi.TtlWrapper; -import org.jetbrains.annotations.NotNull; import java.util.concurrent.ThreadFactory; @@ -17,6 +16,6 @@ public interface DisableInheritableThreadFactory extends ThreadFactory, TtlWrapp * Unwrap {@link DisableInheritableThreadFactory} to the original/underneath one. */ @Override - @NotNull + ThreadFactory unwrap(); } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java index 5ecf93cb0..95f76b978 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java @@ -1,6 +1,5 @@ package com.fr.third.alibaba.ttl.threadpool; -import org.jetbrains.annotations.NotNull; import java.util.concurrent.ThreadFactory; @@ -14,12 +13,12 @@ import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.rest class DisableInheritableThreadFactoryWrapper implements DisableInheritableThreadFactory { private final ThreadFactory threadFactory; - DisableInheritableThreadFactoryWrapper(@NotNull ThreadFactory threadFactory) { + DisableInheritableThreadFactoryWrapper(ThreadFactory threadFactory) { this.threadFactory = threadFactory; } @Override - public Thread newThread(@NotNull Runnable r) { + public Thread newThread(Runnable r) { final Object backup = clear(); try { return threadFactory.newThread(r); @@ -28,7 +27,7 @@ class DisableInheritableThreadFactoryWrapper implements DisableInheritableThread } } - @NotNull + @Override public ThreadFactory unwrap() { return threadFactory; diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorServiceTtlWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorServiceTtlWrapper.java index ebb4ea482..b415395b1 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorServiceTtlWrapper.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorServiceTtlWrapper.java @@ -4,7 +4,6 @@ import com.fr.third.alibaba.ttl.TransmittableThreadLocal; import com.fr.third.alibaba.ttl.TtlCallable; import com.fr.third.alibaba.ttl.TtlRunnable; import com.fr.third.alibaba.ttl.spi.TtlEnhanced; -import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.List; @@ -21,7 +20,7 @@ import java.util.concurrent.*; class ExecutorServiceTtlWrapper extends ExecutorTtlWrapper implements ExecutorService, TtlEnhanced { private final ExecutorService executorService; - ExecutorServiceTtlWrapper(@NotNull ExecutorService executorService) { + ExecutorServiceTtlWrapper(ExecutorService executorService) { super(executorService); this.executorService = executorService; } @@ -31,7 +30,7 @@ class ExecutorServiceTtlWrapper extends ExecutorTtlWrapper implements ExecutorSe executorService.shutdown(); } - @NotNull + @Override public List shutdownNow() { return executorService.shutdownNow(); @@ -48,52 +47,52 @@ class ExecutorServiceTtlWrapper extends ExecutorTtlWrapper implements ExecutorSe } @Override - public boolean awaitTermination(long timeout, @NotNull TimeUnit unit) throws InterruptedException { + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return executorService.awaitTermination(timeout, unit); } - @NotNull + @Override - public Future submit(@NotNull Callable task) { + public Future submit(Callable task) { return executorService.submit(TtlCallable.get(task)); } - @NotNull + @Override - public Future submit(@NotNull Runnable task, T result) { + public Future submit(Runnable task, T result) { return executorService.submit(TtlRunnable.get(task), result); } - @NotNull + @Override - public Future submit(@NotNull Runnable task) { + public Future submit(Runnable task) { return executorService.submit(TtlRunnable.get(task)); } - @NotNull + @Override - public List> invokeAll(@NotNull Collection> tasks) throws InterruptedException { + public List> invokeAll(Collection> tasks) throws InterruptedException { return executorService.invokeAll(TtlCallable.gets(tasks)); } - @NotNull + @Override - public List> invokeAll(@NotNull Collection> tasks, long timeout, @NotNull TimeUnit unit) throws InterruptedException { + public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { return executorService.invokeAll(TtlCallable.gets(tasks), timeout, unit); } - @NotNull + @Override - public T invokeAny(@NotNull Collection> tasks) throws InterruptedException, ExecutionException { + public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException { return executorService.invokeAny(TtlCallable.gets(tasks)); } @Override - public T invokeAny(@NotNull Collection> tasks, long timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return executorService.invokeAny(TtlCallable.gets(tasks), timeout, unit); } - @NotNull + @Override public ExecutorService unwrap() { return executorService; diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorTtlWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorTtlWrapper.java index 87aabac2d..ffb3309d7 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorTtlWrapper.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ExecutorTtlWrapper.java @@ -4,7 +4,6 @@ import com.fr.third.alibaba.ttl.TransmittableThreadLocal; import com.fr.third.alibaba.ttl.TtlRunnable; import com.fr.third.alibaba.ttl.spi.TtlEnhanced; import com.fr.third.alibaba.ttl.spi.TtlWrapper; -import org.jetbrains.annotations.NotNull; import java.util.concurrent.Executor; @@ -19,17 +18,17 @@ import java.util.concurrent.Executor; class ExecutorTtlWrapper implements Executor, TtlWrapper, TtlEnhanced { private final Executor executor; - ExecutorTtlWrapper(@NotNull Executor executor) { + ExecutorTtlWrapper(Executor executor) { this.executor = executor; } @Override - public void execute(@NotNull Runnable command) { + public void execute(Runnable command) { executor.execute(TtlRunnable.get(command)); } @Override - @NotNull + public Executor unwrap() { return executor; } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ScheduledExecutorServiceTtlWrapper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ScheduledExecutorServiceTtlWrapper.java index dd1ea268e..a26b67fcb 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ScheduledExecutorServiceTtlWrapper.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/ScheduledExecutorServiceTtlWrapper.java @@ -4,7 +4,6 @@ import com.fr.third.alibaba.ttl.TransmittableThreadLocal; import com.fr.third.alibaba.ttl.TtlCallable; import com.fr.third.alibaba.ttl.TtlRunnable; import com.fr.third.alibaba.ttl.spi.TtlEnhanced; -import org.jetbrains.annotations.NotNull; import java.util.concurrent.Callable; @@ -24,37 +23,37 @@ import java.util.concurrent.TimeUnit; class ScheduledExecutorServiceTtlWrapper extends ExecutorServiceTtlWrapper implements ScheduledExecutorService, TtlEnhanced { final ScheduledExecutorService scheduledExecutorService; - public ScheduledExecutorServiceTtlWrapper(@NotNull ScheduledExecutorService scheduledExecutorService) { + public ScheduledExecutorServiceTtlWrapper(ScheduledExecutorService scheduledExecutorService) { super(scheduledExecutorService); this.scheduledExecutorService = scheduledExecutorService; } - @NotNull + @Override - public ScheduledFuture schedule(@NotNull Runnable command, long delay, @NotNull TimeUnit unit) { + public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { return scheduledExecutorService.schedule(TtlRunnable.get(command), delay, unit); } - @NotNull + @Override - public ScheduledFuture schedule(@NotNull Callable callable, long delay, @NotNull TimeUnit unit) { + public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { return scheduledExecutorService.schedule(TtlCallable.get(callable), delay, unit); } - @NotNull + @Override - public ScheduledFuture scheduleAtFixedRate(@NotNull Runnable command, long initialDelay, long period, @NotNull TimeUnit unit) { + public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { return scheduledExecutorService.scheduleAtFixedRate(TtlRunnable.get(command), initialDelay, period, unit); } - @NotNull + @Override - public ScheduledFuture scheduleWithFixedDelay(@NotNull Runnable command, long initialDelay, long delay, @NotNull TimeUnit unit) { + public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { return scheduledExecutorService.scheduleWithFixedDelay(TtlRunnable.get(command), initialDelay, delay, unit); } @Override - @NotNull + public ScheduledExecutorService unwrap() { return scheduledExecutorService; } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlExecutors.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlExecutors.java index 39a273155..7d05f0df3 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlExecutors.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlExecutors.java @@ -3,7 +3,6 @@ package com.fr.third.alibaba.ttl.threadpool; import com.fr.third.alibaba.ttl.TransmittableThreadLocal; import com.fr.third.alibaba.ttl.spi.TtlEnhanced; import com.fr.third.alibaba.ttl.threadpool.agent.TtlAgent; -import org.jetbrains.annotations.Nullable; import java.util.concurrent.*; @@ -41,8 +40,8 @@ public final class TtlExecutors { * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} * to the execution time of {@link Runnable}. */ - @Nullable - public static Executor getTtlExecutor(@Nullable Executor executor) { + + public static Executor getTtlExecutor( Executor executor) { if (TtlAgent.isTtlAgentLoaded() || null == executor || executor instanceof TtlEnhanced) { return executor; } @@ -54,8 +53,8 @@ public final class TtlExecutors { * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link java.util.concurrent.Callable} * to the execution time of {@link Runnable} or {@link java.util.concurrent.Callable}. */ - @Nullable - public static ExecutorService getTtlExecutorService(@Nullable ExecutorService executorService) { + + public static ExecutorService getTtlExecutorService( ExecutorService executorService) { if (TtlAgent.isTtlAgentLoaded() || executorService == null || executorService instanceof TtlEnhanced) { return executorService; } @@ -67,8 +66,8 @@ public final class TtlExecutors { * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link java.util.concurrent.Callable} * to the execution time of {@link Runnable} or {@link java.util.concurrent.Callable}. */ - @Nullable - public static ScheduledExecutorService getTtlScheduledExecutorService(@Nullable ScheduledExecutorService scheduledExecutorService) { + + public static ScheduledExecutorService getTtlScheduledExecutorService( ScheduledExecutorService scheduledExecutorService) { if (TtlAgent.isTtlAgentLoaded() || scheduledExecutorService == null || scheduledExecutorService instanceof TtlEnhanced) { return scheduledExecutorService; } @@ -90,7 +89,7 @@ public final class TtlExecutors { * @see #unwrap(Executor) * @since 2.8.0 */ - public static boolean isTtlWrapper(@Nullable T executor) { + public static boolean isTtlWrapper( T executor) { return executor instanceof TtlEnhanced; } @@ -110,9 +109,9 @@ public final class TtlExecutors { * @see #isTtlWrapper(Executor) * @since 2.8.0 */ - @Nullable + @SuppressWarnings("unchecked") - public static T unwrap(@Nullable T executor) { + public static T unwrap( T executor) { if (!isTtlWrapper(executor)) return executor; return (T) ((ExecutorTtlWrapper) executor).unwrap(); @@ -125,8 +124,8 @@ public final class TtlExecutors { * @see DisableInheritableThreadFactory * @since 2.10.0 */ - @Nullable - public static ThreadFactory getDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) { + + public static ThreadFactory getDisableInheritableThreadFactory( ThreadFactory threadFactory) { if (threadFactory == null || isDisableInheritableThreadFactory(threadFactory)) return threadFactory; return new DisableInheritableThreadFactoryWrapper(threadFactory); @@ -138,7 +137,7 @@ public final class TtlExecutors { * @see #getDisableInheritableThreadFactory(ThreadFactory) * @since 2.10.0 */ - @Nullable + public static ThreadFactory getDefaultDisableInheritableThreadFactory() { return getDisableInheritableThreadFactory(Executors.defaultThreadFactory()); } @@ -149,7 +148,7 @@ public final class TtlExecutors { * @see DisableInheritableThreadFactory * @since 2.10.0 */ - public static boolean isDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) { + public static boolean isDisableInheritableThreadFactory( ThreadFactory threadFactory) { return threadFactory instanceof DisableInheritableThreadFactory; } @@ -159,8 +158,8 @@ public final class TtlExecutors { * @see DisableInheritableThreadFactory * @since 2.10.0 */ - @Nullable - public static ThreadFactory unwrap(@Nullable ThreadFactory threadFactory) { + + public static ThreadFactory unwrap( ThreadFactory threadFactory) { if (!isDisableInheritableThreadFactory(threadFactory)) return threadFactory; return ((DisableInheritableThreadFactory) threadFactory).unwrap(); diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlForkJoinPoolHelper.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlForkJoinPoolHelper.java index 10b862d1f..dd9bd8104 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlForkJoinPoolHelper.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlForkJoinPoolHelper.java @@ -1,6 +1,5 @@ package com.fr.third.alibaba.ttl.threadpool; -import org.jetbrains.annotations.Nullable; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory; @@ -26,8 +25,8 @@ public class TtlForkJoinPoolHelper { * @see DisableInheritableForkJoinWorkerThreadFactory * @since 2.10.1 */ - @Nullable - public static ForkJoinWorkerThreadFactory getDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) { + + public static ForkJoinWorkerThreadFactory getDisableInheritableForkJoinWorkerThreadFactory( ForkJoinWorkerThreadFactory threadFactory) { if (threadFactory == null || isDisableInheritableForkJoinWorkerThreadFactory(threadFactory)) return threadFactory; @@ -40,7 +39,7 @@ public class TtlForkJoinPoolHelper { * @see #getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory) * @since 2.10.1 */ - @Nullable + public static ForkJoinWorkerThreadFactory getDefaultDisableInheritableForkJoinWorkerThreadFactory() { return getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinPool.defaultForkJoinWorkerThreadFactory); } @@ -51,7 +50,7 @@ public class TtlForkJoinPoolHelper { * @see DisableInheritableForkJoinWorkerThreadFactory * @since 2.10.1 */ - public static boolean isDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) { + public static boolean isDisableInheritableForkJoinWorkerThreadFactory( ForkJoinWorkerThreadFactory threadFactory) { return threadFactory instanceof DisableInheritableForkJoinWorkerThreadFactory; } @@ -61,8 +60,8 @@ public class TtlForkJoinPoolHelper { * @see DisableInheritableForkJoinWorkerThreadFactory * @since 2.10.1 */ - @Nullable - public static ForkJoinWorkerThreadFactory unwrap(@Nullable ForkJoinWorkerThreadFactory threadFactory) { + + public static ForkJoinWorkerThreadFactory unwrap( ForkJoinWorkerThreadFactory threadFactory) { if (!isDisableInheritableForkJoinWorkerThreadFactory(threadFactory)) return threadFactory; return ((DisableInheritableForkJoinWorkerThreadFactory) threadFactory).unwrap(); diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlUtils.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlUtils.java new file mode 100644 index 000000000..6f7d9830c --- /dev/null +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/TtlUtils.java @@ -0,0 +1,39 @@ +package com.fr.third.alibaba.ttl.threadpool; + +import com.fr.third.alibaba.ttl.TtlRunnable; +import com.fr.third.alibaba.ttl.spi.TtlAttachments; +import com.fr.third.alibaba.ttl.spi.TtlEnhanced; + +import static com.fr.third.alibaba.ttl.TransmittableThreadLocal.Transmitter.capture; + + +public class TtlUtils { + public static Object doCaptureWhenNotTtlEnhanced( Object obj) { + if (obj instanceof TtlEnhanced) return null; + else return capture(); + } + + public static void setAutoWrapperAttachment( Object ttlAttachment) { + if (notTtlAttachments(ttlAttachment)) return; + ((TtlAttachments) ttlAttachment).setTtlAttachment(TtlAttachments.KEY_IS_AUTO_WRAPPER, true); + } + + + public static Runnable unwrapIfIsAutoWrapper( Runnable runnable) { + if (isAutoWrapper(runnable)) return TtlRunnable.unwrap(runnable); + else return runnable; + } + + private static boolean notTtlAttachments( Object ttlAttachment) { + return !(ttlAttachment instanceof TtlAttachments); + } + + private static boolean isAutoWrapper( Runnable ttlAttachments) { + if (notTtlAttachments(ttlAttachments)) return false; + + final Boolean value = ((TtlAttachments) ttlAttachments).getTtlAttachment(TtlAttachments.KEY_IS_AUTO_WRAPPER); + if (value == null) return false; + + return value; + } +} \ No newline at end of file diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlAgent.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlAgent.java index f1e5bb783..cd3740a07 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlAgent.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlAgent.java @@ -7,12 +7,6 @@ import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlE import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlForkJoinTransformlet; import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlTimerTaskTransformlet; -import com.fr.third.alibaba.ttl.threadpool.DisableInheritableForkJoinWorkerThreadFactory; -import com.fr.third.alibaba.ttl.threadpool.DisableInheritableThreadFactory; -import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; -import com.fr.third.alibaba.ttl.threadpool.TtlForkJoinPoolHelper; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; import java.util.ArrayList; @@ -128,7 +122,7 @@ public final class TtlAgent { * @see Logger#STDERR * @see Logger#STDOUT */ - public static void premain(String agentArgs, @NotNull Instrumentation inst) { + public static void premain(String agentArgs, Instrumentation inst) { kvs = splitCommaColonStringToKV(agentArgs); Logger.setLoggerImplType(getLogImplTypeFromAgentArgs(kvs)); @@ -157,7 +151,7 @@ public final class TtlAgent { } } - private static String getLogImplTypeFromAgentArgs(@NotNull final Map kvs) { + private static String getLogImplTypeFromAgentArgs(final Map kvs) { return kvs.get(Logger.TTL_AGENT_LOGGER_KEY); } @@ -202,15 +196,15 @@ public final class TtlAgent { return isOptionSetOrTrue(kvs, TTL_AGENT_ENABLE_TIMER_TASK_KEY); } - private static boolean isOptionSetOrFalse(@Nullable final Map kvs, @NotNull String key) { + private static boolean isOptionSetOrFalse( final Map kvs, String key) { return isOptionSetOrFalse(kvs, key, false); } - private static boolean isOptionSetOrTrue(@Nullable final Map kvs, @NotNull String key) { + private static boolean isOptionSetOrTrue( final Map kvs, String key) { return isOptionSetOrFalse(kvs, key, true); } - private static boolean isOptionSetOrFalse(@Nullable final Map kvs, @NotNull String key, boolean defaultValue) { + private static boolean isOptionSetOrFalse( final Map kvs, String key, boolean defaultValue) { if (null == kvs) return defaultValue; final boolean hasEnableKey = kvs.containsKey(key); @@ -222,8 +216,8 @@ public final class TtlAgent { /** * Split to {@code json} like String({@code "k1:v1,k2:v2"}) to KV map({@code "k1"->"v1", "k2"->"v2"}). */ - @NotNull - static Map splitCommaColonStringToKV(@Nullable String commaColonString) { + + static Map splitCommaColonStringToKV( String commaColonString) { Map ret = new HashMap(); if (commaColonString == null || commaColonString.trim().length() == 0) return ret; diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlTransformer.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlTransformer.java index 4f8d3ea34..a38628bb8 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlTransformer.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/TtlTransformer.java @@ -3,8 +3,6 @@ package com.fr.third.alibaba.ttl.threadpool.agent; import com.fr.third.alibaba.ttl.threadpool.agent.internal.logging.Logger; import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.ClassInfo; import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.lang.instrument.ClassFileTransformer; @@ -29,7 +27,7 @@ public class TtlTransformer implements ClassFileTransformer { * see {@code @return} of {@link ClassFileTransformer#transform(ClassLoader, String, Class, ProtectionDomain, byte[])} */ - // [ERROR] com.alibaba.ttl.threadpool.agent.TtlTransformer.transform(ClassLoader, String, Class, ProtectionDomain, byte[]) + // [ERROR] com.fr.third.alibaba.ttl.threadpool.agent.TtlTransformer.transform(ClassLoader, String, Class, ProtectionDomain, byte[]) // may expose internal representation by returning TtlTransformer.NO_TRANSFORM // the value is null, so there is NO "EI_EXPOSE_REP" problem actually. private static final byte[] NO_TRANSFORM = null; @@ -44,8 +42,8 @@ public class TtlTransformer implements ClassFileTransformer { } @Override - public final byte[] transform(@Nullable final ClassLoader loader, @Nullable final String classFile, final Class classBeingRedefined, - final ProtectionDomain protectionDomain, @NotNull final byte[] classFileBuffer) { + public final byte[] transform( final ClassLoader loader, final String classFile, final Class classBeingRedefined, + final ProtectionDomain protectionDomain, final byte[] classFileBuffer) { try { // Lambda has no class file, no need to transform, just return. if (classFile == null) return NO_TRANSFORM; @@ -67,7 +65,7 @@ public class TtlTransformer implements ClassFileTransformer { return NO_TRANSFORM; } - private static String toClassName(@NotNull final String classFile) { + private static String toClassName(final String classFile) { return classFile.replace('/', '.'); } } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/ClassInfo.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/ClassInfo.java index 8d656e5c6..e65c6673e 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/ClassInfo.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/ClassInfo.java @@ -1,14 +1,14 @@ package com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet; import com.fr.third.javassist.CtClass; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import com.fr.third.javassist.ClassPool; -import com.fr.third.javassist.CtClass; import com.fr.third.javassist.LoaderClassPath; +import com.fr.third.javassist.NotFoundException; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; /** * @author Jerry Lee (oldratlee at gmail dot com) @@ -18,25 +18,26 @@ public class ClassInfo { private final String className; private final byte[] classFileBuffer; private final ClassLoader loader; + private static Set paths = new CopyOnWriteArraySet<>(); // SuppressFBWarnings for classFileBuffer parameter: - // [ERROR] new com.alibaba.ttl.threadpool.agent.internal.transformlet.ClassInfo(String, byte[], ClassLoader) + // [ERROR] new com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.ClassInfo(String, byte[], ClassLoader) // may expose internal representation by storing an externally mutable object // into ClassInfo.classFileBuffer - public ClassInfo(@NotNull String className, byte[] classFileBuffer, @Nullable ClassLoader loader) { + public ClassInfo(String className, byte[] classFileBuffer, ClassLoader loader) { this.className = className; this.classFileBuffer = classFileBuffer; this.loader = loader; } - @NotNull + public String getClassName() { return className; } private CtClass ctClass; - @NotNull + public CtClass getCtClass() throws IOException { if (ctClass != null) return ctClass; @@ -46,7 +47,13 @@ public class ClassInfo { } else { classPool.appendClassPath(new LoaderClassPath(loader)); } - + for (String path: paths) { + try { + classPool.appendClassPath(path); + } catch (NotFoundException e) { + e.printStackTrace(); + } + } final CtClass clazz = classPool.makeClass(new ByteArrayInputStream(classFileBuffer), false); clazz.defrost(); @@ -63,4 +70,8 @@ public class ClassInfo { public void setModified() { this.modified = true; } + + public static void addPath(String path) { + paths.add(path); + } } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/JavassistTransformlet.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/JavassistTransformlet.java index b88102889..eca3e756d 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/JavassistTransformlet.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/JavassistTransformlet.java @@ -1,6 +1,5 @@ package com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet; -import org.jetbrains.annotations.NotNull; import com.fr.third.javassist.CannotCompileException; import com.fr.third.javassist.NotFoundException; @@ -13,5 +12,5 @@ import java.io.IOException; * @since 2.5.1 */ public interface JavassistTransformlet { - void doTransform(@NotNull ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException; + void doTransform(ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException; } diff --git a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlExecutorTransformlet.java b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlExecutorTransformlet.java index 603e4c5dd..1d6a9a566 100644 --- a/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlExecutorTransformlet.java +++ b/fine-transmittable-thread-local/src/main/java/com/fr/third/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlExecutorTransformlet.java @@ -1,12 +1,8 @@ package com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.impl; -import com.fr.third.alibaba.ttl.threadpool.TtlExecutors; import com.fr.third.alibaba.ttl.threadpool.agent.internal.logging.Logger; import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.ClassInfo; import com.fr.third.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet; -import com.fr.third.alibaba.ttl.TtlCallable; -import com.fr.third.alibaba.ttl.TtlRunnable; -import org.jetbrains.annotations.NotNull; import com.fr.third.javassist.*; import java.io.IOException; @@ -42,8 +38,8 @@ public class TtlExecutorTransformlet implements JavassistTransformlet { EXECUTOR_CLASS_NAMES.add(THREAD_POOL_EXECUTOR_CLASS_NAME); EXECUTOR_CLASS_NAMES.add("java.util.concurrent.ScheduledThreadPoolExecutor"); - PARAM_TYPE_NAME_TO_DECORATE_METHOD_CLASS.put(RUNNABLE_CLASS_NAME, "com.alibaba.ttl.TtlRunnable"); - PARAM_TYPE_NAME_TO_DECORATE_METHOD_CLASS.put("java.util.concurrent.Callable", "com.alibaba.ttl.TtlCallable"); + PARAM_TYPE_NAME_TO_DECORATE_METHOD_CLASS.put(RUNNABLE_CLASS_NAME, "com.fr.third.alibaba.ttl.TtlRunnable"); + PARAM_TYPE_NAME_TO_DECORATE_METHOD_CLASS.put("java.util.concurrent.Callable", "com.fr.third.alibaba.ttl.TtlCallable"); } private static final String THREAD_FACTORY_CLASS_NAME = "java.util.concurrent.ThreadFactory"; @@ -55,7 +51,7 @@ public class TtlExecutorTransformlet implements JavassistTransformlet { } @Override - public void doTransform(@NotNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException { + public void doTransform(final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException { if (EXECUTOR_CLASS_NAMES.contains(classInfo.getClassName())) { final CtClass clazz = classInfo.getCtClass(); @@ -84,10 +80,10 @@ public class TtlExecutorTransformlet implements JavassistTransformlet { /** * @see TtlRunnable#get(Runnable, boolean, boolean) * @see TtlCallable#get(Callable, boolean, boolean) - * @see Utils#setAutoWrapperAttachment(Object) + * @see com.fr.third.alibaba.ttl.threadpool.TtlUtils#setAutoWrapperAttachment(Object) */ // [ERROR] Format string should use %n rather than \n - private void updateSubmitMethodsOfExecutorClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(@NotNull final CtMethod method) throws NotFoundException, CannotCompileException { + private void updateSubmitMethodsOfExecutorClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(final CtMethod method) throws NotFoundException, CannotCompileException { final int modifiers = method.getModifiers(); if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers)) return; @@ -100,7 +96,7 @@ public class TtlExecutorTransformlet implements JavassistTransformlet { // decorate to TTL wrapper, // and then set AutoWrapper attachment/Tag "$%d = %s.get($%d, false, true);" - + "\ncom.alibaba.ttl.threadpool.agent.internal.transformlet.impl.Utils.setAutoWrapperAttachment($%The mechanism for instrumentation + * + * 此包中的不允许直接使用ttl中其他代码 */ package com.fr.third.alibaba.ttl.threadpool.agent; From c67fd548158e29d50eaf60438b1c84f2ea42a520 Mon Sep 17 00:00:00 2001 From: Elijah Date: Fri, 9 Oct 2020 09:35:59 +0800 Subject: [PATCH 5/8] =?UTF-8?q?DEC-14578=20feat:=20=E4=BD=BFhibernate?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=B8=BB=E9=94=AE=E7=9A=84=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../third/org/hibernate/dialect/Dialect.java | 9 ++- .../org/hibernate/dialect/MySQLDialect.java | 5 ++ .../internal/AbstractSchemaMigrator.java | 69 +++++++++++++++++-- .../internal/GroupedSchemaMigratorImpl.java | 3 + .../IndividuallySchemaMigratorImpl.java | 3 + .../internal/StandardPrimaryKeyExporter.java | 63 +++++++++++++++++ 6 files changed, 143 insertions(+), 9 deletions(-) create mode 100644 fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/StandardPrimaryKeyExporter.java diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/Dialect.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/Dialect.java index 2f4d45d07..6d209b985 100644 --- a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/Dialect.java +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/Dialect.java @@ -1601,11 +1601,11 @@ public abstract class Dialect implements ConversionContext { * Build an instance of a {@link SQLExceptionConversionDelegate} for * interpreting dialect-specific error or SQLState codes. *

- * When {@link #buildSQLExceptionConverter} returns null, the default + * When {@link #buildSQLExceptionConverter} returns null, the default * {@link SQLExceptionConverter} is used to interpret SQLState and * error codes. If this method is overridden to return a non-null value, * the default {@link SQLExceptionConverter} will use the returned - * {@link SQLExceptionConversionDelegate} in addition to the following + * {@link SQLExceptionConversionDelegate} in addition to the following * standard delegates: *

    *
  1. a "static" delegate based on the JDBC 4 defined SQLException hierarchy;
  2. @@ -2099,6 +2099,11 @@ public abstract class Dialect implements ConversionContext { return " add constraint " + constraintName + " primary key "; } + + public String getDropPrimaryKeyConstraintString(String constraintName) { + return " drop constraint " + constraintName; + } + /** * Does the database/driver have bug in deleting rows that refer to other rows being deleted in the same query? * diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/MySQLDialect.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/MySQLDialect.java index 81bb77cda..82b4a4b87 100644 --- a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/MySQLDialect.java +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/MySQLDialect.java @@ -244,6 +244,11 @@ public class MySQLDialect extends Dialect { return " drop foreign key "; } + @Override + public String getDropPrimaryKeyConstraintString(String constraintName) { + return " drop primary key "; + } + @Override public LimitHandler getLimitHandler() { return LIMIT_HANDLER; diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java index e89288ed2..0e08a9e46 100644 --- a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java @@ -6,12 +6,6 @@ */ package com.fr.third.org.hibernate.tool.schema.internal; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - import com.fr.third.org.hibernate.boot.Metadata; import com.fr.third.org.hibernate.boot.model.naming.Identifier; import com.fr.third.org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; @@ -26,17 +20,21 @@ import com.fr.third.org.hibernate.engine.config.spi.StandardConverters; import com.fr.third.org.hibernate.engine.jdbc.internal.FormatStyle; import com.fr.third.org.hibernate.engine.jdbc.internal.Formatter; import com.fr.third.org.hibernate.internal.util.StringHelper; +import com.fr.third.org.hibernate.mapping.Column; import com.fr.third.org.hibernate.mapping.Constraint; import com.fr.third.org.hibernate.mapping.ForeignKey; import com.fr.third.org.hibernate.mapping.Index; +import com.fr.third.org.hibernate.mapping.PrimaryKey; import com.fr.third.org.hibernate.mapping.Table; import com.fr.third.org.hibernate.mapping.UniqueKey; import com.fr.third.org.hibernate.resource.transaction.spi.DdlTransactionIsolator; import com.fr.third.org.hibernate.tool.hbm2ddl.UniqueConstraintSchemaUpdateStrategy; +import com.fr.third.org.hibernate.tool.schema.extract.spi.ColumnInformation; import com.fr.third.org.hibernate.tool.schema.extract.spi.DatabaseInformation; import com.fr.third.org.hibernate.tool.schema.extract.spi.ForeignKeyInformation; import com.fr.third.org.hibernate.tool.schema.extract.spi.IndexInformation; import com.fr.third.org.hibernate.tool.schema.extract.spi.NameSpaceTablesInformation; +import com.fr.third.org.hibernate.tool.schema.extract.spi.PrimaryKeyInformation; import com.fr.third.org.hibernate.tool.schema.extract.spi.SequenceInformation; import com.fr.third.org.hibernate.tool.schema.extract.spi.TableInformation; import com.fr.third.org.hibernate.tool.schema.internal.exec.GenerationTarget; @@ -48,9 +46,15 @@ import com.fr.third.org.hibernate.tool.schema.spi.SchemaFilter; import com.fr.third.org.hibernate.tool.schema.spi.SchemaManagementException; import com.fr.third.org.hibernate.tool.schema.spi.SchemaMigrator; import com.fr.third.org.hibernate.tool.schema.spi.TargetDescriptor; - import com.fr.third.org.jboss.logging.Logger; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + import static com.fr.third.org.hibernate.cfg.AvailableSettings.UNIQUE_CONSTRAINT_SCHEMA_UPDATE_STRATEGY; /** @@ -446,6 +450,57 @@ public abstract class AbstractSchemaMigrator implements SchemaMigrator { return tableInformation.getForeignKey( Identifier.toIdentifier( foreignKey.getName() ) ); } + protected void applyPrimaryKey( + Table table, + TableInformation tableInfo, + Dialect dialect, + Metadata metadata, + Formatter formatter, + ExecutionOptions options, + GenerationTarget... targets) { + try { + PrimaryKey primaryKey = table.getPrimaryKey(); + if (primaryKey == null) { + return; + } + Exporter exporter = new StandardPrimaryKeyExporter(dialect); + PrimaryKeyInformation existedPrimaryKeyInfo = tableInfo.getPrimaryKey(); + if (existedPrimaryKeyInfo == null) { + applySqlStrings(true, exporter.getSqlCreateStrings(primaryKey, metadata), formatter, options, targets); + } else if (!columnEquals(table.getPrimaryKey().getColumns(), existedPrimaryKeyInfo.getColumns())) { + //主键列不匹配, 先删再增 + PrimaryKey deletedKey = copyPrimaryKey(tableInfo.getPrimaryKey().getPrimaryKeyIdentifier().getText(), table); + applySqlStrings(true, exporter.getSqlDropStrings(deletedKey, metadata), formatter, options, targets); + applySqlStrings(true, exporter.getSqlCreateStrings(primaryKey, metadata), formatter, options, targets); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + + } + + private PrimaryKey copyPrimaryKey(String newName, Table table) { + PrimaryKey copy = new PrimaryKey(table); + copy.setName(newName); + return copy; + } + + private boolean columnEquals(List columns, Iterable iterator) { + int count = 0; + Set names = new HashSet(); + for (Column column: columns) { + names.add(column.getName().toLowerCase()); + } + for (ColumnInformation columnInformation : iterator) { + String name = columnInformation.getColumnIdentifier().getText(); + if (!names.contains(name.toLowerCase())) { + return false; + } + count++; + } + return count == columns.size(); + } + protected void checkExportIdentifier(Exportable exportable, Set exportIdentifiers) { final String exportIdentifier = exportable.getExportIdentifier(); if ( exportIdentifiers.contains( exportIdentifier ) ) { diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/GroupedSchemaMigratorImpl.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/GroupedSchemaMigratorImpl.java index 14b07629a..7d397a377 100644 --- a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/GroupedSchemaMigratorImpl.java +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/GroupedSchemaMigratorImpl.java @@ -83,6 +83,9 @@ public class GroupedSchemaMigratorImpl extends AbstractSchemaMigrator { if ( tableInformation == null || ( tableInformation != null && tableInformation.isPhysicalTable() ) ) { applyIndexes( table, tableInformation, dialect, metadata, formatter, options, targets ); applyUniqueKeys( table, tableInformation, dialect, metadata, formatter, options, targets ); + if (tableInformation != null) { + applyPrimaryKey(table, tableInformation, dialect, metadata, formatter, options, targets); + } } } } diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/IndividuallySchemaMigratorImpl.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/IndividuallySchemaMigratorImpl.java index 716623bb6..154b20f63 100644 --- a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/IndividuallySchemaMigratorImpl.java +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/IndividuallySchemaMigratorImpl.java @@ -83,6 +83,9 @@ public class IndividuallySchemaMigratorImpl extends AbstractSchemaMigrator { if ( tableInformation == null || ( tableInformation != null && tableInformation.isPhysicalTable() ) ) { applyIndexes( table, tableInformation, dialect, metadata, formatter, options, targets ); applyUniqueKeys( table, tableInformation, dialect, metadata, formatter, options, targets ); + if (tableInformation != null) { + applyPrimaryKey(table, tableInformation, dialect, metadata, formatter, options, targets); + } } } } diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/StandardPrimaryKeyExporter.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/StandardPrimaryKeyExporter.java new file mode 100644 index 000000000..4b9393023 --- /dev/null +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/StandardPrimaryKeyExporter.java @@ -0,0 +1,63 @@ +package com.fr.third.org.hibernate.tool.schema.internal; + +import com.fr.third.org.hibernate.boot.Metadata; +import com.fr.third.org.hibernate.dialect.Dialect; +import com.fr.third.org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import com.fr.third.org.hibernate.mapping.Column; +import com.fr.third.org.hibernate.mapping.PrimaryKey; +import com.fr.third.org.hibernate.tool.schema.spi.Exporter; + +import java.util.Iterator; + +/** + * @author Elijah + * @version 10.5 + * Created by Elijah on 2020/9/30 + */ +public class StandardPrimaryKeyExporter implements Exporter { + private Dialect dialect; + + public StandardPrimaryKeyExporter(Dialect dialect) { + this.dialect = dialect; + } + + @Override + public String[] getSqlCreateStrings(PrimaryKey primaryKey, Metadata metadata) { + final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); + final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( + primaryKey.getTable().getQualifiedTableName(), + dialect + ); + + final String constraintName = dialect.quote( primaryKey.getName() ); + return new String[]{ "alter table " + tableName + dialect.getAddPrimaryKeyConstraintString(constraintName) + " " + columnsToString( primaryKey ) }; + } + + protected String columnsToString(PrimaryKey primaryKey) { + final StringBuilder sb = new StringBuilder(); + sb.append( " (" ); + final Iterator columnIterator = primaryKey.columnIterator(); + while ( columnIterator.hasNext() ) { + final Column column = columnIterator.next(); + sb.append( column.getQuotedName( dialect ) ); + if ( columnIterator.hasNext() ) { + sb.append( ", " ); + } + } + + return sb.append( ')' ).toString(); + } + + @Override + public String[] getSqlDropStrings(PrimaryKey primaryKey, Metadata metadata) { + final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); + final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( + primaryKey.getTable().getQualifiedTableName(), + dialect + ); + final StringBuilder buf = new StringBuilder( "alter table " ); + buf.append( tableName ); + buf.append(dialect.getDropPrimaryKeyConstraintString(dialect.quote( primaryKey.getName()))); + return new String[] { buf.toString() }; + } +} \ No newline at end of file From c92398b9b8ef8ec698dfc48f9e2ca132785674c3 Mon Sep 17 00:00:00 2001 From: Elijah Date: Tue, 13 Oct 2020 09:28:06 +0800 Subject: [PATCH 6/8] =?UTF-8?q?DEC-14578=20feat:=20hibernate=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=88=A0=E9=99=A4=E6=97=A7=E5=94=AF=E4=B8=80=E9=94=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/hibernate/dialect/MySQLDialect.java | 21 ++++++++--- .../dialect/unique/DefaultUniqueDelegate.java | 5 ++- .../dialect/unique/MySQLUniqueDelegate.java | 23 ++++++++++++ .../internal/IndexInformationImpl.java | 20 ++++++++++- ...tionExtractorJdbcDatabaseMetaDataImpl.java | 18 ++++++++++ .../schema/extract/spi/IndexInformation.java | 2 ++ .../internal/AbstractSchemaMigrator.java | 35 +++++++++++++++++++ 7 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/unique/MySQLUniqueDelegate.java diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/MySQLDialect.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/MySQLDialect.java index 82b4a4b87..acee55f31 100644 --- a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/MySQLDialect.java +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/MySQLDialect.java @@ -22,6 +22,8 @@ import com.fr.third.org.hibernate.dialect.identity.MySQLIdentityColumnSupport; import com.fr.third.org.hibernate.dialect.pagination.AbstractLimitHandler; import com.fr.third.org.hibernate.dialect.pagination.LimitHandler; import com.fr.third.org.hibernate.dialect.pagination.LimitHelper; +import com.fr.third.org.hibernate.dialect.unique.MySQLUniqueDelegate; +import com.fr.third.org.hibernate.dialect.unique.UniqueDelegate; import com.fr.third.org.hibernate.engine.spi.RowSelection; import com.fr.third.org.hibernate.exception.LockAcquisitionException; import com.fr.third.org.hibernate.exception.LockTimeoutException; @@ -43,6 +45,8 @@ import com.fr.third.org.hibernate.type.StandardBasicTypes; @SuppressWarnings("deprecation") public class MySQLDialect extends Dialect { + private final UniqueDelegate uniqueDelegate; + private static final LimitHandler LIMIT_HANDLER = new AbstractLimitHandler() { @Override public String processSql(String sql, RowSelection selection) { @@ -196,6 +200,8 @@ public class MySQLDialect extends Dialect { getDefaultProperties().setProperty( Environment.MAX_FETCH_DEPTH, "2" ); getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE ); + + uniqueDelegate = new MySQLUniqueDelegate( this ); } protected void registerVarcharTypes() { @@ -234,6 +240,11 @@ public class MySQLDialect extends Dialect { ); } + @Override + public String getDropPrimaryKeyConstraintString(String constraintName) { + return " drop primary key "; + } + @Override public boolean supportsLimit() { return true; @@ -244,11 +255,6 @@ public class MySQLDialect extends Dialect { return " drop foreign key "; } - @Override - public String getDropPrimaryKeyConstraintString(String constraintName) { - return " drop primary key "; - } - @Override public LimitHandler getLimitHandler() { return LIMIT_HANDLER; @@ -427,6 +433,11 @@ public class MySQLDialect extends Dialect { return ps.getResultSet(); } + @Override + public UniqueDelegate getUniqueDelegate() { + return uniqueDelegate; + } + @Override public boolean supportsRowValueConstructorSyntax() { return true; diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/unique/DefaultUniqueDelegate.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/unique/DefaultUniqueDelegate.java index 836e3b68e..36ffdb5ec 100644 --- a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/unique/DefaultUniqueDelegate.java +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/unique/DefaultUniqueDelegate.java @@ -85,7 +85,7 @@ public class DefaultUniqueDelegate implements UniqueDelegate { final StringBuilder buf = new StringBuilder( "alter table " ); buf.append( tableName ); - buf.append(" drop constraint " ); + buf.append(getDropUnique()); if ( dialect.supportsIfExistsBeforeConstraintName() ) { buf.append( "if exists " ); } @@ -96,4 +96,7 @@ public class DefaultUniqueDelegate implements UniqueDelegate { return buf.toString(); } + protected String getDropUnique(){ + return " drop constraint "; + } } diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/unique/MySQLUniqueDelegate.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/unique/MySQLUniqueDelegate.java new file mode 100644 index 000000000..caab6c8e5 --- /dev/null +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/dialect/unique/MySQLUniqueDelegate.java @@ -0,0 +1,23 @@ +package com.fr.third.org.hibernate.dialect.unique; + +import com.fr.third.org.hibernate.dialect.Dialect; + +/** + * @author Andrea Boriero + */ +public class MySQLUniqueDelegate extends DefaultUniqueDelegate { + + /** + * Constructs MySQLUniqueDelegate + * + * @param dialect The dialect for which we are handling unique constraints + */ + public MySQLUniqueDelegate(Dialect dialect) { + super( dialect ); + } + + @Override + protected String getDropUnique() { + return " drop index "; + } +} \ No newline at end of file diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/internal/IndexInformationImpl.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/internal/IndexInformationImpl.java index 81bc14363..fb33abaa4 100644 --- a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/internal/IndexInformationImpl.java +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/internal/IndexInformationImpl.java @@ -21,12 +21,19 @@ import com.fr.third.org.hibernate.tool.schema.spi.SchemaManagementException; public class IndexInformationImpl implements IndexInformation { private final Identifier indexIdentifier; private final List columnList; + private boolean unique; public IndexInformationImpl(Identifier indexIdentifier, List columnList) { this.indexIdentifier = indexIdentifier; this.columnList = columnList; } + public IndexInformationImpl(Identifier indexIdentifier, List columnList, boolean unique) { + this.indexIdentifier = indexIdentifier; + this.columnList = columnList; + this.unique = unique; + } + @Override public Identifier getIndexIdentifier() { return indexIdentifier; @@ -37,6 +44,11 @@ public class IndexInformationImpl implements IndexInformation { return columnList; } + @Override + public boolean isUnique() { + return unique; + } + public static Builder builder(Identifier indexIdentifier) { return new Builder( indexIdentifier ); } @@ -44,6 +56,7 @@ public class IndexInformationImpl implements IndexInformation { public static class Builder { private final Identifier indexIdentifier; private final List columnList = new ArrayList(); + private boolean unique; public Builder(Identifier indexIdentifier) { this.indexIdentifier = indexIdentifier; @@ -54,13 +67,18 @@ public class IndexInformationImpl implements IndexInformation { return this; } + public Builder setUnique(boolean unique) { + this.unique = unique; + return this; + } + public IndexInformationImpl build() { if ( columnList.isEmpty() ) { throw new SchemaManagementException( "Attempt to resolve JDBC metadata failed to find columns for index [" + indexIdentifier.getText() + "]" ); } - return new IndexInformationImpl( indexIdentifier, Collections.unmodifiableList( columnList ) ); + return new IndexInformationImpl( indexIdentifier, Collections.unmodifiableList( columnList ), unique); } } } diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java index e98aef411..b1dbb4e9d 100644 --- a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java @@ -710,6 +710,24 @@ public class InformationExtractorJdbcDatabaseMetaDataImpl implements Information } try { + //处理唯一键 + ResultSet uniqueKeyResult = extractionContext.getJdbcDatabaseMetaData().getIndexInfo(catalogFilter, schemaFilter, tableName.getTableName().getText(), true, true); + try { + while (uniqueKeyResult.next()) { + if ( uniqueKeyResult.getShort("TYPE") == DatabaseMetaData.tableIndexStatistic ) { + continue; + } + final Identifier indexIdentifier = DatabaseIdentifier.toIdentifier(uniqueKeyResult.getString("INDEX_NAME")); + IndexInformationImpl.Builder builder = builders.get( indexIdentifier ); + if ( builder == null ) { + builder = IndexInformationImpl.builder( indexIdentifier ).setUnique(true); + builders.put( indexIdentifier, builder ); + } + } + } finally { + uniqueKeyResult.close(); + } + ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getIndexInfo( catalogFilter, schemaFilter, diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/spi/IndexInformation.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/spi/IndexInformation.java index b5caeb1cf..b9426cc96 100644 --- a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/spi/IndexInformation.java +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/extract/spi/IndexInformation.java @@ -30,4 +30,6 @@ public interface IndexInformation { * @return The columns */ public List getIndexedColumns(); + + boolean isUnique(); } diff --git a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java index 0e08a9e46..d3e452571 100644 --- a/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java +++ b/fine-hibernate/src/main/java/com/fr/third/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java @@ -359,6 +359,29 @@ public abstract class AbstractSchemaMigrator implements SchemaMigrator { if ( uniqueConstraintStrategy != UniqueConstraintSchemaUpdateStrategy.SKIP ) { final Exporter exporter = dialect.getUniqueKeyExporter(); + Set identifiers = getUniqueKeyIdentifiers(table); + if (tableInfo != null) { + for (IndexInformation indexInfo : tableInfo.getIndexes()) { + if (!indexInfo.isUnique() || indexInfo.getIndexIdentifier().equals(tableInfo.getPrimaryKey().getPrimaryKeyIdentifier())) { + continue; + } + //如果旧的唯一键已经不存在, 则删除 + if (!identifiers.contains(indexInfo.getIndexIdentifier())) { + log.warn("delete unique key not existed in entity: " + indexInfo.getIndexIdentifier().getText()); + UniqueKey old = new UniqueKey(); + old.setTable(table); + old.setName(indexInfo.getIndexIdentifier().getText()); + applySqlStrings( + true, + exporter.getSqlDropStrings(old, metadata), + formatter, + options, + targets + ); + } + } + } + final Iterator ukItr = table.getUniqueKeyIterator(); while ( ukItr.hasNext() ) { final UniqueKey uniqueKey = (UniqueKey) ukItr.next(); @@ -392,6 +415,18 @@ public abstract class AbstractSchemaMigrator implements SchemaMigrator { } } + private Set getUniqueKeyIdentifiers(Table table) { + Set identifiers = new HashSet<>(); + Iterator uniqueKeys = table.getUniqueKeyIterator(); + while (uniqueKeys.hasNext()) { + UniqueKey uniqueKey = uniqueKeys.next(); + if (StringHelper.isNotEmpty(uniqueKey.getName())) { + identifiers.add(Identifier.toIdentifier(uniqueKey.getName())); + } + } + return identifiers; + } + private UniqueConstraintSchemaUpdateStrategy determineUniqueConstraintSchemaUpdateStrategy(Metadata metadata) { final ConfigurationService cfgService = ((MetadataImplementor) metadata).getMetadataBuildingOptions() .getServiceRegistry() From a2fadb5bf3c89a92c0a1bcaaa8fb6a901ce2e0b5 Mon Sep 17 00:00:00 2001 From: Elijah Date: Tue, 13 Oct 2020 09:28:33 +0800 Subject: [PATCH 7/8] =?UTF-8?q?DEC-14578=20feat:=20hibernate=E4=BA=8C?= =?UTF-8?q?=E7=BA=A7=E7=BC=93=E5=AD=98=E5=8D=A1=E9=A1=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fr/third/net/sf/ehcache/pool/builtin-sizeof.filter | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fine-ehcache/src/main/java/com/fr/third/net/sf/ehcache/pool/builtin-sizeof.filter b/fine-ehcache/src/main/java/com/fr/third/net/sf/ehcache/pool/builtin-sizeof.filter index 5e51d45db..b3650bc46 100644 --- a/fine-ehcache/src/main/java/com/fr/third/net/sf/ehcache/pool/builtin-sizeof.filter +++ b/fine-ehcache/src/main/java/com/fr/third/net/sf/ehcache/pool/builtin-sizeof.filter @@ -22,6 +22,11 @@ com.fr.third.org.hibernate.cache.spi.QueryKey.tenantIdentifier com.fr.third.org.hibernate.engine.spi.TypedValue.type com.fr.third.org.hibernate.engine.spi.TypedValue.entityMode +# Hibernate 5.x Second Level Entity/Collection Caching +com.fr.third.org.hibernate.cache.internal.CacheKeyImplementation.type +com.fr.third.org.hibernate.cache.internal.CacheKeyImplementation.entityOrRoleName +com.fr.third.org.hibernate.cache.internal.CacheKeyImplementation.tenantId + # This TC internal field is shared amongst all clustered entries org.terracotta.cache.serialization.SerializedEntry.tcClazz com.tc.object.TCObjectSelfImpl.tcClazz From ce88ba1b9decd8adf2d52d5a38b822b44a232bf0 Mon Sep 17 00:00:00 2001 From: charile_Lu Date: Thu, 1 Apr 2021 13:37:44 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E6=97=A0jira=E4=BB=BB=E5=8A=A1=20docs:=20?= =?UTF-8?q?=E8=A1=A5=E5=85=85readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fine-bouncycastle/readme.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fine-bouncycastle/readme.md diff --git a/fine-bouncycastle/readme.md b/fine-bouncycastle/readme.md new file mode 100644 index 000000000..0a3aa3155 --- /dev/null +++ b/fine-bouncycastle/readme.md @@ -0,0 +1,2 @@ +版本:1.64
    +源码:https://www.bouncycastle.org/latest_releases.html
    \ No newline at end of file