| Package | Description |
|---|---|
| com.github.dm.jrt.annotation |
Annotation definitions.
|
| com.github.dm.jrt.builder |
Classes and interfaces related to routine builders.
|
| com.github.dm.jrt.channel |
Classes and interfaces related to routine channels.
|
| com.github.dm.jrt.core |
Core classes and interfaces related to routine building and invocation.
|
| com.github.dm.jrt.function |
Functional interfaces and utility classes.
|
| com.github.dm.jrt.invocation |
Classes and interfaces related to routine invocations.
|
| com.github.dm.jrt.log |
Log related classes and definitions.
|
| com.github.dm.jrt.routine |
Routine interfaces and implementations.
|
| com.github.dm.jrt.runner |
Classes and interfaces related to routine runners.
|
| com.github.dm.jrt.util |
Utility classes definitions.
|
The code below shows how it is possible to implement the computation of the root mean square of some input data, by distributing it in a number of background threads.
Example 1: via invocation implementations.
This is actually the most efficient way, since there is full control on how data are passed to the specific invocations.
In fact, the parsing, the square and the mean computation all happen in parallel background threads.
public class Main {
public static void main(final String[] args) {
final Routine<String, Integer> parseRoutine =
JRoutine.on(factoryOf(Parse.class)).buildRoutine();
final Routine<Integer, Integer> squareRoutine =
JRoutine.on(factoryOf(Square.class)).buildRoutine();
final Routine<Integer, Double> meanRoutine =
JRoutine.on(factoryOf(SquareRootMean.class)).buildRoutine();
final Double rms =
meanRoutine.asyncCall(squareRoutine.parallelCall(parseRoutine.parallelCall(args)))
.afterMax(seconds(3))
.next();
System.out.println(rms);
System.exit(0);
}
private static class Parse extends TemplateInvocation<String, Integer> {
@Override
public void onInput(final String s, @NotNull final ResultChannel<Integer> result) {
result.pass(Integer.parseInt(s));
}
}
private static class Square extends TemplateInvocation<Integer, Integer> {
@Override
public void onInput(final Integer integer, @NotNull final ResultChannel<Integer> result) {
final int input = integer;
result.pass(input * input);
}
}
private static class SquareRootMean extends TemplateInvocation<Integer, Double> {
private int mCount;
private int mSum;
@Override
public void onInitialize() {
mCount = 0;
mSum = 0;
}
@Override
public void onInput(final Integer integer, @NotNull final ResultChannel<Double> result) {
++mCount;
mSum += integer;
}
@Override
public void onResult(@NotNull final ResultChannel<Double> result) {
if (mCount > 0) {
result.pass(Math.sqrt((double) mSum / mCount));
} else {
result.pass(0d);
}
}
}
}
Example 2: via invocation implementations (again).
It is possible to completely avoid the use of reflection by slightly modifying the example above.
public class Main {
public static void main(final String[] args) {
final Routine<String, Integer> parseRoutine = JRoutine.on(new Parse()).buildRoutine();
final Routine<Integer, Integer> squareRoutine = JRoutine.on(new Square()).buildRoutine();
final Routine<Integer, Double> meanRoutine =
JRoutine.on(new SquareRootMeanFactory()).buildRoutine();
final Double rms =
meanRoutine.asyncCall(squareRoutine.parallelCall(parseRoutine.parallelCall(args)))
.afterMax(seconds(3))
.next();
System.out.println(rms);
System.exit(0);
}
private static class Parse extends FilterInvocation<String, Integer> {
public void onInput(final String s, @NotNull final ResultChannel<Integer> result) {
result.pass(Integer.parseInt(s));
}
}
private static class Square extends FilterInvocation<Integer, Integer> {
public void onInput(final Integer integer, @NotNull final ResultChannel<Integer> result) {
final int input = integer;
result.pass(input * input);
}
}
private static class SquareRootMean extends TemplateInvocation<Integer, Double> {
private int mCount;
private int mSum;
@Override
public void onInitialize() {
mCount = 0;
mSum = 0;
}
@Override
public void onInput(final Integer integer, @NotNull final ResultChannel<Double> result) {
++mCount;
mSum += integer;
}
@Override
public void onResult(@NotNull final ResultChannel<Double> result) {
if (mCount > 0) {
result.pass(Math.sqrt((double) mSum / mCount));
} else {
result.pass(0d);
}
}
}
private static class SquareRootMeanFactory extends InvocationFactory<Integer, Double> {
@NotNull
public Invocation<Integer, Double> newInvocation() {
return new SquareRootMean();
}
}
}
Example 3: via reflection.
This approach allows the asynchronous invocation of an object methods by creating routines which wrap the methods to call.
In this case, the mean computation must actually wait for all the input data to be available before being invoked. Thus, it cannot really happen in a parallel way like in the previous example.
public class Main {
private static final String MEAN = "mean";
private static final String PARSE = "parse";
private static final String SQUARE = "square";
public static void main(final String[] args) {
final ClassRoutineBuilder builder = JRoutine.on(classOfType(Main.class)).proxies()
.withSharedFields()
.set()
.invocations()
.withReadTimeout(seconds(3))
.set();
final Routine<String, Integer> parseRoutine = builder.aliasMethod(PARSE);
final Routine<Integer, Integer> squareRoutine = builder.aliasMethod(SQUARE);
final Routine<List<Integer>, Double> meanRoutine = builder.aliasMethod(MEAN);
final Double rms = meanRoutine.asyncCall(
squareRoutine.parallelCall(parseRoutine.parallelCall(args)).all()).next();
System.out.println(rms);
System.exit(0);
}
@Alias(PARSE)
private static int parseArg(final String arg) {
return Integer.parseInt(arg);
}
@Alias(SQUARE)
private static int square(final int value) {
return value * value;
}
@Alias(MEAN)
private static double squareRootMean(final List<Integer> values) {
if (values.isEmpty()) {
return 0d;
}
int sum = 0;
for (final int value : values) {
sum += value;
}
return Math.sqrt((double) sum / values.size());
}
}
Example 4: via proxy.
Using a proxy object is just a convenient way to wrap several methods at once.
Note that the same annotations of the previous example could have been used to bind the methods with the proxy interface.
public class Main {
public static void main(final String[] args) {
final Main main = new Main();
final AsyncMain proxy = JRoutine.on(instance(main))
.proxies()
.withSharedFields()
.set()
.invocations()
.withReadTimeout(seconds(3))
.set()
.buildProxy(AsyncMain.class);
final double rms = proxy.squareRootMean(proxy.square(proxy.parseArg(args)));
System.out.println(rms);
System.exit(0);
}
private int parseArg(final String arg) {
return Integer.parseInt(arg);
}
private int square(final int value) {
return value * value;
}
private double squareRootMean(final List<Integer> values) {
if (values.isEmpty()) {
return 0d;
}
int sum = 0;
for (final int value : values) {
sum += value;
}
return Math.sqrt((double) sum / values.size());
}
private interface AsyncMain {
@Invoke(InvocationMode.PARALLEL)
@Output
OutputChannel<Integer> parseArg(
@Input(value = String.class, mode = InputMode.ELEMENT) String[] args);
@Invoke(InvocationMode.PARALLEL)
@Output
OutputChannel<Integer> square(
@Input(value = int.class, mode = InputMode.ELEMENT) OutputChannel<Integer> value);
double squareRootMean(
@Input(value = List.class, mode = InputMode.COLLECTION) OutputChannel<Integer> values);
}
}
Example 5: via functional routine.
The library provides an additional functional notation to build routines.
Note that the passed instances are expected to behave like functions (that is, no variable state and no side effects), for this reason they are required to have a static context.
The lambda notation used in the example is just for demonstration purpose. In order to compile with Java 7 or below, explicit object creation must be employed.
In fact, the interfaces defined in the "function" package are conceptually functional interfaces.
public class Main {
public static void main(final String[] args) {
final FunctionalRoutine<String, Double> meanRoutine =
JFunctional.routine()
.thenParallelMap((Function) (s) -> {
return Integer.parseInt(s);
})
.thenParallelMap((Function) (integer) -> {
return integer * integer;
})
.thenSyncMap((Function) (integer) -> {
return new SumData(integer, 1);
})
.thenAsyncAccumulate((BiFunction) (data1, data2) -> {
return new SumData(data1.sum + data2.sum,
data1.count + data2.count);
})
.thenSyncMap((Function) (sumData) -> {
return Math.sqrt((double) sumData.sum / sumData.count);
});
final Double rms = meanRoutine.asyncCall(args).afterMax(seconds(1)).next();
System.out.println(rms);
System.exit(0);
}
private static class SumData {
private final int count;
private final int sum;
private SumData(final int sum, final int count) {
this.sum = sum;
this.count = count;
}
}
}