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

com.github.dm.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.github.dm.jrt.core;

import com.github.dm.jrt.builder.IOChannelBuilder;
import com.github.dm.jrt.builder.ObjectRoutineBuilder;
import com.github.dm.jrt.builder.RoutineBuilder;
import com.github.dm.jrt.invocation.InvocationFactory;

import org.jetbrains.annotations.NotNull;

/**
 * This utility class represents the entry point to the library 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. Invocations mimic the scope of * a function call. Objects are instantiated when needed and recycled for successive invocations. *

* 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 library functionality 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 proxy artifact or module in the * project dependencies. *

* This class provides also a way to build I/O 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 IOChannel<Result, Result> channel = JRoutine.io().buildChannel();
 *         channel.pass(doSomething1.asyncCall())
 *                .pass(doSomething2.asyncCall())
 *                .close();
 *                .afterMax(seconds(20))
 *                .allInto(results);
 *     
 * 
* Or simply: *
 *     
 *
 *         final OutputChannel<Result> output1 = doSomething1.asyncCall();
 *         final OutputChannel<Result> output2 = doSomething2.asyncCall();
 *         output1.afterMax(seconds(20)).allInto(results);
 *         output2.afterMax(seconds(20)).allInto(results);
 *     
 * 
* (Note that, the order of the input or the output of the routine is not guaranteed unless properly * configured) *

* Example 2: Asynchronously concatenate the output of two routines. *

 *     
 *
 *         doSomething2.asyncCall(doSomething1.asyncCall())).afterMax(seconds(20)).allInto(results);
 *     
 * 
*

* Example 3: Asynchronously get the output of two routines. *

 *     
 *
 *         public interface AsyncCallback {
 *
 *             public void onResults(
 *                  @Input(Result.class) OutputChannel<Result> result1,
 *                  @Input(Result.class) OutputChannel<Result> result2);
 *         }
 *
 *         final AsyncCallback callback = JRoutine.on(instance(myCallback))
 *                                                .buildProxy(AsyncCallback.class);
 *         callback.onResults(doSomething1.asyncCall(), doSomething2.asyncCall());
 *     
 * 
* 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 IOChannel<Result, Result> channel = JRoutine.io().buildChannel();
 *
 *         new Thread() {
 *
 *             @Override
 *             public void run() {
 *
 *                 channel.pass(new Result()).close();
 *             }
 *
 *         }.start();
 *
 *         final Routine<Result, Result> routine =
 *                  JRoutine.<Result>on(PassingInvocation.<Result>factoryOf())
 *                          .buildRoutine();
 *         routine.asyncCall(channel).afterMax(seconds(20)).allInto(results);
 *     
 * 
*

* Created by davide-maestroni on 09/07/2014. * * @see Annotations */ public class JRoutine { /** * Avoid direct instantiation. */ protected JRoutine() { } /** * Returns an I/O channel builder. * * @return the channel builder instance. */ @NotNull public static IOChannelBuilder io() { return new DefaultIOChannelBuilder(); } /** * Returns a routine builder wrapping 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.
* Note also that the invocation input data will be cached, and the results will be produced * only after the invocation channel is closed, so be sure to avoid streaming inputs in * order to prevent starvation or out of memory errors. * * @param target the invocation target. * @return the routine builder instance. * @throws java.lang.IllegalArgumentException if the specified object class represents an * interface. */ @NotNull public static ObjectRoutineBuilder on(@NotNull final InvocationTarget target) { return new DefaultObjectRoutineBuilder(target); } /** * Returns a routine builder based on the specified invocation factory.
* In order to prevent undesired leaks, the class of the specified factory must have a * static context. * * @param factory the invocation factory. * @param the input data type. * @param the output data type. * @return the routine builder instance. * @throws java.lang.IllegalArgumentException if the class of the specified factory is not * static. */ @NotNull public static RoutineBuilder on( @NotNull final InvocationFactory factory) { return new DefaultRoutineBuilder(factory); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy