org.refcodes.jobbus.JobBusProxy 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")
// -----------------------------------------------------------------------------
// 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.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.refcodes.command.NoExceptionAvailableRuntimeException;
import org.refcodes.command.NoResultAvailableRuntimeException;
import org.refcodes.command.NotYetExecutedRuntimeException;
import org.refcodes.command.Undoable;
import org.refcodes.component.HandleTimeoutRuntimeException;
import org.refcodes.component.UnknownHandleRuntimeException;
import org.refcodes.component.UnsupportedHandleOperationRuntimeException;
import org.refcodes.controlflow.ControlFlowUtility;
import org.refcodes.controlflow.RetryTimeout;
import org.refcodes.data.RetryLoopCount;
import org.refcodes.data.SleepLoopTime;
import org.refcodes.exception.ExceptionUtility;
/**
* The {@link JobBusProxy} implements a {@link JobBus} proxy: a {@link JobBus}
* proxy can use a remote {@link JobBus} whilst only delegating those operations
* to the remote {@link JobBus} which can be handled on the remote system. Any
* operation requiring asynchronous {@link Thread} operations is handled by the
* {@link JobBusProxy}. This is necessary for the synchronous operations as a)
* waiting for an asynchronous operation to finish may result in a timeout
* caused by the remoting framework and as b) invoking lambda operations on the
* proxy will not be propagated to a remote {@link JobBus} instance as
* bidirectional remoting usually is not supported by a remoting framework.
*
* @param The context type to use, can by any component, service or POJO.
* @param The handle type used to reference a job.
*/
public class JobBusProxy implements JobBus {
// /////////////////////////////////////////////////////////////////////////
// STATICS:
// /////////////////////////////////////////////////////////////////////////
private static Logger LOGGER = Logger.getLogger( JobBusProxy.class.getName() );
// /////////////////////////////////////////////////////////////////////////
// CONSTANTS:
// /////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////
// VARIABLES:
// /////////////////////////////////////////////////////////////////////////
private JobBus _jobBus;
private ExecutorService _executorService;
// /////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS:
// /////////////////////////////////////////////////////////////////////////
/**
* Instantiates a new job bus proxy impl.
*
* @param aJobBus the job bus
*/
public JobBusProxy( JobBus aJobBus ) {
this( aJobBus, null );
}
/**
* Instantiates a new job bus proxy impl.
*
* @param aJobBus the job bus
* @param aExecutorService the executor service
*/
public JobBusProxy( JobBus aJobBus, ExecutorService aExecutorService ) {
_jobBus = aJobBus;
if ( aExecutorService == null ) {
_executorService = ControlFlowUtility.createCachedExecutorService( true );
}
else {
_executorService = ControlFlowUtility.toManagedExecutorService( aExecutorService );
}
}
// /////////////////////////////////////////////////////////////////////////
// INJECTION:
// /////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////
// METHODS:
// /////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
@Override
public boolean hasHandle( H aHandle ) {
return _jobBus.hasHandle( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasProgress( H aHandle ) throws UnknownHandleRuntimeException {
return _jobBus.hasProgress( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasReset( H aHandle ) throws UnknownHandleRuntimeException {
return _jobBus.hasReset( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasFlush( H aHandle ) throws UnknownHandleRuntimeException {
return _jobBus.hasFlush( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public Undoable lookupHandle( H aHandle ) throws UnknownHandleRuntimeException {
return _jobBus.lookupHandle( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public Undoable removeHandle( H aHandle ) throws UnknownHandleRuntimeException {
return _jobBus.removeHandle( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public void reset( H aHandle ) throws UnknownHandleRuntimeException, UnsupportedHandleOperationRuntimeException {
_jobBus.reset( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public float getProgress( H aHandle ) throws UnsupportedHandleOperationRuntimeException, UnknownHandleRuntimeException {
return _jobBus.getProgress( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public void flush( H aHandle ) throws IOException, UnknownHandleRuntimeException, UnsupportedHandleOperationRuntimeException {
_jobBus.flush( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public H execute( Undoable aJob ) {
return _jobBus.execute( aJob );
}
/**
* {@inheritDoc}
*/
@Override
public boolean isExecuted( H aHandle ) throws UnknownHandleRuntimeException {
return _jobBus.isExecuted( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasResult( H aHandle ) throws UnknownHandleRuntimeException, NotYetExecutedRuntimeException {
return _jobBus.hasResult( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasException( H aHandle ) throws UnknownHandleRuntimeException, NotYetExecutedRuntimeException {
return _jobBus.hasException( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public RET getResult( H aHandle ) throws UnknownHandleRuntimeException, NotYetExecutedRuntimeException, NoResultAvailableRuntimeException {
return _jobBus.getResult( aHandle );
}
/**
* {@inheritDoc}
*/
@Override
public E getException( H aHandle ) throws UnknownHandleRuntimeException, NotYetExecutedRuntimeException, NoExceptionAvailableRuntimeException {
return _jobBus.getException( aHandle );
}
/* Non-atomic methods to be implemented on proxy's system: */
@Override
public void execute( Undoable aJob, final Consumer aResultConsumer ) {
final H theHandle = _jobBus.execute( aJob );
Runnable theLambdaRunnable = new Runnable() {
@Override
public void run() {
waitForExecution( theHandle );
try {
aResultConsumer.accept( getResult( theHandle ) );
}
catch ( UnknownHandleRuntimeException | NotYetExecutedRuntimeException | NoResultAvailableRuntimeException e ) {
LOGGER.log( Level.WARNING, ExceptionUtility.toMessage( e ), e );
}
}
};
_executorService.execute( theLambdaRunnable );
}
/**
* {@inheritDoc}
*/
@Override
public void execute( Undoable aJob, final BiConsumer aResultConsumer ) {
final H theHandle = _jobBus.execute( aJob );
Runnable theLambdaRunnable = new Runnable() {
@Override
public void run() {
waitForExecution( theHandle );
try {
try {
aResultConsumer.accept( getResult( theHandle ), null );
}
catch ( NoResultAvailableRuntimeException e ) {
aResultConsumer.accept( null, getException( theHandle ) );
}
}
catch ( UnknownHandleRuntimeException | NotYetExecutedRuntimeException | NoExceptionAvailableRuntimeException e ) {
LOGGER.log( Level.WARNING, ExceptionUtility.toMessage( e ), e );
}
}
};
_executorService.execute( theLambdaRunnable );
}
/**
* {@inheritDoc}
*/
@Override
public void waitForExecution( H aHandle ) throws UnknownHandleRuntimeException {
while ( !_jobBus.isExecuted( aHandle ) ) {
try {
Thread.sleep( SleepLoopTime.NORM.getTimeMillis() );
}
catch ( InterruptedException e ) {
break;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void waitForExecution( H aHandle, long aTimeoutMillis ) throws UnknownHandleRuntimeException, HandleTimeoutRuntimeException {
RetryTimeout theRetryTimeout = new RetryTimeout( aTimeoutMillis, RetryLoopCount.NORM_NUM_RETRY_LOOPS.getValue() );
while ( !_jobBus.isExecuted( aHandle ) && theRetryTimeout.hasNextRetry() ) {
theRetryTimeout.nextRetry();
}
if ( !isExecuted( aHandle ) ) {
throw new HandleTimeoutRuntimeException( aHandle, "Execution of the command referenced by the given handle did not terminate in the given amount of <" + aTimeoutMillis + "> ms, aborting wait loop." );
}
}
/**
* {@inheritDoc}
*/
@Override
public , RET> RET getResult( JOB aJob ) throws NoResultAvailableRuntimeException {
H theHandle = execute( aJob );
waitForExecution( theHandle );
return _jobBus.getResult( theHandle );
}
/**
* {@inheritDoc}
*/
@Override
public , RET> RET getResult( JOB aJob, long aTimeoutMillis ) {
H theHandle = execute( aJob );
waitForExecution( theHandle, aTimeoutMillis );
return _jobBus.getResult( theHandle );
}
// /////////////////////////////////////////////////////////////////////////
// HOOKS:
// /////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////
// HELPER:
// /////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////
// INNER CLASSES:
// /////////////////////////////////////////////////////////////////////////
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy