Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jacpfx.vertx.rest.response.blocking.ResponseBlockingExecution Maven / Gradle / Ivy
/*
* Copyright [2017] [Andy Moncsek]
*
* 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 org.jacpfx.vertx.rest.response.blocking;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.shareddata.Counter;
import io.vertx.core.shareddata.Lock;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import org.jacpfx.common.ExecutionResult;
import org.jacpfx.common.VxmsShared;
import org.jacpfx.common.concurrent.LocalData;
import org.jacpfx.common.throwable.ThrowableFunction;
import org.jacpfx.common.throwable.ThrowableSupplier;
import org.jacpfx.vertx.rest.response.basic.ResponseExecution;
/**
* Created by Andy Moncsek on 19.01.16.
* Performs blocking Executions and prepares response
*/
public class ResponseBlockingExecution {
private static final int DEFAULT_VALUE = 0;
private static final long DEFAULT_LONG_VALUE = 0;
private static final int DEFAULT_LOCK_TIMEOUT = 2000;
private static final int STOP_CONDITION = -1;
private static final long LOCK_VALUE = -1l;
/**
* Creates the response value based on the flow defined in the fluent API. The resulting response
* will be passed to the resultHandler. This method should be executed in a non blocking context.
* When defining a timeout a second execution context will be created.
*
* @param _methodId the method name/id to be executed
* @param _supplier the user defined supply method to be executed (mapToStringResponse,
* mapToByteResponse, mapToObjectResponse)
* @param _resultHandler the result handler, that takes the result
* @param _errorHandler the intermediate error method, executed on each error
* @param _onFailureRespond the method to be executed on failure
* @param _errorMethodHandler the fallback method
* @param vxmsShared the vxmsShared instance, containing the Vertx instance and other shared
* objects per instance
* @param _fail last thrown Exception
* @param _retry the amount of retries
* @param _timeout, the max timeout time for the method execution
* @param _circuitBreakerTimeout the stateful circuit breaker release time
* @param _delay the delay time between retry
* @param the type of response (String, byte, Object)
*/
public static void executeRetryAndCatchAsync(String _methodId,
ThrowableSupplier _supplier,
Future> _resultHandler,
Consumer _errorHandler,
ThrowableFunction _onFailureRespond,
Consumer _errorMethodHandler,
VxmsShared vxmsShared, Throwable _fail,
int _retry,
long _timeout,
long _circuitBreakerTimeout,
long _delay) {
if (_circuitBreakerTimeout > DEFAULT_LONG_VALUE) {
executeLocked((lock, counter) -> counter.get(counterHandler -> {
long currentVal = counterHandler.result();
if (currentVal == DEFAULT_LONG_VALUE) {
executeInitialState(_methodId,
_supplier,
_resultHandler,
_errorHandler,
_onFailureRespond,
_errorMethodHandler,
vxmsShared, _fail,
_retry, _timeout,
_circuitBreakerTimeout,
_delay, lock, counter);
} else if (currentVal > DEFAULT_LONG_VALUE) {
executeDefault(_methodId,
_supplier,
_resultHandler,
_errorHandler,
_onFailureRespond,
_errorMethodHandler,
vxmsShared, _fail,
_retry, _timeout,
_circuitBreakerTimeout,
_delay, lock);
} else {
executeErrorState(_resultHandler, _errorHandler, _onFailureRespond, _errorMethodHandler,
_fail, lock);
}
}), _methodId, vxmsShared, _resultHandler, _errorHandler, _onFailureRespond,
_errorMethodHandler, null);
} else {
executeStateless(_supplier, _resultHandler, _errorHandler, _onFailureRespond,
_errorMethodHandler, vxmsShared, _retry, _timeout, _delay);
}
}
private static void executeErrorState(Future> _blockingHandler,
Consumer _errorHandler,
ThrowableFunction _onFailureRespond,
Consumer _errorMethodHandler,
Throwable t, Lock lock) {
Optional.ofNullable(lock).ifPresent(Lock::release);
handleErrorExecution(_blockingHandler,
_errorHandler,
_onFailureRespond,
_errorMethodHandler,
Optional.ofNullable(t).orElse(Future.failedFuture("circuit open").cause()));
}
private static void executeDefault(String _methodId,
ThrowableSupplier _supplier,
Future> _blockingHandler,
Consumer _errorHandler,
ThrowableFunction _onFailureRespond,
Consumer _errorMethodHandler,
VxmsShared vxmsShared, Throwable _failure,
int _retry, long _timeout,
long _circuitBreakerTimeout,
long _delay, Lock lock) {
Optional.ofNullable(lock).ifPresent(Lock::release);
final Vertx vertx = vxmsShared.getVertx();
vertx.executeBlocking(bhandler -> {
try {
executeDefaultState(_supplier, _blockingHandler, vxmsShared, _timeout);
bhandler.complete();
} catch (Throwable e) {
executeLocked((lck, counter) ->
counter.decrementAndGet(valHandler -> {
if (valHandler.succeeded()) {
handleStatefulError(_methodId,
_supplier,
_blockingHandler,
_errorHandler,
_onFailureRespond,
_errorMethodHandler,
vxmsShared, _failure,
_retry,
_timeout,
_circuitBreakerTimeout,
_delay, e,
lck, counter,
valHandler);
bhandler.complete();
} else {
releaseLockAndHandleError(_blockingHandler, _errorHandler, _onFailureRespond,
_errorMethodHandler, valHandler.cause(), lck);
bhandler.complete();
}
}), _methodId, vxmsShared, _blockingHandler, _errorHandler, _onFailureRespond,
_errorMethodHandler, bhandler);
}
}, false, res -> {
});
}
private static void executeInitialState(String _methodId,
ThrowableSupplier _supplier,
Future> _blockingHandler,
Consumer _errorHandler,
ThrowableFunction _onFailureRespond,
Consumer _errorMethodHandler,
VxmsShared vxmsShared, Throwable _t, int _retry,
long _timeout, long _circuitBreakerTimeout,
long _delay, Lock lock, Counter counter) {
final long initialRetryCounterValue = (long) (_retry + 1);
counter.addAndGet(initialRetryCounterValue,
rHandler -> executeDefault(_methodId, _supplier, _blockingHandler, _errorHandler,
_onFailureRespond,
_errorMethodHandler, vxmsShared, _t, _retry, _timeout, _circuitBreakerTimeout, _delay,
lock));
}
private static void releaseLockAndHandleError(Future> _blockingHandler,
Consumer _errorHandler,
ThrowableFunction _onFailureRespond,
Consumer _errorMethodHandler,
Throwable cause, Lock lock) {
Optional.ofNullable(lock).ifPresent(Lock::release);
handleErrorExecution(_blockingHandler, _errorHandler, _onFailureRespond, _errorMethodHandler,
cause);
}
private static void handleErrorExecution(Future> _blockingHandler,
Consumer _errorHandler,
ThrowableFunction _onFailureRespond,
Consumer _errorMethodHandler,
Throwable cause) {
final T result = handleError(_errorHandler, _onFailureRespond, _errorMethodHandler, cause);
if (!_blockingHandler.isComplete()) {
_blockingHandler.complete(new ExecutionResult<>(result, true, true, null));
}
}
private static void handleStatefulError(String _methodId,
ThrowableSupplier _supplier,
Future> _blockingHandler,
Consumer _errorHandler,
ThrowableFunction _onFailureRespond,
Consumer _errorMethodHandler,
VxmsShared vxmsShared, Throwable _t, int _retry,
long _timeout, long _circuitBreakerTimeout,
long _delay, Throwable e, Lock lck,
Counter counter, AsyncResult valHandler) {
//////////////////////////////////////////
long count = valHandler.result();
if (count <= DEFAULT_LONG_VALUE) {
setCircuitBreakerReleaseTimer(vxmsShared, _retry, _circuitBreakerTimeout, counter);
openCircuitBreakerAndHandleError(_blockingHandler, _errorHandler, _onFailureRespond,
_errorMethodHandler, vxmsShared, e, lck, counter);
} else {
lck.release();
ResponseExecution.handleError(_errorHandler, e);
handleDelay(_delay);
executeRetryAndCatchAsync(_methodId, _supplier, _blockingHandler, _errorHandler,
_onFailureRespond, _errorMethodHandler, vxmsShared, _t, _retry, _timeout,
_circuitBreakerTimeout, _delay);
}
////////////////////////////////////////
}
private static void openCircuitBreakerAndHandleError(
Future> _blockingHandler,
Consumer _errorHandler,
ThrowableFunction _onFailureRespond,
Consumer _errorMethodHandler,
VxmsShared vxmsShared, Throwable e,
Lock lck, Counter counter) {
counter.addAndGet(LOCK_VALUE, val -> {
lck.release();
final Vertx vertx = vxmsShared.getVertx();
vertx.executeBlocking(bhandler -> {
T result = handleError(_errorHandler, _onFailureRespond, _errorMethodHandler, e);
if (!_blockingHandler.isComplete()) {
_blockingHandler.complete(new ExecutionResult<>(result, true, true, null));
}
}, false, res -> {
});
});
}
private static void setCircuitBreakerReleaseTimer(VxmsShared vxmsShared, int _retry,
long _circuitBreakerTimeout, Counter counter) {
final Vertx vertx = vxmsShared.getVertx();
vertx.setTimer(_circuitBreakerTimeout, timer -> {
final long initialRetryCounterValue = (long) (_retry + 1);
counter.addAndGet(initialRetryCounterValue, val -> {
});
});
}
private static void executeDefaultState(ThrowableSupplier _supplier,
Future> _blockingHandler, VxmsShared vxmsShared, long _timeout)
throws Throwable {
T result;
if (_timeout > DEFAULT_LONG_VALUE) {
result = executeWithTimeout(_supplier, vxmsShared, _timeout);
} else {
result = _supplier.get();
}
if (!_blockingHandler.isComplete()) {
_blockingHandler.complete(new ExecutionResult<>(result, true, false, null));
}
}
private static T executeWithTimeout(ThrowableSupplier _supplier, VxmsShared vxmsShared,
long _timeout) throws Throwable {
T result;
final CompletableFuture timeoutFuture = new CompletableFuture<>();
final Vertx vertx = vxmsShared.getVertx();
vertx.executeBlocking((innerHandler) -> {
try {
timeoutFuture.complete(_supplier.get());
} catch (Throwable throwable) {
timeoutFuture.obtrudeException(throwable);
}
}, false, (val) -> {
});
try {
result = timeoutFuture.get(_timeout, TimeUnit.MILLISECONDS);
} catch (TimeoutException timeout) {
throw new TimeoutException("operation _timeout");
}
return result;
}
private static void executeStateless(ThrowableSupplier _supplier,
Future> _blockingHandler,
Consumer errorHandler,
ThrowableFunction onFailureRespond,
Consumer errorMethodHandler,
VxmsShared vxmsShared, int _retry,
long timeout, long delay) {
T result = null;
boolean errorHandling = false;
while (_retry >= DEFAULT_LONG_VALUE) {
errorHandling = false;
try {
if (timeout > DEFAULT_LONG_VALUE) {
result = executeWithTimeout(_supplier, vxmsShared, timeout);
_retry = STOP_CONDITION;
} else {
result = _supplier.get();
_retry = STOP_CONDITION;
}
} catch (Throwable e) {
_retry--;
if (_retry < DEFAULT_VALUE) {
try {
result = handleError(errorHandler, onFailureRespond, errorMethodHandler, e);
errorHandling = true;
} catch (Exception ee) {
_blockingHandler.fail(ee);
}
} else {
ResponseExecution.handleError(errorHandler, e);
handleDelay(delay);
}
}
}
if (!errorHandling || errorHandling && result != null) {
if (!_blockingHandler.isComplete()) {
_blockingHandler.complete(new ExecutionResult<>(result, true, errorHandling, null));
}
}
}
private static void handleDelay(long delay) {
try {
if (delay > DEFAULT_LONG_VALUE) {
Thread.sleep(delay);
}
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
private static T handleError(Consumer errorHandler,
ThrowableFunction onFailureRespond,
Consumer errorMethodHandler, Throwable e) {
T result = null;
try {
if (errorHandler != null) {
errorHandler.accept(e);
}
if (onFailureRespond != null) {
result = onFailureRespond.apply(e);
}
if (errorHandler == null && onFailureRespond == null) {
errorMethodHandler.accept(e);
return null;
}
} catch (Throwable throwable) {
errorMethodHandler.accept(throwable);
}
return result;
}
private static void executeLocked(LockedConsumer consumer,
String _methodId,
VxmsShared vxmsShared,
Future> _blockingHandler,
Consumer _errorHandler,
ThrowableFunction _onFailureRespond,
Consumer _errorMethodHandler,
Future blockingCodeHandler) {
// TODO make cluster-aware
final LocalData sharedData = vxmsShared.getLocalData();
sharedData.getLockWithTimeout(_methodId, DEFAULT_LOCK_TIMEOUT, lockHandler -> {
final Lock lock = lockHandler.result();
if (lockHandler.succeeded()) {
sharedData.getCounter(_methodId, resultHandler -> {
if (resultHandler.succeeded()) {
consumer.execute(lock, resultHandler.result());
} else {
releaseLockAndHandleError(_blockingHandler, _errorHandler, _onFailureRespond,
_errorMethodHandler, resultHandler.cause(), lock);
Optional.ofNullable(blockingCodeHandler).ifPresent(Future::complete);
}
});
} else {
handleErrorExecution(_blockingHandler, _errorHandler, _onFailureRespond,
_errorMethodHandler, lockHandler.cause());
Optional.ofNullable(blockingCodeHandler).ifPresent(Future::complete);
}
});
}
private interface LockedConsumer {
void execute(Lock lock, Counter counter);
}
}