Skip to content

Commit

Permalink
♻️ replace ThreadLocalProxy with SPI #22
Browse files Browse the repository at this point in the history
  • Loading branch information
trydofor committed Feb 17, 2024
1 parent 1fdfa90 commit 091ce7f
Show file tree
Hide file tree
Showing 12 changed files with 241 additions and 170 deletions.
73 changes: 73 additions & 0 deletions src/main/java/pro/fessional/mirana/dync/OrderedSpi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package pro.fessional.mirana.dync;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.ServiceLoader;

/**
* order and get 1st service
*
* @author trydofor
* @since 2024-02-16
*/
public interface OrderedSpi {

@Nullable
static <S> S first(@NotNull Class<S> service) {
return first(service, (Comparator<S>) null);
}

@Nullable
static <S> S first(@NotNull Class<S> service, @NotNull ClassLoader loader) {
return first(service, loader, null);
}

@Nullable
static <S> S first(@NotNull Class<S> service, @Nullable Comparator<S> comparator) {
return first(ServiceLoader.load(service), comparator);
}

@Nullable
static <S> S first(@NotNull Class<S> service, @NotNull ClassLoader loader, @Nullable Comparator<S> comparator) {
return first(ServiceLoader.load(service, loader), comparator);
}

@Nullable
static <S> S first(@NotNull ServiceLoader<S> loader, @Nullable Comparator<S> comparator) {
S cur = null;
if (comparator == null) {
Iterator<S> it = loader.iterator();
if (it.hasNext()) {
cur = it.next();
}

if (cur instanceof Comparable) { // not null, not empty
ArrayList<S> arr = new ArrayList<>();
arr.add(cur);
while (it.hasNext()) {
arr.add(it.next());
}

arr.sort(null);
cur = arr.get(0);
}
}
else {
ArrayList<S> arr = new ArrayList<>();
for (S s : loader) {
arr.add(s);
}

if (!arr.isEmpty()) {
arr.sort(comparator);
cur = arr.get(0);
}
}

return cur;
}
}
22 changes: 22 additions & 0 deletions src/main/java/pro/fessional/mirana/evil/ThreadLocalProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package pro.fessional.mirana.evil;

import org.jetbrains.annotations.NotNull;

/**
* ThreadLocal without init value.
*
* @author trydofor
* @since 2024-02-16
*/
public interface ThreadLocalProvider extends Comparable<ThreadLocalProvider> {
default int getOrder() {
return 0;
}

@Override
default int compareTo(@NotNull ThreadLocalProvider o) {
return Integer.compare(this.getOrder(), o.getOrder());
}

@NotNull ThreadLocal<?> get();
}
108 changes: 0 additions & 108 deletions src/main/java/pro/fessional/mirana/evil/ThreadLocalProxy.java

This file was deleted.

48 changes: 25 additions & 23 deletions src/main/java/pro/fessional/mirana/evil/TweakingContext.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package pro.fessional.mirana.evil;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import pro.fessional.mirana.dync.OrderedSpi;

import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;

/**
* <pre>
* init - should init before the service and called once.
* default - should init before the service and called once.
* global - global scope, should be used at the system level.
* thread - thread scope, should use try {tweak} finally{reset} pattern.
* </pre>
Expand All @@ -20,25 +20,30 @@ public class TweakingContext<T> {

private final AtomicReference<Supplier<T>> defaultValue = new AtomicReference<>();
private final AtomicReference<Supplier<T>> globalValue = new AtomicReference<>();
private final ThreadLocalProxy<Supplier<T>> threadValue = new ThreadLocalProxy<>();
private final ThreadLocal<Supplier<T>> threadValue;

/**
* without default value
*/
@SuppressWarnings("unchecked")
public TweakingContext() {
ThreadLocalProvider spi = OrderedSpi.first(ThreadLocalProvider.class);
threadValue = spi == null ? new ThreadLocal<>() : (ThreadLocal<Supplier<T>>) spi.get();
}

/**
* init with default value
*/
public TweakingContext(T initDefault) {
this();
initDefault(initDefault);
}

/**
* init with default value
*/
public TweakingContext(Supplier<T> initDefault) {
this();
initDefault(initDefault);
}

Expand Down Expand Up @@ -73,22 +78,29 @@ public void initGlobal(Supplier<T> value) {
/**
* init thread value
*/
public void initThread(@NotNull ThreadLocal<Supplier<T>> threadLocal, boolean tryToCleanOld) throws ThreadLocalAttention {
threadValue.replaceBackend(threadLocal, tryToCleanOld);
public void initThread(T value) {
tweakThread(value);
}

/**
* init thread value
*/
public void initThread(Supplier<T> value) {
tweakThread(value);
}

/**
* tweak global value
*/
public void tweakGlobal(T stack) {
globalValue.set(() -> stack);
public void tweakGlobal(T value) {
globalValue.set(() -> value);
}

/**
* tweak global value
*/
public void tweakGlobal(Supplier<T> stack) {
globalValue.set(stack);
public void tweakGlobal(Supplier<T> value) {
globalValue.set(value);
}

/**
Expand All @@ -101,25 +113,15 @@ public void resetGlobal() {
/**
* tweak thread value. should use try {tweak} finally{reset} pattern
*/
public void tweakThread(T stack) {
if (stack == null) {
threadValue.remove();
}
else {
threadValue.set(() -> stack);
}
public void tweakThread(T value) {
threadValue.set(() -> value);
}

/**
* tweak thread value. should use try {tweak} finally{reset} pattern
*/
public void tweakThread(Supplier<T> stack) {
if (stack == null) {
threadValue.remove();
}
else {
threadValue.set(stack);
}
public void tweakThread(Supplier<T> value) {
threadValue.set(value);
}

/**
Expand Down
23 changes: 23 additions & 0 deletions src/test/java/pro/fessional/mirana/dync/OrderedSpiTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package pro.fessional.mirana.dync;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;

/**
* @author trydofor
* @since 2024-02-17
*/
class OrderedSpiTest {

@Test
void orderNull() {
ArrayList<Integer> arr = new ArrayList<>();
arr.add(2);
arr.add(1);
arr.sort(null);
Assertions.assertEquals(Arrays.asList(1,2), arr);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package pro.fessional.mirana.evil;

import org.jetbrains.annotations.NotNull;

/**
* @author trydofor
* @since 2024-02-16
*/
public class TestThreadLocalProvider1 implements ThreadLocalProvider {

@Override
public int getOrder() {
return 1;
}

@Override
public @NotNull ThreadLocal<?> get() {
return new ThreadLocal<>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package pro.fessional.mirana.evil;

import org.jetbrains.annotations.NotNull;

/**
* @author trydofor
* @since 2024-02-16
*/
public class TestThreadLocalProvider2 implements ThreadLocalProvider {
@Override
public int getOrder() {
return 2;
}

@Override
public @NotNull ThreadLocal<?> get() {
return new ThreadLocal<>();
}
}
Loading

0 comments on commit 091ce7f

Please sign in to comment.