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

org.refcodes.jobbus.JobBus Maven / Gradle / Ivy

There is a newer version: 3.3.8
Show newest version
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// =============================================================================
// This code is copyright (c) by Siegfried Steiner, Munich, Germany and licensed
// under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// =============================================================================
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// together with the GPL linking exception applied; as being applied by the GNU
// Classpath ("http://www.gnu.org/software/classpath/license.html")
// =============================================================================
// Apache License, v2.0 ("http://www.apache.org/licenses/TEXT-2.0")
// =============================================================================
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////

package org.refcodes.jobbus;

import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

import org.refcodes.command.NoExceptionAvailableRuntimeException;
import org.refcodes.command.NoResultAvailableRuntimeException;
import org.refcodes.command.NotYetExecutedRuntimeException;
import org.refcodes.command.Undoable;
import org.refcodes.component.FlushHandle;
import org.refcodes.component.HandleLookup;
import org.refcodes.component.HandleTimeoutRuntimeException;
import org.refcodes.component.ProgressHandle;
import org.refcodes.component.ResetHandle;
import org.refcodes.component.UnknownHandleRuntimeException;

/**
 * The {@link JobBus} makes use of the {@link Undoable} pattern and is used to
 * execute job ({@link Undoable}) instances by a client. The client may be the
 * business logic creating a {@link Undoable} (job) to be executed. The
 * {@link JobBus} takes a client's {@link Undoable} (job) to be executed. For
 * asynchronous execution a handle is passed back to the client with which the
 * state (in progress, failure, success) of the {@link Undoable} (job) can be
 * determined as well as the {@link Undoable}'s (job's) result be requested (the
 * actual result or an exception in case of failure). For synchronous operation,
 * the {@link JobBus} halts your invoking thread till either the result is
 * (available and) passed back or an exception is thrown. To invoke a
 * {@link Undoable} (job), the {@link JobBus}, being the invoker, passes the
 * context to the {@link Undoable} (job) and requests the {@link Undoable} (job)
 * to apply its operation with regard to the context. As you can see, the
 * {@link JobBus} is responsible for managing the context and for invoking the
 * {@link Undoable} (job). This decouples the business logic from the knowledge
 * on how to retrieve a context or where the {@link Undoable} is actually being
 * executed (more on this later). As of the implemented handle paradigm, the
 * job-bus may be used by various parties without revealing their
 * {@link Undoable} (job) instances (to each other) being processed by the
 * {@link JobBus}. DISTRIBUTED ENVIRONMENT The operation a {@link Undoable}
 * (job) represents is atomic, encapsulated in an object and applied to a
 * context. The {@link JobBus} may distribute the {@link Undoable} (job) to a
 * different {@link JobBus}, probably located on a different machine, where the
 * {@link Undoable} (job) eventually gets executed. The result of the
 * {@link Undoable} (job) execution then gets passed back to the originating
 * {@link JobBus}, which then passes it back to the client. (this scenario
 * assumes that a) your command (job) is serializable as well as b) your result
 * is serializable) DO/UNDO STACK As a {@link Undoable} (job) may also undo
 * things it has done (executed), an undo stack may hold your application's
 * {@link Undoable} (job) instances in the order of their execution. Using to
 * undo stack in reverse order, the executed operations can be undone one-by-one
 * or in batch. COMPONENT / SERVICE In a component or service driven
 * environment, the {@link JobBus} may be one of the services centrally being
 * set up and configured as well as centrally being provided to your
 * application's component (service) instances. So you have one point of
 * {@link Undoable} (job) execution; application wide; providing the benefits of
 * the {@link JobBus} in a transparent manner to your application. Possible
 * extension (idea): Implement some kind of receipt or Meta-Data which provides
 * information on the {@link Undoable} (job) instance's start and end times,
 * result, exception, progress and so on, retrieved via handle.
 * 
 * @param  The context type to use, can by any component, service or POJO.
 * @param  The handle type used to reference a job.
 */
public interface JobBus extends HandleLookup>, ProgressHandle, ResetHandle, FlushHandle {

	/**
	 * Executes the given job. By double dispatch the job's execute method is
	 * invoked. The Job is provided with a service-bus to be able to perform its
	 * task. This is an implementation of the command pattern.
	 * 
	 * @param aJob The job to be executed.
	 * 
	 * @return The handle associated with the provided job.
	 */
	public H execute( Undoable aJob );

