com.gh.bmd.jrt.core.JRoutine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jroutine Show documentation
Show all versions of jroutine Show documentation
Parallel programming on the go
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.gh.bmd.jrt.core;
import com.gh.bmd.jrt.builder.ClassRoutineBuilder;
import com.gh.bmd.jrt.builder.ObjectRoutineBuilder;
import com.gh.bmd.jrt.builder.RoutineBuilder;
import com.gh.bmd.jrt.builder.StandaloneChannelBuilder;
import com.gh.bmd.jrt.common.ClassToken;
import com.gh.bmd.jrt.invocation.Invocation;
import com.gh.bmd.jrt.invocation.InvocationFactory;
import com.gh.bmd.jrt.invocation.Invocations;
import javax.annotation.Nonnull;
/**
* This utility class represents the entry point to the framework functionalities by acting as a
* factory of routine builders.
*
* There are mainly two ways to create a routine object:
*
* Routine by invocation customization
* The first approach consists in implementing an invocation object.
*
* Routine by method invocation
* The second approach is based on the asynchronous invocation of a method of an existing class or
* object via reflection.
* It is possible to annotate selected methods to be asynchronously invoked, or to simply select
* a method through its signature. It is also possible to build a proxy object whose methods will
* in turn asynchronously invoke the target object ones.
* Note that a proxy object can be simply defined as an interface implemented by the target, but
* also as a completely unrelated one mirroring the target methods. In this way it is possible to
* apply the framework functionalities to objects defined by third party libraries which are not
* under direct control.
* A mirror interface adds the possibility to override input and output parameters with output
* channels, so that data are transferred asynchronously, avoiding the need to block execution while
* waiting for them to be available.
* Finally, it also possible to create a wrapper class to enable asynchronous invocation of methods,
* through annotation pre-processing and compile-time code generation. In order to activate the
* processing of annotations, it is simply necessary to include the "jroutine-processor" artifact
* or module in the project dependencies.
*
* This class provides also a way to build standalone channel instances, which can be used to pass
* data without the need to start a routine invocation.
*
* Some usage examples
*
* Example 1: Asynchronously merge the output of two routines.
*
*
*
* final StandaloneChannel<Result> channel = JRoutine.standalone().buildChannel();
*
* channel.input()
* .pass(doSomething1.callAsync())
* .pass(doSomething2.callAsync())
* .close();
* channel.output()
* .eventually()
* .readAllInto(results);
*
*
* Or simply:
*
*
*
* final OutputChannel<Result> output1 = doSomething1.callAsync();
* final OutputChannel<Result> output2 = doSomething2.callAsync();
*
* output1.eventually().readAllInto(results);
* output2.eventually().readAllInto(results);
*
*
* (Note that, the order of the input or the output of the routine is not guaranteed unless the
* proper builder methods are called)
*
* Example 2: Asynchronously concatenate the output of two routines.
*
*
*
* doSomething1.callAsync(doSomething2.callAsync())).eventually().readAllInto(results);
*
*
*
* Example 3: Asynchronously get the output of two routines.
*
*
*
* public interface AsyncCallback {
*
* public void onResults(
* @Pass(Result.class) OutputChannel<Result> result1,
* @Pass(Result.class) OutputChannel<Result> result2);
* }
*
* final AsyncCallback callback = JRoutine.on(myCallback)
* .buildProxy(AsyncCallback.class);
*
* callback.onResults(doSomething1.callAsync(), doSomething2.callAsync());
*
*
* Where the object myCallback
implements a method
* public void onResults(Result result1, Result result2)
.
*
* Example 4: Asynchronously feed a routine from a different thread.
*
*
*
* final StandaloneChannel<Result> channel = JRoutine.standalone().buildChannel();
*
* new Thread() {
*
* @Override
* public void run() {
*
* channel.input().pass(new Result()).close();
* }
*
* }.start();
*
* final Routine<Result, Result> routine =
* JRoutine.<Result>on(PassingInvocation.<Result>factoryOf())
* .buildRoutine();
*
* routine.callAsync(channel.output()).eventually().readAllInto(results);
*
*
*
* Created by davide on 9/7/14.
*
* @see com.gh.bmd.jrt.annotation.Bind
* @see com.gh.bmd.jrt.annotation.Pass
* @see com.gh.bmd.jrt.annotation.ShareGroup
* @see com.gh.bmd.jrt.annotation.Timeout
* @see com.gh.bmd.jrt.annotation.TimeoutAction
*/
public class JRoutine {
/**
* Avoid direct instantiation.
*/
protected JRoutine() {
}
/**
* Returns a routine builder wrapping the specified target class.
*
* @param target the target class.
* @return the routine builder instance.
* @throws java.lang.IllegalArgumentException if a duplicate name in the annotations is
* detected.
*/
@Nonnull
public static ClassRoutineBuilder on(@Nonnull final Class> target) {
return new DefaultClassRoutineBuilder(target);
}
/**
* Returns a routine builder based on the specified invocation factory.
*
* The invocation instance is created only when needed, by passing the specified arguments to
* the constructor. Note that the arguments objects should be immutable or, at least, never
* shared inside and outside the routine in order to avoid concurrency issues.
*
* @param factory the invocation factory.
* @param the input data type.
* @param