org.refcodes.jobbus.JobBus Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of refcodes-jobbus Show documentation
Show all versions of refcodes-jobbus Show documentation
Artifact providing command pattern based job-bus functionality.
// /////////////////////////////////////////////////////////////////////////////
// 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