	/**
	 * Executes the given job and invokes the provided {@link Consumer} lambda
	 * (closure) upon finished execution. The parameter is passed in case we
	 * have an ordinary result, an exceptual situation is "ignored" as the
	 * {@link Consumer} will not be invoked in such a case. In case you have to
	 * take action upon an exceptional situation, then use the
	 * {@link #execute(Undoable, BiConsumer)} method.
	 *
	 * @param  the generic type
	 * @param  the element type
	 * @param aJob The job to be executed.
	 * @param aResultConsumer The {@link Consumer} lambda to be invoked upon
	 *        finished execution.
	 */
	public  void execute( Undoable aJob, Consumer aResultConsumer );

	/**
	 * Executes the given job and invokes the provides {@link BiConsumer} lambda
	 * (closure) upon finished execution. The first parameter is passed in case
	 * we have an ordinary result, the second one is passed in case we have an
	 * exceptional situation. Either the one parameter or the other one is
	 * passed, never both of them at the same invocation! In case both arguments
	 * are null, then your job has returned null. Consider using the
	 * {@link Optional} to be returned by your job. Though consider that the
	 * {@link Optional} is NOT serializable which could cause problems with
	 * remote job execution! In case you do not have to take action upon an
	 * exceptional situation, then use the {@link #execute(Undoable, Consumer)}
	 * method.
	 *
	 * @param  the generic type
	 * @param  the element type
	 * @param aJob The job to be executed.
	 * @param aResultConsumer The {@link BiConsumer} lambda to be invoked upon
	 *        finished execution.
	 * 
	 * @see "http://www.refcodes.org/blog/obliged_to_do_the_optional_or_is_it_optional"
	 */
	public  void execute( Undoable aJob, BiConsumer aResultConsumer );

	/**
	 * Waits till the job identified by the given handle finished execution by
	 * regularly terminating or by throwing an exception. The handle my be used
	 * to determine if there was an exception or not and to retrieve the result
	 * or in case of an exception the exception object.
	 * 
	 * @param aHandle The handle associated with the provided job.
	 * 
	 * @throws UnknownHandleRuntimeException in case the handle is not unknown.
	 */
	public void waitForExecution( H aHandle ) throws UnknownHandleRuntimeException;

	/**
	 * Waits till the job identified by the given handle finished execution by
	 * regularly terminating or by throwing an exception or till the timeout has
	 * been reached. In case the timeout has been reached before execution was
	 * finished, then a {@link HandleTimeoutRuntimeException} is thrown to abort
	 * the waiting loop. This is especially useful when a remote connection is
	 * used to managed a distributed {@link JobBus} infrastructure and due to
	 * connection issues, wait time would be endless. The handle my be used to
	 * determine if there was an exception or not and to retrieve the result or
	 * in case of an exception the exception object.
	 * 
	 * @param aHandle The handle associated with the provided job.
	 * @param aTimeoutMillis The timeout to wait at most even when execution did
	 *        not finish. In case the timeout has been reached before execution
	 *        was finished, then a {@link HandleTimeoutRuntimeException} is
	 *        thrown to abort the waiting loop.
	 * 
	 * @throws UnknownHandleRuntimeException Thrown in case the handle is not
	 *         unknown.
	 * @throws HandleTimeoutRuntimeException Thrown in case the timeout was
	 *         reached before execution finished.
	 */
	public void waitForExecution( H aHandle, long aTimeoutMillis ) throws UnknownHandleRuntimeException, HandleTimeoutRuntimeException;

	/**
	 * Executes the job and waits for the job's result or an exception.
	 *
	 * @param  the generic type
	 * @param  The return type of the {@link Undoable}'s proceedings.
	 * @param aJob The job to execute
	 * 
	 * @return The result of the job execution. In case the job does not produce
	 *         a result by default ("void"), then the according exception is
	 *         thrown. Make sure the job produces a result!
	 * 
	 * @throws NoResultAvailableRuntimeException in case a job has been executed
	 *         which never delivers a result or which terminated with an
	 *         exception. Use {@link #hasException(Object)} and
	 *         {@link #hasResult(Object)} to clarify which state your
	 *         {@link Undoable} (job) is in.
	 */
	public , RET> RET getResult( JOB aJob ) throws NoResultAvailableRuntimeException;

	/**
	 * Executes the job and waits for the job's result or an exception or till
	 * the timeout has been reached. In case the timeout has been reached before
	 * execution was finished, then a {@link HandleTimeoutRuntimeException} is
	 * thrown to abort the waiting loop. This is especially useful when a remote
	 * connection is used to managed a distributed {@link JobBus} infrastructure
	 * and due to connection issues, wait time would be endless.
	 *
	 * @param  the generic type
	 * @param  The return type of the {@link Undoable}'s proceedings.
	 * @param aJob The job to execute
	 * @param aTimeoutMillis The timeout to wait at most even when execution did
	 *        not finish. In case the timeout has been reached before execution
	 *        was finished, then a {@link HandleTimeoutRuntimeException} is
	 *        thrown to abort the waiting loop.
	 * 
	 * @return The result of the job execution. In case the job does not produce
	 *         a result by default ("void"), then the according exception is
	 *         thrown. Make sure the job produces a result!
	 * 
	 * @throws NoResultAvailableRuntimeException in case a job has been executed
	 *         which never delivers a result or which terminated with an
	 *         exception. Use {@link #hasException(Object)} and
	 *         {@link #hasResult(Object)} to clarify which state your
	 *         {@link Undoable} (job) is in.
	 * @throws HandleTimeoutRuntimeException the handle timeout runtime
	 *         exception
	 */
	public , RET> RET getResult( JOB aJob, long aTimeoutMillis ) throws NoResultAvailableRuntimeException, HandleTimeoutRuntimeException;

	/**
	 * Determines whether the job has been executed.
	 *
	 * @param aHandle The handle associated to the job in question.
	 * 
	 * @return True if the job represented by the handle has been executed.
	 * 
	 * @throws UnknownHandleRuntimeException in case the handle is not unknown.
	 */
	boolean isExecuted( H aHandle ) throws UnknownHandleRuntimeException;

	/**
	 * Determines whether the job identified by the given handle has a regular
	 * result (instead of an exception). There may be jobs which do not have any
	 * result, i.e. check if the job has been executed and also check if there
	 * is a result or an exception before requesting the according information.
	 *
	 * @param aHandle The handle associated to the job in question.
	 * 
	 * @return The result of the job.
	 * 
	 * @throws UnknownHandleRuntimeException in case the handle is not unknown.
	 * @throws NotYetExecutedRuntimeException in case the job has not been
	 *         executed yet
	 */
	boolean hasResult( H aHandle ) throws UnknownHandleRuntimeException, NotYetExecutedRuntimeException;

	/**
	 * Determines whether the job identified by the given handle ended with an
	 * exception (instead of a regular result). Most jobs do not have any
	 * exception, i.e. check if the job has been executed and also check if
	 * there is a result or an exception before requesting the according
	 * information.
	 *
	 * @param aHandle The handle associated to the job in question.
	 * 
	 * @return The exception of the job's execution.
	 * 
	 * @throws UnknownHandleRuntimeException in case the handle is not unknown.
	 * @throws NotYetExecutedRuntimeException in case the job has not been
	 *         executed yet.
	 */
	boolean hasException( H aHandle ) throws UnknownHandleRuntimeException, NotYetExecutedRuntimeException;

	/**
	 * Returns the result of the job as the result of executing the job.
	 *
	 * @param  As of convenience, the return type of the {@link Undoable}
	 *        instance's proceedings. CAUTION: As the handle does not permit
	 *        insight on the {@link Undoable} (job) instance's return type, you
	 *        may end up with a class cast exception in case you do not make
	 *        sure that the result is of the expected type RET.
	 * @param aHandle The handle associated to the job in question.
	 * 
	 * @return The result after executing the job.
	 * 
	 * @throws UnknownHandleRuntimeException in case the handle is not unknown.
	 * @throws NotYetExecutedRuntimeException in case the job has not been
	 *         executed yet.
	 * @throws NoResultAvailableRuntimeException in case the job did not provide
	 *         a result after execution.
	 */
	 RET getResult( H aHandle ) throws UnknownHandleRuntimeException, NotYetExecutedRuntimeException, NoResultAvailableRuntimeException;

	/**
	 * Returns the exception of the job in case it terminated with an error.
	 *
	 * @param  the element type
	 * @param aHandle The handle associated to the job in question.
	 * 
	 * @return The exception after executing the job.
	 * 
	 * @throws UnknownHandleRuntimeException in case the handle is not unknown.
	 * @throws NotYetExecutedRuntimeException in case the job has not been
	 *         executed yet.
	 * @throws NoExceptionAvailableRuntimeException in case the job did not
	 *         provide an exception after execution.
	 */
	 E getException( H aHandle ) throws UnknownHandleRuntimeException, NotYetExecutedRuntimeException, NoExceptionAvailableRuntimeException;
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy