Task execution library derived from JXP's execution framework.
This library provides task execution and synchronisation applying certain reusable task execution modes. For example, one could create a mode that manages a transaction when executing a task.
repositories {
maven { url "https://jitpack.io" }
}
dependencies {
implementation "com.github.robinfriedli:exec:1.4"
}
<dependency>
<groupId>com.github.robinfriedli</groupId>
<artifactId>exec</artifactId>
<version>1.4</version>
<type>pom</type>
</dependency>
<repository>
<name>jitpack.io</name>
<url>https://jitpack.io</url>
</repository>
Also, make sure you are using the Kotlin JVM plugin and Kotlin is set up. Refer to the guide for Gradle and Maven.
Java example:
public void testInvokeCallable() throws Exception {
Invoker invoker = Invoker.newInstance();
Mode mode = Mode.create()
.with(new AbstractNestedModeWrapper() {
@SuppressWarnings("unchecked")
@Override
public <T> Callable<T> wrap(Callable<T> callable) {
return () -> {
int i = (Integer) callable.call();
return (T) (Object) (i + 5);
};
}
})
.with(new AbstractNestedModeWrapper() {
@SuppressWarnings("unchecked")
@Override
public <T> Callable<T> wrap(Callable<T> callable) {
return () -> {
int i = (Integer) callable.call();
return (T) (Object) (i * 2);
};
}
});
int i = invoker.invoke(mode, () -> 3);
assertEquals(i, 11);
}
Equivalent Kotlin example
fun testInvokeCallable() {
val invoker = newInstance()
val mode = create()
.with(object : AbstractNestedModeWrapper() {
override fun <T> wrap(callable: Callable<T>): Callable<T> {
return Callable {
val i = callable.call() as Int
(i + 5) as T
}
}
})
.with(object : AbstractNestedModeWrapper() {
override fun <T> wrap(callable: Callable<T>): Callable<T> {
return Callable {
val i = callable.call() as Int
(i * 2) as T
}
}
})
val i = invoker.invoke<Int>(mode) { 3 }
assertEquals(i, 11)
}
Or check out JXP for examples in production. E.g.:
From AbstractContext:
@Override
public <E> E invoke(boolean commit, boolean instantApply, Callable<E> task) {
Mode mode = Mode.create()
.with(new MutexSyncMode<>(getMutexKey(), GLOBAL_CONTEXT_SYNC))
.with(getTransactionMode(instantApply, false).shouldCommit(commit));
return invoke(mode, task);
}
@Override
public <E> E invoke(Mode mode, Callable<E> task) {
Invoker invoker = Invoker.newInstance();
return invoker.invoke(mode, task, e -> new PersistException("Exception in task", e));
}
From AbstractTransactionalMode:
@NotNull
@Override
public <E> Callable<E> wrap(@NotNull Callable<E> callable) {
return () -> {
activeTransaction = context.getTransaction();
newTransaction = getTransaction();
oldTransaction = null;
if (activeTransaction != null) {
switchTx();
} else {
openTx();
}
E returnValue;
try {
returnValue = callable.call();
activeTransaction.internal().apply();
if (!activeTransaction.isApplyOnly()) {
if (shouldCommit) {
activeTransaction.internal().commit(writeToFile);
} else {
context.getUncommittedTransactions().add(activeTransaction);
}
}
} catch (Exception e) {
try {
activeTransaction.internal().assertRollback();
} catch (Exception e1) {
Logger logger = context.getBackend().getLogger();
logger.error("Exception while rolling back changes", e1);
}
throw new PersistException(e.getClass().getSimpleName() + " thrown while running task. Closing transaction.", e);
} finally {
List<QueuedTask<?>> queuedTasks = activeTransaction.getQueuedTasks();
boolean failed = activeTransaction.failed();
closeTx();
queuedTasks.forEach(t -> {
if (failed && t.isCancelOnFailure()) {
t.cancel(false);
} else {
t.runLoggingErrors();
}
});
}
return returnValue;
};
}
This is an example of how Modes can be used to manage a Transaction when executing a task.