All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gh.bmd.jrt.core.JRoutine Maven / Gradle / Ivy

There is a newer version: 5.9.0
Show newest version
/*
 * 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 the output data type. * @return the routine builder instance. */ @Nonnull public static RoutineBuilder on( @Nonnull final InvocationFactory factory) { return new DefaultRoutineBuilder(factory); } /** * Returns a routine builder based on the specified invocation class token. *

* The invocation instance is created through reflection only when needed. * * @param token the invocation class token. * @param the input data type. * @param the output data type. * @return the routine builder instance. */ @Nonnull public static RoutineBuilder on( @Nonnull final ClassToken> token) { return on(Invocations.factoryOf(token)); } /** * Returns a routine builder wrapping a weak reference to the specified target object.
* Note that it is responsibility of the caller to retain a strong reference to the target * instance to prevent it from being garbage collected. * * @param target the target object. * @return the routine builder instance. * @throws java.lang.IllegalArgumentException if a duplicate name in the annotations is * detected. */ @Nonnull public static ObjectRoutineBuilder on(@Nonnull final Object target) { return new DefaultObjectRoutineBuilder(target); } /** * Returns a standalone channel builder. * * @return the standalone channel builder instance. */ @Nonnull public static StandaloneChannelBuilder standalone() { return new DefaultStandaloneChannelBuilder(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy