Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update implementation to resolve lang spec deviation misuse #1706

Merged
6 changes: 3 additions & 3 deletions ballerina-tests/http-interceptor-tests/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http_interceptor_tests"
version = "2.9.0"
version = "2.9.1"

[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
version = "2.9.0"
version = "2.9.1"

[platform.java11]
graalvmCompatible = true

[[platform.java11.dependency]]
scope = "testOnly"
path = "../../test-utils/build/libs/http-test-utils-2.9.0.jar"
path = "../../test-utils/build/libs/http-test-utils-2.9.1-SNAPSHOT.jar"
6 changes: 3 additions & 3 deletions ballerina-tests/http-interceptor-tests/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
version = "2.9.0"
version = "2.9.1"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
Expand Down Expand Up @@ -99,7 +99,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_interceptor_tests"
version = "2.9.0"
version = "2.9.1"
dependencies = [
{org = "ballerina", name = "http"},
{org = "ballerina", name = "http_test_common"},
Expand All @@ -115,7 +115,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
version = "2.9.0"
version = "2.9.1"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ listener http:Listener responseInterceptorReturnsErrorTestServerEP = new(respons

service http:InterceptableService / on responseInterceptorReturnsErrorTestServerEP {

public function createInterceptors() returns [LastResponseInterceptor, ResponseInterceptorReturnsError, DefaultResponseInterceptor] {
public function createInterceptors() returns http:Interceptor[] {
return [new LastResponseInterceptor(), new ResponseInterceptorReturnsError(), new DefaultResponseInterceptor()];
}

Expand Down Expand Up @@ -561,7 +561,7 @@ service http:InterceptableService /requestInterceptorJwtInformation on new http:
}
}) {

public function createInterceptors() returns RequestInterceptorJwtInformation {
public function createInterceptors() returns http:Interceptor {
return new RequestInterceptorJwtInformation();
}

Expand Down
2 changes: 1 addition & 1 deletion ballerina-tests/http-test-common/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[package]
org = "ballerina"
name = "http_test_common"
version = "2.9.0"
version = "2.9.1"
2 changes: 1 addition & 1 deletion ballerina-tests/http-test-common/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ distribution-version = "2201.7.0"
[[package]]
org = "ballerina"
name = "http_test_common"
version = "2.9.0"
version = "2.9.1"
dependencies = [
{org = "ballerina", name = "lang.string"},
{org = "ballerina", name = "mime"},
Expand Down
6 changes: 3 additions & 3 deletions ballerina/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
org = "ballerina"
name = "http"
version = "2.9.0"
version = "2.9.1"
authors = ["Ballerina"]
keywords = ["http", "network", "service", "listener", "client"]
repository = "https://github.com/ballerina-platform/module-ballerina-http"
Expand All @@ -16,8 +16,8 @@ graalvmCompatible = true
[[platform.java11.dependency]]
groupId = "io.ballerina.stdlib"
artifactId = "http-native"
version = "2.9.0"
path = "../native/build/libs/http-native-2.9.0.jar"
version = "2.9.1"
path = "../native/build/libs/http-native-2.9.1-SNAPSHOT.jar"

[[platform.java11.dependency]]
groupId = "io.ballerina.stdlib"
Expand Down
2 changes: 1 addition & 1 deletion ballerina/CompilerPlugin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ id = "http-compiler-plugin"
class = "io.ballerina.stdlib.http.compiler.HttpCompilerPlugin"

[[dependency]]
path = "../compiler-plugin/build/libs/http-compiler-plugin-2.9.0.jar"
path = "../compiler-plugin/build/libs/http-compiler-plugin-2.9.1-SNAPSHOT.jar"
2 changes: 1 addition & 1 deletion ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http"
version = "2.9.0"
version = "2.9.1"
dependencies = [
{org = "ballerina", name = "auth"},
{org = "ballerina", name = "cache"},
Expand Down
23 changes: 13 additions & 10 deletions ballerina/http_service_endpoint.bal
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public isolated class Listener {

private int port;
private InferredListenerConfiguration inferredConfig;
private Interceptor[] interceptors;

# Gets invoked during module initialization to initialize the listener.
#
Expand All @@ -40,20 +39,24 @@ public isolated class Listener {
server: config.server,
requestLimits: config.requestLimits
};
self.interceptors = [new DefaultErrorInterceptor()];
Interceptor|Interceptor[]? interceptors = config["interceptors"];
if interceptors is Interceptor[] {
foreach Interceptor interceptor in interceptors {
self.interceptors.push(interceptor);
}
} else if interceptors is Interceptor {
self.interceptors.push(interceptors);
}
self.inferredConfig = inferredListenerConfig.cloneReadOnly();
self.port = port;
return externInitEndpoint(self, config);
}

isolated function createInterceptors(Interceptor|Interceptor[]? interceptorConfigValues) returns Interceptor[] {
Interceptor|Interceptor[]? configValues = interceptorConfigValues;
Interceptor[] interceptors = [new DefaultErrorInterceptor()];
if configValues is Interceptor[] {
foreach Interceptor interceptor in configValues {
interceptors.push(interceptor);
}
} else if configValues is Interceptor {
interceptors.push(configValues);
}
return interceptors;
}

# Starts the registered service programmatically.
#
# + return - An `error` if an error occurred during the listener starting process
Expand Down
5 changes: 3 additions & 2 deletions ballerina/resiliency_failover_client.bal
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ public client isolated class FailoverClient {
self.succeededEndpointIndex = 0;
self.failoverClientsArray = [];
Client clientEp;
Client?[] httpClients = self.failoverClientsArray;
int i = 0;
foreach var target in failoverClientConfig.targets {
ClientConfiguration epConfig = createClientEPConfigFromFailoverEPConfig(failoverClientConfig, target);
clientEp = check new(target.url, epConfig);
httpClients[i] = clientEp;
lock {
self.failoverClientsArray[i] = clientEp;
}
i += 1;
}
FailoverInferredConfig failoverInferredConfig = {
Expand Down
7 changes: 4 additions & 3 deletions ballerina/resiliency_load_balance_client.bal
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ public client isolated class LoadBalanceClient {
self.failover = loadBalanceClientConfig.failover;
self.loadBalanceClientsArray = [];
Client clientEp;
Client?[] lbClients = self.loadBalanceClientsArray;
int i = 0;
foreach var target in loadBalanceClientConfig.targets {
ClientConfiguration epConfig = createClientEPConfigFromLoalBalanceEPConfig(loadBalanceClientConfig, target);
clientEp = check new(target.url , epConfig);
lbClients[i] = clientEp;
clientEp = check new(target.url , epConfig);
lock {
self.loadBalanceClientsArray[i] = clientEp;
}
i += 1;
}
var lbRule = loadBalanceClientConfig.lbRule;
Expand Down
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ This file contains all the notable changes done to the Ballerina HTTP package th
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Fixed

- [Fix exception when return type of `createInterceptors` function is an array type](https://github.com/ballerina-platform/ballerina-standard-library/issues/4649)

## [2.9.0] - 2023-06-30

### Added
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
org.gradle.caching=true
group=io.ballerina.stdlib
version=2.9.1-SNAPSHOT
ballerinaLangVersion= 2201.7.0
ballerinaLangVersion=2201.7.0
ballerinaTomlParserVersion=1.2.2
commonsLang3Version=3.8.1
nettyVersion=4.1.94.Final
Expand Down
4 changes: 4 additions & 0 deletions native/spotbugs-exclude.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@
<Class name="io.ballerina.stdlib.http.api.HttpService$1" />
<Bug pattern="DM_EXIT" />
</Match>
<Match>
<Class name="io.ballerina.stdlib.http.api.HttpUtil$1" />
<Bug pattern="DM_EXIT" />
</Match>
<Match>
<Class name="io.ballerina.stdlib.http.api.client.endpoint.CreateSimpleHttpClient" />
<Bug pattern="REC_CATCH_EXCEPTION" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,9 @@ public void notifyFailure(BError bError) {
Object[] interceptors = interceptorsArrayFromService.getValues();
List<Object> interceptorServices = new ArrayList<>();
for (Object interceptor: interceptors) {
if (Objects.isNull(interceptor)) {
break;
}
interceptorServices.add(interceptor);
}

Expand Down Expand Up @@ -529,6 +532,9 @@ private static void populateBalInterceptorServicesArray(HttpService service, BAr
interceptorsArray.append(interceptor);
}
for (Object interceptor : fromService.getValues()) {
if (Objects.isNull(interceptor)) {
break;
}
interceptorsArray.append(interceptor);
}
service.setBalInterceptorServicesArray(interceptorsArray);
Expand Down
48 changes: 42 additions & 6 deletions native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@

import io.ballerina.runtime.api.Environment;
import io.ballerina.runtime.api.Module;
import io.ballerina.runtime.api.PredefinedTypes;
import io.ballerina.runtime.api.Runtime;
import io.ballerina.runtime.api.TypeTags;
import io.ballerina.runtime.api.async.Callback;
import io.ballerina.runtime.api.creators.ErrorCreator;
import io.ballerina.runtime.api.creators.ValueCreator;
import io.ballerina.runtime.api.types.Field;
Expand Down Expand Up @@ -115,6 +117,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

import static io.ballerina.runtime.api.constants.RuntimeConstants.BALLERINA_VERSION;
Expand All @@ -130,7 +133,9 @@
import static io.ballerina.runtime.observability.ObservabilityConstants.TAG_KEY_PEER_ADDRESS;
import static io.ballerina.stdlib.http.api.HttpConstants.ANN_CONFIG_ATTR_COMPRESSION_CONTENT_TYPES;
import static io.ballerina.stdlib.http.api.HttpConstants.ANN_CONFIG_ATTR_SSL_ENABLED_PROTOCOLS;
import static io.ballerina.stdlib.http.api.HttpConstants.CREATE_INTERCEPTORS_FUNCTION_NAME;
import static io.ballerina.stdlib.http.api.HttpConstants.ENDPOINT_CONFIG_HTTP2_INITIAL_WINDOW_SIZE;
import static io.ballerina.stdlib.http.api.HttpConstants.ENDPOINT_CONFIG_INTERCEPTORS;
import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_HEADERS;
import static io.ballerina.stdlib.http.api.HttpConstants.RESOLVED_REQUESTED_URI;
import static io.ballerina.stdlib.http.api.HttpConstants.RESPONSE_CACHE_CONTROL;
Expand All @@ -143,6 +148,7 @@
import static io.ballerina.stdlib.http.api.HttpConstants.SECURESOCKET_CONFIG_SESSION_TIMEOUT;
import static io.ballerina.stdlib.http.api.HttpConstants.SECURESOCKET_CONFIG_TRUSTSTORE_FILE_PATH;
import static io.ballerina.stdlib.http.api.HttpConstants.SECURESOCKET_CONFIG_TRUSTSTORE_PASSWORD;
import static io.ballerina.stdlib.http.api.HttpConstants.SERVICE_ENDPOINT_CONFIG;
import static io.ballerina.stdlib.http.api.HttpConstants.SINGLE_SLASH;
import static io.ballerina.stdlib.http.api.HttpConstants.SOCKET_CONFIG_CONNECT_TIMEOUT;
import static io.ballerina.stdlib.http.api.HttpConstants.SOCKET_CONFIG_KEEP_ALIVE;
Expand Down Expand Up @@ -1600,22 +1606,52 @@
}

public static void populateInterceptorServicesFromListener(BObject serviceEndpoint, Runtime runtime) {
Object[] interceptors = {};
List<BObject> interceptorServices = new ArrayList<>();
BArray interceptorsArray = serviceEndpoint.getArrayValue(HttpConstants.ENDPOINT_CONFIG_INTERCEPTORS);

if (interceptorsArray != null) {
interceptors = interceptorsArray.getValues();
BMap listenerConfig = ((BMap) serviceEndpoint.getNativeData(SERVICE_ENDPOINT_CONFIG));
final CountDownLatch latch = new CountDownLatch(1);
final BArray[] interceptorResponse = new BArray[1];
Callback interceptorCallback = new Callback() {
@Override
public void notifySuccess(Object result) {
if (result instanceof BArray) {
interceptorResponse[0] = (BArray) result;
} else {
((BError) result).printStackTrace();

Check warning on line 1620 in native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java#L1620

Added line #L1620 was not covered by tests
}
latch.countDown();
}
@Override
public void notifyFailure(BError bError) {
bError.printStackTrace();
System.exit(1);
}

Check warning on line 1628 in native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java#L1626-L1628

Added lines #L1626 - L1628 were not covered by tests
};
if (listenerConfig != null && listenerConfig.get(ENDPOINT_CONFIG_INTERCEPTORS) != null) {
Object interceptorConfig = listenerConfig.get(ENDPOINT_CONFIG_INTERCEPTORS);
runtime.invokeMethodAsyncSequentially(serviceEndpoint, CREATE_INTERCEPTORS_FUNCTION_NAME, null, null,
interceptorCallback, null, PredefinedTypes.TYPE_ANY, interceptorConfig, true);
} else {
runtime.invokeMethodAsyncSequentially(serviceEndpoint, CREATE_INTERCEPTORS_FUNCTION_NAME, null, null,
interceptorCallback, null, PredefinedTypes.TYPE_ANY, null, true);
}

try {
latch.await();
} catch (InterruptedException exception) {
log.warn("Interrupted before receiving the interceptor response");

Check warning on line 1641 in native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java#L1640-L1641

Added lines #L1640 - L1641 were not covered by tests
}
if (interceptorResponse[0] == null) {
return;

Check warning on line 1644 in native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java#L1644

Added line #L1644 was not covered by tests
}
Object[] interceptors = interceptorResponse[0].getValues();
for (Object interceptor: interceptors) {
if (interceptor == null) {
break;
}
interceptorServices.add((BObject) interceptor);
}

serviceEndpoint.addNativeData(HttpConstants.INTERCEPTORS, interceptorsArray);
serviceEndpoint.addNativeData(HttpConstants.INTERCEPTORS, interceptorResponse[0]);
Register.resetInterceptorRegistry(serviceEndpoint, interceptorServices.size());
List<HTTPInterceptorServicesRegistry> httpInterceptorServicesRegistries
= Register.getHttpInterceptorServicesRegistries(serviceEndpoint);
Expand Down