diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/DataContext.java b/native/src/main/java/io/ballerina/stdlib/http/api/DataContext.java index 768fca6ec0..da4325f878 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/DataContext.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/DataContext.java @@ -25,6 +25,8 @@ import io.ballerina.stdlib.http.transport.contract.HttpClientConnector; import io.ballerina.stdlib.http.transport.message.HttpCarbonMessage; +import static io.ballerina.stdlib.http.api.HttpConstants.FUTURE_COMPLETE_ERR_MSG; + /** * {@code DataContext} is the wrapper to hold {@code Context} and {@code Callback}. */ @@ -55,17 +57,17 @@ public DataContext(Environment environment, HttpCarbonMessage inboundRequestMsg) public void notifyInboundResponseStatus(BObject inboundResponse, BError httpConnectorError) { //Make the request associate with this response consumable again so that it can be reused. if (inboundResponse != null) { - getFuture().complete(inboundResponse); + completeFuture(inboundResponse, "notify inbound response status"); } else if (httpConnectorError != null) { - getFuture().complete(httpConnectorError); + completeFuture(httpConnectorError, "notify inbound response connector error"); } else { BError err = HttpUtil.createHttpError("inbound response retrieval error", HttpErrorType.CLIENT_ERROR); - getFuture().complete(err); + completeFuture(err, "notify inbound response retrieval error"); } } public void notifyOutboundResponseStatus(BError httpConnectorError) { - getFuture().complete(httpConnectorError); + completeFuture(httpConnectorError, "notify outbound response connector error"); } public HttpCarbonMessage getOutboundRequest() { @@ -84,7 +86,12 @@ public Environment getEnvironment() { return environment; } - public Future getFuture() { - return balFuture; + public void completeFuture(Object result, String methodCall) { + try { + balFuture.complete(result); + } catch (BError err) { + System.err.printf(FUTURE_COMPLETE_ERR_MSG, methodCall, err.getMessage()); + HttpUtil.printStacktraceIfError(result); + } } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpCallableUnitCallback.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpCallableUnitCallback.java index 09a58b2be9..77a38d9898 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpCallableUnitCallback.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpCallableUnitCallback.java @@ -130,7 +130,7 @@ public void invokeBalMethod(Object[] paramFeed, String methodName) { @Override public void notifySuccess(Object result) { stopObserverContext(); - printStacktraceIfError(result); + HttpUtil.printStacktraceIfError(result); } @Override @@ -188,17 +188,11 @@ private boolean alreadyResponded(Object result) { HttpUtil.methodInvocationCheck(requestMessage, HttpConstants.INVALID_STATUS_CODE, ILLEGAL_FUNCTION_INVOKED); } catch (BError e) { if (result != null) { // handles nil return and end of resource exec - printStacktraceIfError(result); + HttpUtil.printStacktraceIfError(result); err.println(HttpConstants.HTTP_RUNTIME_WARNING_PREFIX + e.getMessage()); } return true; } return false; } - - private void printStacktraceIfError(Object result) { - if (result instanceof BError) { - ((BError) result).printStackTrace(); - } - } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java index 7ee9c3d5d3..c08cf26928 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java @@ -613,6 +613,8 @@ public class HttpConstants { public static final BString REQUEST_CTX_MEMBERS = StringUtils.fromString("members"); + public static final String FUTURE_COMPLETE_ERR_MSG = "%s failed with bal future completion error: %s%n"; + private HttpConstants() { } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpRequestInterceptorUnitCallback.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpRequestInterceptorUnitCallback.java index 76cc1302c3..3725d9e7ff 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpRequestInterceptorUnitCallback.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpRequestInterceptorUnitCallback.java @@ -101,12 +101,6 @@ private boolean alreadyResponded() { return false; } - private void printStacktraceIfError(Object result) { - if (result instanceof BError) { - ((BError) result).printStackTrace(); - } - } - private void sendRequestToNextService() { ballerinaHTTPConnectorListener.onMessage(requestMessage); } @@ -186,7 +180,7 @@ public void invokeBalMethod(Object[] paramFeed, String methodName) { Callback returnCallback = new Callback() { @Override public void notifySuccess(Object result) { - printStacktraceIfError(result); + HttpUtil.printStacktraceIfError(result); } @Override diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpResponseInterceptorUnitCallback.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpResponseInterceptorUnitCallback.java index 00f5d223c2..05e20f95fe 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpResponseInterceptorUnitCallback.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpResponseInterceptorUnitCallback.java @@ -88,12 +88,6 @@ public void invokeErrorInterceptors(BError error, boolean printError) { returnErrorResponse(error); } - private void printStacktraceIfError(Object result) { - if (result instanceof BError) { - ((BError) result).printStackTrace(); - } - } - private void sendResponseToNextService() { Respond.nativeRespondWithDataCtx(environment, caller, response, dataContext); } @@ -171,7 +165,7 @@ public void invokeBalMethod(Object[] paramFeed, String methodName) { public void notifySuccess(Object result) { stopObserverContext(); dataContext.notifyOutboundResponseStatus(null); - printStacktraceIfError(result); + HttpUtil.printStacktraceIfError(result); } @Override diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java index 8cf4716653..71f0c874ce 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java @@ -1971,6 +1971,12 @@ public static boolean isHttpStatusCodeResponseTypeWithBody(Type type) { return false; } + public static void printStacktraceIfError(Object result) { + if (result instanceof BError) { + ((BError) result).printStackTrace(); + } + } + private HttpUtil() { } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/HasPromise.java b/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/HasPromise.java index c100b351fb..4a5a8e8786 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/HasPromise.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/HasPromise.java @@ -18,6 +18,7 @@ import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Future; +import io.ballerina.runtime.api.values.BError; import io.ballerina.runtime.api.values.BObject; import io.ballerina.stdlib.http.api.HttpConstants; import io.ballerina.stdlib.http.api.HttpUtil; @@ -25,6 +26,8 @@ import io.ballerina.stdlib.http.transport.contract.HttpClientConnectorListener; import io.ballerina.stdlib.http.transport.message.ResponseHandle; +import static io.ballerina.stdlib.http.api.HttpConstants.FUTURE_COMPLETE_ERR_MSG; + /** * {@code HasPromise} action can be used to check whether a push promise is available. */ @@ -51,7 +54,11 @@ private static class PromiseAvailabilityCheckListener implements HttpClientConne @Override public void onPushPromiseAvailability(boolean isPromiseAvailable) { - balFuture.complete(isPromiseAvailable); + try { + balFuture.complete(isPromiseAvailable); + } catch (BError err) { + System.err.printf(FUTURE_COMPLETE_ERR_MSG, "check promise availability", err.getMessage()); + } } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/HttpClientAction.java b/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/HttpClientAction.java index 405c062e68..8dd400200b 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/HttpClientAction.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/client/actions/HttpClientAction.java @@ -52,6 +52,7 @@ import static io.ballerina.stdlib.http.api.HttpConstants.CURRENT_TRANSACTION_CONTEXT_PROPERTY; import static io.ballerina.stdlib.http.api.HttpConstants.EMPTY; import static io.ballerina.stdlib.http.api.HttpConstants.EQUAL_SIGN; +import static io.ballerina.stdlib.http.api.HttpConstants.FUTURE_COMPLETE_ERR_MSG; import static io.ballerina.stdlib.http.api.HttpConstants.MAIN_STRAND; import static io.ballerina.stdlib.http.api.HttpConstants.ORIGIN_HOST; import static io.ballerina.stdlib.http.api.HttpConstants.POOLED_BYTE_BUFFER_FACTORY; @@ -226,7 +227,13 @@ private static Object invokeClientMethod(Environment env, BObject client, String env.getRuntime().invokeMethodAsync(client, methodName, null, null, new Callback() { @Override public void notifySuccess(Object result) { - balFuture.complete(result); + try { + balFuture.complete(result); + } catch (BError err) { + System.err.printf(FUTURE_COMPLETE_ERR_MSG, "invoke client method with success result", + err.getMessage()); + HttpUtil.printStacktraceIfError(result); + } } @Override @@ -234,7 +241,13 @@ public void notifyFailure(BError bError) { BError invocationError = HttpUtil.createHttpError("client method invocation failed: " + bError.getErrorMessage(), HttpErrorType.CLIENT_ERROR, bError); - balFuture.complete(invocationError); + try { + balFuture.complete(invocationError); + } catch (BError err) { + System.err.printf(FUTURE_COMPLETE_ERR_MSG, "invoke client method with failure result", + err.getMessage()); + HttpUtil.printStacktraceIfError(invocationError); + } } }, propertyMap, PredefinedTypes.TYPE_NULL, paramFeed); return null; diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternHttpDataSourceBuilder.java b/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternHttpDataSourceBuilder.java index fc9498b0b4..a9212f0cea 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternHttpDataSourceBuilder.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternHttpDataSourceBuilder.java @@ -40,6 +40,7 @@ import java.util.Locale; import java.util.Objects; +import static io.ballerina.stdlib.http.api.HttpConstants.FUTURE_COMPLETE_ERR_MSG; import static io.ballerina.stdlib.mime.util.EntityBodyHandler.constructBlobDataSource; import static io.ballerina.stdlib.mime.util.EntityBodyHandler.constructJsonDataSource; import static io.ballerina.stdlib.mime.util.EntityBodyHandler.constructStringDataSource; @@ -229,7 +230,14 @@ private static void createErrorAndNotify(Future balFuture, String errMsg) { } private static void setReturnValuesAndNotify(Future balFuture, Object result) { - balFuture.complete(result); + try { + balFuture.complete(result); + } catch (BError error) { + String resultType = result instanceof BError ? "error" : "success"; + System.err.printf(FUTURE_COMPLETE_ERR_MSG, "return data source builder " + resultType + " result", + error.getMessage()); + HttpUtil.printStacktraceIfError(result); + } } private static void updateDataSourceAndNotify(Future balFuture, BObject entityObj, diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/connection/Respond.java b/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/connection/Respond.java index 03242c8c95..9ad07d0bdd 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/connection/Respond.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/connection/Respond.java @@ -92,7 +92,7 @@ public static Object nativeRespondWithDataCtx(Environment env, BObject connectio "as the response has been already used.", inboundRequestMsg.getSequenceId()); } BError httpError = HttpUtil.createHttpError(errorMessage, HttpErrorType.GENERIC_LISTENER_ERROR); - dataContext.getFuture().complete(httpError); + dataContext.completeFuture(httpError, "notify outbound dirty response"); return null; } outboundResponseObj.addNativeData(HttpConstants.DIRTY_RESPONSE, true); @@ -107,7 +107,7 @@ public static Object nativeRespondWithDataCtx(Environment env, BObject connectio HttpUtil.checkFunctionValidity(inboundRequestMsg, outboundResponseMsg); } catch (BError e) { log.debug(e.getPrintableStackTrace(), e); - dataContext.getFuture().complete(e); + dataContext.completeFuture(e, "notify function availability failure"); return null; } @@ -151,14 +151,14 @@ public static Object nativeRespondWithDataCtx(Environment env, BObject connectio } } catch (BError e) { log.debug(e.getPrintableStackTrace(), e); - dataContext.getFuture().complete( - HttpUtil.createHttpError(e.getMessage(), HttpErrorType.GENERIC_LISTENER_ERROR)); + dataContext.completeFuture(HttpUtil.createHttpError(e.getMessage(), HttpErrorType.GENERIC_LISTENER_ERROR), + "notify outbound response sent error"); } catch (Throwable e) { //Exception is already notified by http transport. String errorMessage = "Couldn't complete outbound response: " + e.getMessage(); log.debug(errorMessage, e); - dataContext.getFuture().complete( - HttpUtil.createHttpError(errorMessage, HttpErrorType.GENERIC_LISTENER_ERROR)); + dataContext.completeFuture(HttpUtil.createHttpError(errorMessage, HttpErrorType.GENERIC_LISTENER_ERROR), + "notify outbound response completion error"); } return null; }