Skip to content

Commit

Permalink
refactor: delegate resetDefaultExecutor() to CffuFactoryBuilder, …
Browse files Browse the repository at this point in the history
…and avoiding re-wrapping
  • Loading branch information
oldratlee committed Aug 3, 2024
1 parent 0a5d113 commit 71cc51c
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 20 deletions.
6 changes: 3 additions & 3 deletions cffu-core/src/main/java/io/foldright/cffu/CffuFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ public final class CffuFactory {
*/
@Contract(pure = true)
public static CffuFactoryBuilder builder(Executor defaultExecutor) {
return new CffuFactoryBuilder(CompletableFutureUtils.screenExecutor(defaultExecutor));
return new CffuFactoryBuilder(defaultExecutor);
}

/**
* Returns a new CffuFactory from this CffuFactory that reset the defaultExecutor.
*/
@Contract(pure = true)
CffuFactory resetDefaultExecutor(Executor defaultExecutor) {
return new CffuFactory(defaultExecutor, forbidObtrudeMethods);
public CffuFactory resetDefaultExecutor(Executor defaultExecutor) {
return CffuFactoryBuilder.resetDefaultExecutor(this, defaultExecutor);
}

@Contract(pure = true)
Expand Down
46 changes: 44 additions & 2 deletions cffu-core/src/main/java/io/foldright/cffu/CffuFactoryBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.foldright.cffu.spi.ExecutorWrapperProvider;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.VisibleForTesting;

import javax.annotation.concurrent.ThreadSafe;
import java.util.List;
Expand All @@ -28,7 +29,43 @@ public final class CffuFactoryBuilder {
private volatile boolean forbidObtrudeMethods = false;

CffuFactoryBuilder(Executor defaultExecutor) {
this.defaultExecutor = wrapExecutor(defaultExecutor);
this.defaultExecutor = makeExecutor(defaultExecutor);
}

private static Executor makeExecutor(Executor executor) {
// check CffuMadeExecutor interface to avoid re-wrapping.
if (executor instanceof CffuMadeExecutor) return executor;

Executor wrapByProviders = wrapExecutorByProviders(CompletableFutureUtils.screenExecutor(executor));
return CffuMadeExecutor.wrapMadeInterface(wrapByProviders);
}

/**
* An interface for avoiding re-wrapping.
*/
@VisibleForTesting
interface CffuMadeExecutor extends Executor {
static CffuMadeExecutor wrapMadeInterface(Executor executor) {
return new CffuMadeExecutor() {
@Override
public Executor unwrap() {
return executor;
}

@Override
public void execute(Runnable command) {
executor.execute(command);
}

@Override
public String toString() {
return "CffuMadeExecutor of executor(" + executor + ")";
}
};
}

@VisibleForTesting
Executor unwrap();
}

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -57,7 +94,12 @@ public CffuFactory build() {
return new CffuFactory(defaultExecutor, forbidObtrudeMethods);
}

private static Executor wrapExecutor(Executor executor) {
@Contract(pure = true)
static CffuFactory resetDefaultExecutor(CffuFactory fac, Executor defaultExecutor) {
return new CffuFactory(makeExecutor(defaultExecutor), fac.forbidObtrudeMethods());
}

private static Executor wrapExecutorByProviders(Executor executor) {
for (ExecutorWrapperProvider provider : EXECUTOR_WRAPPER_PROVIDERS) {
Supplier<String> msg = () -> provider + "(class: " + provider.getClass().getName() + ") return null";
executor = requireNonNull(provider.wrap(executor), msg);
Expand Down
21 changes: 15 additions & 6 deletions cffu-core/src/test/java/io/foldright/cffu/CffuFactoryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import static io.foldright.cffu.CompletableFutureUtils.failedFuture;
import static io.foldright.cffu.CompletableFutureUtils.toCompletableFutureArray;
import static io.foldright.cffu.DefaultExecutorTestUtils.unwrapMadeExecutor;
import static io.foldright.test_utils.TestUtils.*;
import static java.util.concurrent.CompletableFuture.completedFuture;
import static java.util.concurrent.ForkJoinPool.commonPool;
Expand Down Expand Up @@ -811,7 +812,7 @@ void test_toCffu() throws Exception {
CffuFactory fac = CffuFactory.builder(anotherExecutorService).forbidObtrudeMethods(true).build();
Cffu<Integer> cffu = fac.toCffu(cffu_in);
assertNotSame(cffu_in, cffu);
assertSame(anotherExecutorService, cffu.defaultExecutor());
assertSame(anotherExecutorService, unwrapMadeExecutor(cffu));
assertSame(fac, cffu.cffuFactory());
assertEquals("obtrude methods is forbidden by cffu", assertThrowsExactly(UnsupportedOperationException.class, () ->
cffu.obtrudeValue(44)
Expand Down Expand Up @@ -913,16 +914,23 @@ void test_cffuListToArray() {

@Test
void test_getter() {
assertSame(executorService, cffuFactory.defaultExecutor());
assertEquals("CffuMadeExecutor of executor(" + executorService + ")",
cffuFactory.defaultExecutor().toString());

assertSame(executorService, unwrapMadeExecutor(cffuFactory));
assertFalse(cffuFactory.forbidObtrudeMethods());

CffuFactory fac = CffuFactory.builder(anotherExecutorService).forbidObtrudeMethods(true).build();
assertSame(anotherExecutorService, fac.defaultExecutor());
assertSame(anotherExecutorService, unwrapMadeExecutor(fac));
assertTrue(fac.forbidObtrudeMethods());

final CffuFactory fac2 = cffuFactory.resetDefaultExecutor(anotherExecutorService);
assertSame(anotherExecutorService, fac2.defaultExecutor());
assertSame(anotherExecutorService, unwrapMadeExecutor(fac2));
assertEquals(cffuFactory.forbidObtrudeMethods(), fac2.forbidObtrudeMethods());

final CffuFactory fac3 = cffuFactory.resetDefaultExecutor(fac2.defaultExecutor());
assertSame(fac2.defaultExecutor(), fac3.defaultExecutor());
assertEquals(fac2.forbidObtrudeMethods(), fac3.forbidObtrudeMethods());
}

@Test
Expand All @@ -945,15 +953,16 @@ void test_executorSetting_MayBe_ThreadPerTaskExecutor() throws Exception {

CffuFactory fac = CffuFactory.builder(commonPool()).build();
if (USE_COMMON_POOL) {
assertSame(commonPool(), fac.defaultExecutor());
assertSame(commonPool(), unwrapMadeExecutor(fac));
} else {
String executorClassName = fac.defaultExecutor().getClass().getName();
String executorClassName = unwrapMadeExecutor(fac).getClass().getName();
assertTrue(executorClassName.endsWith("$ThreadPerTaskExecutor"));
}

assertEquals(42, fac.supplyAsync(() -> 42).get());
}


// endregion
////////////////////////////////////////////////////////////////////////////////
// region# Test helper methods/fields
Expand Down
3 changes: 2 additions & 1 deletion cffu-core/src/test/java/io/foldright/cffu/CffuTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.function.Consumer;
import java.util.function.Function;

import static io.foldright.cffu.DefaultExecutorTestUtils.unwrapMadeExecutor;
import static io.foldright.test_utils.TestUtils.*;
import static java.util.concurrent.CompletableFuture.completedFuture;
import static java.util.function.Function.identity;
Expand Down Expand Up @@ -486,7 +487,7 @@ void test_resetCffuFactory() {

Executor executor = Runnable::run;
final Cffu<Integer> f2 = cf.resetDefaultExecutor(executor);
assertSame(executor, f2.defaultExecutor());
assertSame(executor, unwrapMadeExecutor(f2));
assertEquals(cffuFactory.forbidObtrudeMethods(), f2.cffuFactory().forbidObtrudeMethods());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.foldright.cffu;

import java.util.concurrent.Executor;


public class DefaultExecutorTestUtils {
public static Executor unwrapMadeExecutor(CffuFactory factory) {
final CffuFactoryBuilder.CffuMadeExecutor executor = (CffuFactoryBuilder.CffuMadeExecutor) factory.defaultExecutor();
return executor.unwrap();
}

public static Executor unwrapMadeExecutor(Cffu<?> cffu) {
final CffuFactoryBuilder.CffuMadeExecutor executor = (CffuFactoryBuilder.CffuMadeExecutor) cffu.defaultExecutor();
return executor.unwrap();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.foldright.cffu.spi

import io.foldright.cffu.CffuFactory
import io.foldright.cffu.DefaultExecutorTestUtils.unwrapMadeExecutor
import io.foldright.test_utils.testThreadPoolExecutor
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.types.shouldBeSameInstanceAs
Expand All @@ -10,15 +11,15 @@ class ExecutorWrapperProviderTest : FunSpec({
test("disable TestExecutorWrapper") {
val factory = CffuFactory.builder(testThreadPoolExecutor).build()
val cffu = factory.runAsync {}
cffu.defaultExecutor().shouldBeSameInstanceAs(testThreadPoolExecutor)
unwrapMadeExecutor(cffu).shouldBeSameInstanceAs(testThreadPoolExecutor)
}

test("enable TestExecutorWrapper") {
enableTestExecutorWrapper()

val factory = CffuFactory.builder(testThreadPoolExecutor).build()
val cffu = factory.runAsync {}
cffu.defaultExecutor().shouldNotBeSameInstanceAs(testThreadPoolExecutor)
unwrapMadeExecutor(cffu).shouldNotBeSameInstanceAs(testThreadPoolExecutor)
}

beforeTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.foldright.cffu.test

import io.foldright.cffu.Cffu
import io.foldright.cffu.CffuFactory
import io.foldright.cffu.DefaultExecutorTestUtils
import io.foldright.cffu.NoCfsProvidedException
import io.foldright.cffu.kotlin.*
import io.foldright.test_utils.testCffuFactory
Expand All @@ -17,17 +18,15 @@ import io.kotest.matchers.types.shouldBeTypeOf
import io.kotest.matchers.types.shouldNotBeSameInstanceAs
import io.kotest.matchers.types.shouldNotBeTypeOf
import kotlinx.coroutines.future.await
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionStage
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.*

const val n = 42
const val anotherN = 4242
const val s = "43"
const val d = 44.0
val rte = RuntimeException("Bang")


class CffuExtensionsTest : FunSpec({
////////////////////////////////////////
// toCffu
Expand All @@ -36,12 +35,12 @@ class CffuExtensionsTest : FunSpec({
suspend fun checkToCffu(cffu: Cffu<Int>, n: Int) {
cffu.await() shouldBe n

cffu.defaultExecutor() shouldBeSameInstanceAs testThreadPoolExecutor
cffu.unwrapMadeExecutor() shouldBeSameInstanceAs testThreadPoolExecutor
cffu.cffuFactory() shouldBeSameInstanceAs testCffuFactory

val fac2 = CffuFactory.builder(testForkJoinPoolExecutor).build()
cffu.resetCffuFactory(fac2).let {
it.defaultExecutor() shouldBeSameInstanceAs testForkJoinPoolExecutor
it.unwrapMadeExecutor() shouldBeSameInstanceAs testForkJoinPoolExecutor
it.cffuFactory() shouldBeSameInstanceAs fac2
}
}
Expand Down Expand Up @@ -656,3 +655,9 @@ class CffuExtensionsTest : FunSpec({
}
}
})

fun CffuFactory.unwrapMadeExecutor(): Executor =
DefaultExecutorTestUtils.unwrapMadeExecutor(this)

fun Cffu<*>.unwrapMadeExecutor(): Executor =
DefaultExecutorTestUtils.unwrapMadeExecutor(this)

0 comments on commit 71cc51c

Please sign in to comment.