Skip to content

Commit

Permalink
add CombinedInvoker and utility methods and constants
Browse files Browse the repository at this point in the history
 - add default constants for Mode and Invoker
 - add overrides for invoke methods without mode that use the default
   Mode constant
  • Loading branch information
robinfriedli committed Apr 16, 2022
1 parent cc87a22 commit 1182ac2
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 13 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repositories {
}
dependencies {
implementation "com.github.robinfriedli:exec:1.2.2"
implementation "com.github.robinfriedli:exec:1.3"
}
```

Expand All @@ -22,7 +22,7 @@ dependencies {
<dependency>
<groupId>com.github.robinfriedli</groupId>
<artifactId>exec</artifactId>
<version>1.2.2</version>
<version>1.3</version>
<type>pom</type>
</dependency>
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
}

group = "net.robinfriedli"
version = "1.2.2"
version = "1.3"
sourceCompatibility = "8"
targetCompatibility = "8"

Expand Down
9 changes: 8 additions & 1 deletion src/main/kotlin/net/robinfriedli/exec/BaseInvoker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import java.util.function.Function

open class BaseInvoker : Invoker {

/**
* Central invoke implementation called by all other methods. This method is responsible for applying [ModeWrapper]s
* to the task so be sure to call this implementation when implementing a custom [Invoker].
*/
@Throws(Exception::class)
override fun <T> invoke(mode: Mode, task: Callable<T>): T {
val modeWrapper = mode.getWrapper()
Expand Down Expand Up @@ -46,4 +50,7 @@ open class BaseInvoker : Invoker {
})
}

}
override fun combine(invoker: Invoker): Invoker {
return CombinedInvoker(this, invoker)
}
}
10 changes: 10 additions & 0 deletions src/main/kotlin/net/robinfriedli/exec/CombinedInvoker.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package net.robinfriedli.exec

import java.util.concurrent.Callable

class CombinedInvoker(private val outer: Invoker, private val inner: Invoker) : BaseInvoker() {
@Throws(Exception::class)
override fun <T> invoke(mode: Mode, task: Callable<T>): T {
return outer.invoke(Callable { inner.invoke(mode, task) })
}
}
38 changes: 36 additions & 2 deletions src/main/kotlin/net/robinfriedli/exec/Invoker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@ import java.util.function.Function
interface Invoker {

companion object {
@JvmStatic
val defaultInstance = BaseInvoker()

@JvmStatic
fun newInstance(): Invoker {
return BaseInvoker()
}
}

/**
* Runs the given callable with the given mode applied
* Runs the given callable with the given mode applied.
*
* The supplied mode is used to decorate the task by wrapping the task in the mode's [ModeWrapper].
*
* @param mode the custom mode that defines the task execution
* @param task the callable to run
Expand All @@ -23,12 +28,20 @@ interface Invoker {
@Throws(Exception::class)
fun <T> invoke(mode: Mode, task: Callable<T>): T

fun <T> invoke(task: Callable<T>): T {
return invoke(Mode.empty, task)
}

/**
* Same as [Invoker.invoke] but accepts a Runnable and does not throw a checked exception as Runnables
* cannot throw checked exceptions
*/
fun invoke(mode: Mode, runnable: Runnable)

fun invoke(runnable: Runnable) {
invoke(Mode.empty, runnable)
}

/**
* Runs the task with the given mode applied and handles checked exceptions by wrapping them into runtime exceptions
* using the given function.
Expand All @@ -41,10 +54,31 @@ interface Invoker {
exceptionMapper: Function<Exception, RuntimeException>
): T

fun <T> invoke(
task: Callable<T>,
exceptionMapper: Function<Exception, RuntimeException>
): T {
return invoke(
Mode.empty,
task,
exceptionMapper
)
}

/**
* Runs the task wrapping checked exceptions into [RuntimeException]. This is equivalent to calling
* `invoke(mode, task, e -> new RuntimeException(e))`
*/
fun <T> invokeChecked(mode: Mode, task: Callable<T>): T

}
fun <T> invokeChecked(task: Callable<T>): T {
return invokeChecked(Mode.empty, task)
}

/**
* Creates a [CombinedInvoker] that combines Invokers by calling the supplied Invoker within this Invoker. Modes are
* passed to the innermost invoke call
*/
fun combine(invoker: Invoker): Invoker

}
3 changes: 3 additions & 0 deletions src/main/kotlin/net/robinfriedli/exec/Mode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ class Mode {
private var currentWrapper: ModeWrapper? = null

companion object {
@JvmStatic
val empty = create()

@JvmStatic
fun create(): Mode {
return Mode()
Expand Down
10 changes: 5 additions & 5 deletions src/test/java/net/robinfriedli/exec/JavaTest.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package net.robinfriedli.exec;

import java.util.concurrent.Callable;
import org.testng.annotations.Test;

import org.testng.annotations.*;
import java.util.concurrent.Callable;

import static org.testng.Assert.*;
import static org.testng.Assert.assertEquals;

public class JavaTest {

@Test
public void testSimpleInvocation() {
Invoker invoker = new BaseInvoker();
Mode mode = Mode.create();
Invoker invoker = Invoker.getDefaultInstance();
Mode mode = Mode.getEmpty();

MutableInteger i = new MutableInteger(1);
invoker.invoke(mode, () -> i.add(1));
Expand Down
47 changes: 45 additions & 2 deletions src/test/kotlin/net/robinfriedli/exec/InvokerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class InvokerTest {
@Test
fun testSimpleInvocation() {
val invoker = BaseInvoker()
val mode = Mode.create()
val mode = Mode.empty

var i = 1
invoker.invoke(mode) {
Expand All @@ -25,7 +25,7 @@ class InvokerTest {
fun testApplyCustomModes() {
var i = 1

val invoker = BaseInvoker()
val invoker = Invoker.defaultInstance
val mode = Mode.create()
.with(object : AbstractNestedModeWrapper() {
override fun <T> wrap(callable: Callable<T>): Callable<T> {
Expand Down Expand Up @@ -77,4 +77,47 @@ class InvokerTest {
assertEquals(i, 11)
}

@Test
fun testCombinedInvoker() {
val mode = create()
.with(object : AbstractNestedModeWrapper() {
override fun <T> wrap(callable: Callable<T>): Callable<T> {
return Callable {
(callable.call() as Int + 7) as T
}
}
})

val invoker = newInstance()
.combine(MultiplyingInvoker(2))
.combine(AddingInvoker(1))
.combine(MultiplyingInvoker(3))
.combine(AddingInvoker(2))
.combine(MultiplyingInvoker(2))

val i = invoker.invoke<Int>(mode) { 3 }

// 3
// + 7 (ModeWrapper is applied to the task directly, thus the innermost operation) = 10
// then the invokers in reverse order because each invoker calls the super invoker first
// * 2 = 20
// + 2 = 22
// * 3 = 66
// + 1 = 67
// * 2 = 134
assertEquals(i, 134)
}

class MultiplyingInvoker(private val factor: Int) : BaseInvoker() {
override fun <T> invoke(mode: Mode, task: Callable<T>): T {
return (super.invoke(mode, task) as Int * factor) as T
}
}

class AddingInvoker(private val summand: Int) : BaseInvoker() {
override fun <T> invoke(mode: Mode, task: Callable<T>): T {
return (super.invoke(mode, task) as Int + summand) as T
}
}

}

0 comments on commit 1182ac2

Please sign in to comment.