diff --git a/README.md b/README.md index e75eaac..9b78515 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ This repository only contains the source code for the package. ### Prerequisites -1. Download and install Java SE Development Kit (JDK) version 17. You can download it from either of the following sources: +1. Download and install Java SE Development Kit (JDK) version 21. You can download it from either of the following sources: - [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) - [OpenJDK](https://adoptium.net/) diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml index 975285c..1a36948 100644 --- a/ballerina/Ballerina.toml +++ b/ballerina/Ballerina.toml @@ -9,16 +9,16 @@ repository = "https://github.com/ballerina-platform/module-ballerina-ldap" license = ["Apache-2.0"] distribution = "2201.9.0" -[platform.java17] +[platform.java21] graalvmCompatible = true -[[platform.java17.dependency]] +[[platform.java21.dependency]] groupId = "io.ballerina.lib" artifactId = "ldap-native" version = "1.1.0-SNAPSHOT" path = "../native/build/libs/ldap-native-1.1.0-SNAPSHOT.jar" -[[platform.java17.dependency]] +[[platform.java21.dependency]] groupId = "com.unboundid" artifactId = "unboundid-ldapsdk" version = "7.0.0" diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index 80b73fd..8594c70 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -5,12 +5,12 @@ [ballerina] dependencies-toml-version = "2" -distribution-version = "2201.9.0" +distribution-version = "2201.11.0-20241112-214900-6b80ab87" [[package]] org = "ballerina" name = "crypto" -version = "2.7.2" +version = "2.7.3" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "time"} @@ -92,7 +92,7 @@ modules = [ [[package]] org = "ballerina" name = "time" -version = "2.5.0" +version = "2.6.0" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] diff --git a/ballerina/build.gradle b/ballerina/build.gradle index 00e96e4..68e0729 100644 --- a/ballerina/build.gradle +++ b/ballerina/build.gradle @@ -49,7 +49,7 @@ ballerina { module = packageName testCoverageParam = "--code-coverage --coverage-format=xml" langVersion = ballerinaLangVersion - platform = "java17" + platform = "java21" } configurations { diff --git a/build-config/resources/Ballerina.toml b/build-config/resources/Ballerina.toml index 5b625b9..4673384 100644 --- a/build-config/resources/Ballerina.toml +++ b/build-config/resources/Ballerina.toml @@ -9,16 +9,16 @@ repository = "https://github.com/ballerina-platform/module-ballerina-ldap" license = ["Apache-2.0"] distribution = "2201.9.0" -[platform.java17] +[platform.java21] graalvmCompatible = true -[[platform.java17.dependency]] +[[platform.java21.dependency]] groupId = "io.ballerina.lib" artifactId = "ldap-native" version = "@project.version@" path = "../native/build/libs/ldap-native-@project.version@.jar" -[[platform.java17.dependency]] +[[platform.java21.dependency]] groupId = "com.unboundid" artifactId = "unboundid-ldapsdk" version = "@unboundIdLdap.version@" diff --git a/build.gradle b/build.gradle index 2f98e2c..b2fec17 100644 --- a/build.gradle +++ b/build.gradle @@ -78,6 +78,7 @@ subprojects { } /* Standard libraries */ + ballerinaStdLibs "io.ballerina.stdlib:io-ballerina:${stdlibIoVersion}" ballerinaStdLibs "io.ballerina.stdlib:crypto-ballerina:${stdlibCryptoVersion}" ballerinaStdLibs "io.ballerina.stdlib:time-ballerina:${stdlibTimeVersion}" } diff --git a/gradle.properties b/gradle.properties index 0f0ce4c..1511d18 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ org.gradle.caching=true group=io.ballerina.lib version=1.1.0-SNAPSHOT -ballerinaLangVersion=2201.9.0 +ballerinaLangVersion=2201.11.0-20241117-133400-a3054b77 checkstylePluginVersion=10.12.0 -spotbugsPluginVersion=5.0.14 +spotbugsPluginVersion=6.0.18 shadowJarPluginVersion=8.1.1 downloadPluginVersion=5.4.0 releasePluginVersion=2.8.0 @@ -12,5 +12,6 @@ ballerinaGradlePluginVersion=2.2.4 unboundIdLdapVersion=7.0.0 -stdlibCryptoVersion=2.7.2 -stdlibTimeVersion=2.5.0 +stdlibIoVersion=1.6.2-20240928-084100-656404f +stdlibCryptoVersion=2.7.3-20241113-081400-d015a39 +stdlibTimeVersion=2.6.0-20241113-073800-201b904 diff --git a/native/build.gradle b/native/build.gradle index c35728a..175ad03 100644 --- a/native/build.gradle +++ b/native/build.gradle @@ -57,8 +57,12 @@ test { } spotbugsMain { - effort "max" - reportLevel "low" + def classLoader = plugins["com.github.spotbugs"].class.classLoader + def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") + def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") + ignoreFailures = true + effort = SpotBugsEffort.MAX + reportLevel = SpotBugsConfidence.LOW reportsDir = file("$project.buildDir/reports/spotbugs") reports { html.enabled true diff --git a/native/src/main/java/io/ballerina/lib/ldap/Client.java b/native/src/main/java/io/ballerina/lib/ldap/Client.java index 341999f..886411f 100644 --- a/native/src/main/java/io/ballerina/lib/ldap/Client.java +++ b/native/src/main/java/io/ballerina/lib/ldap/Client.java @@ -45,9 +45,8 @@ import com.unboundid.util.ssl.TrustStoreTrustManager; import io.ballerina.lib.ldap.ssl.SSLConfig; import io.ballerina.runtime.api.Environment; -import io.ballerina.runtime.api.Future; -import io.ballerina.runtime.api.TypeTags; import io.ballerina.runtime.api.creators.ValueCreator; +import io.ballerina.runtime.api.types.TypeTags; import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.utils.TypeUtils; import io.ballerina.runtime.api.utils.ValueUtils; @@ -65,6 +64,7 @@ import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.concurrent.CompletableFuture; import static com.unboundid.ldap.sdk.ResultCode.NO_SUCH_OBJECT; import static com.unboundid.ldap.sdk.ResultCode.OTHER; @@ -223,83 +223,104 @@ private static AggregateTrustManager buildAggregatedTrustManager(SSLConfig sslCo } public static Object add(Environment env, BObject ldapClient, BString dN, BMap entry) { - Future future = env.markAsync(); - try { - LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); - validateConnection(ldapConnection); - AddRequest addRequest = generateAddRequest(dN, entry); - CustomAsyncResultListener customAsyncResultListener = new CustomAsyncResultListener(future); - ldapConnection.asyncAdd(addRequest, customAsyncResultListener); - } catch (LDAPException e) { - future.complete(Utils.createError(e.getMessage(), e)); - } - return null; + return env.yieldAndRun(() -> { + CompletableFuture future = new CompletableFuture<>(); + try { + LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); + validateConnection(ldapConnection); + AddRequest addRequest = generateAddRequest(dN, entry); + CustomAsyncResultListener customAsyncResultListener = new CustomAsyncResultListener(future); + ldapConnection.asyncAdd(addRequest, customAsyncResultListener); + return future.get(); + } catch (LDAPException e) { + return Utils.createError(e.getMessage(), e); + } catch (Throwable e) { + return Utils.createError(e.getMessage(), e); + } + }); } public static Object modify(Environment env, BObject ldapClient, BString dN, BMap entry) { - Future future = env.markAsync(); - try { - LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); - validateConnection(ldapConnection); - ModifyRequest modifyRequest = generateModifyRequest(dN, entry); - CustomAsyncResultListener customAsyncResultListener = new CustomAsyncResultListener(future); - ldapConnection.asyncModify(modifyRequest, customAsyncResultListener); - } catch (LDAPException e) { - future.complete(Utils.createError(e.getMessage(), e)); - } - return null; + return env.yieldAndRun(() -> { + CompletableFuture future = new CompletableFuture<>(); + try { + LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); + validateConnection(ldapConnection); + ModifyRequest modifyRequest = generateModifyRequest(dN, entry); + CustomAsyncResultListener customAsyncResultListener = new CustomAsyncResultListener(future); + ldapConnection.asyncModify(modifyRequest, customAsyncResultListener); + return future.get(); + } catch (LDAPException e) { + return Utils.createError(e.getMessage(), e); + } catch (Throwable e) { + return Utils.createError(e.getMessage(), e); + } + }); } public static Object modifyDn(Environment env, BObject ldapClient, BString currentDn, BString newRdn, boolean deleteOldRdn) { - Future future = env.markAsync(); - try { - LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); - validateConnection(ldapConnection); - ModifyDNRequest modifyRequest = new ModifyDNRequest(currentDn.getValue(), newRdn.getValue(), deleteOldRdn); - CustomAsyncResultListener customAsyncResultListener = new CustomAsyncResultListener(future); - ldapConnection.asyncModifyDN(modifyRequest, customAsyncResultListener); - } catch (LDAPException e) { - future.complete(Utils.createError(e.getMessage(), e)); - } - return null; + return env.yieldAndRun(() -> { + CompletableFuture future = new CompletableFuture<>(); + try { + LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); + validateConnection(ldapConnection); + ModifyDNRequest modifyRequest = + new ModifyDNRequest(currentDn.getValue(), newRdn.getValue(), deleteOldRdn); + CustomAsyncResultListener customAsyncResultListener = new CustomAsyncResultListener(future); + ldapConnection.asyncModifyDN(modifyRequest, customAsyncResultListener); + return future.get(); + } catch (LDAPException e) { + return Utils.createError(e.getMessage(), e); + } catch (Throwable e) { + return Utils.createError(e.getMessage(), e); + } + }); } public static Object delete(Environment env, BObject ldapClient, BString dN) { - Future future = env.markAsync(); - try { - LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); - validateConnection(ldapConnection); - CustomAsyncResultListener customAsyncResultListener = new CustomAsyncResultListener(future); - ldapConnection.asyncDelete(new DeleteRequest(dN.getValue()), customAsyncResultListener); - } catch (LDAPException e) { - future.complete(Utils.createError(e.getMessage(), e)); - } - return null; + return env.yieldAndRun(() -> { + CompletableFuture future = new CompletableFuture<>(); + try { + LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); + validateConnection(ldapConnection); + CustomAsyncResultListener customAsyncResultListener = new CustomAsyncResultListener(future); + ldapConnection.asyncDelete(new DeleteRequest(dN.getValue()), customAsyncResultListener); + return future.get(); + } catch (LDAPException e) { + return Utils.createError(e.getMessage(), e); + } catch (Throwable e) { + return Utils.createError(e.getMessage(), e); + } + }); } public static Object compare(Environment env, BObject ldapClient, BString dN, BString attributeName, BString assertionValue) { - Future future = env.markAsync(); - try { - LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); - validateConnection(ldapConnection); - CompareRequest compareRequest = new CompareRequest(dN.getValue(), attributeName.getValue(), - assertionValue.getValue()); - ldapConnection.asyncCompare(compareRequest, (requestID, compareResult) -> { - if (compareResult.getResultCode().equals(ResultCode.COMPARE_TRUE)) { - future.complete(true); - } else if (compareResult.getResultCode().equals(ResultCode.COMPARE_FALSE)) { - future.complete(false); - } else { - LDAPException ldapException = new LDAPException(compareResult); - future.complete(Utils.createError(ldapException.getMessage(), ldapException)); - } - }); - } catch (LDAPException e) { - future.complete(Utils.createError(e.getMessage(), e)); - } - return null; + return env.yieldAndRun(() -> { + try { + LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); + validateConnection(ldapConnection); + CompareRequest compareRequest = new CompareRequest(dN.getValue(), attributeName.getValue(), + assertionValue.getValue()); + CompletableFuture future = new CompletableFuture<>(); + ldapConnection.asyncCompare(compareRequest, (requestID, compareResult) -> { + if (compareResult.getResultCode().equals(ResultCode.COMPARE_TRUE)) { + future.complete(true); + } else if (compareResult.getResultCode().equals(ResultCode.COMPARE_FALSE)) { + future.complete(false); + } else { + LDAPException ldapException = new LDAPException(compareResult); + future.complete(Utils.createError(ldapException.getMessage(), ldapException)); + } + }); + return future.get(); + } catch (LDAPException e) { + return Utils.createError(e.getMessage(), e); + } catch (Throwable e) { + return Utils.createError(e.getMessage(), e); + } + }); } public static Object getEntry(BObject ldapClient, BString dN, BTypedesc typeParam) { @@ -321,37 +342,45 @@ public static Object getEntry(BObject ldapClient, BString dN, BTypedesc typePara } public static Object search(Environment env, BObject ldapClient, BString baseDn, BString filter, BString scope) { - Future future = env.markAsync(); - try { - SearchScope searchScope = getSearchScope(scope); - LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); - validateConnection(ldapConnection); - SearchResultListener searchResultListener = new CustomSearchResultListener(future, baseDn.getValue()); - SearchRequest searchRequest = new SearchRequest(searchResultListener, baseDn.getValue(), - searchScope, filter.getValue()); - ldapConnection.asyncSearch(searchRequest); - } catch (LDAPException e) { - future.complete(Utils.createError(e.getMessage(), e)); - } - return null; + return env.yieldAndRun(() -> { + CompletableFuture future = new CompletableFuture<>(); + try { + SearchScope searchScope = getSearchScope(scope); + LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); + validateConnection(ldapConnection); + SearchResultListener searchResultListener = new CustomSearchResultListener(future, baseDn.getValue()); + SearchRequest searchRequest = new SearchRequest(searchResultListener, baseDn.getValue(), + searchScope, filter.getValue()); + ldapConnection.asyncSearch(searchRequest); + return future.get(); + } catch (LDAPException e) { + return Utils.createError(e.getMessage(), e); + } catch (Throwable e) { + return Utils.createError(e.getMessage(), e); + } + }); } public static Object searchWithType(Environment env, BObject ldapClient, BString baseDn, BString filter, BString scope, BTypedesc typeParam) { - Future future = env.markAsync(); - try { - SearchScope searchScope = getSearchScope(scope); - LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); - validateConnection(ldapConnection); - SearchResultListener searchResultListener = new CustomSearchEntryListener(future, typeParam, - baseDn.getValue()); - SearchRequest searchRequest = new SearchRequest(searchResultListener, baseDn.getValue(), - searchScope, filter.getValue()); - ldapConnection.asyncSearch(searchRequest); - } catch (LDAPException e) { - future.complete(Utils.createError(e.getMessage(), e)); - } - return null; + return env.yieldAndRun(() -> { + CompletableFuture future = new CompletableFuture<>(); + try { + SearchScope searchScope = getSearchScope(scope); + LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(NATIVE_CLIENT); + validateConnection(ldapConnection); + SearchResultListener searchResultListener = new CustomSearchEntryListener(future, typeParam, + baseDn.getValue()); + SearchRequest searchRequest = new SearchRequest(searchResultListener, baseDn.getValue(), + searchScope, filter.getValue()); + ldapConnection.asyncSearch(searchRequest); + return future.get(); + } catch (LDAPException e) { + return Utils.createError(e.getMessage(), e); + } catch (Throwable e) { + return Utils.createError(e.getMessage(), e); + } + }); } public static void close(BObject ldapClient) { diff --git a/native/src/main/java/io/ballerina/lib/ldap/CustomAsyncResultListener.java b/native/src/main/java/io/ballerina/lib/ldap/CustomAsyncResultListener.java index 16c763e..f99a4eb 100644 --- a/native/src/main/java/io/ballerina/lib/ldap/CustomAsyncResultListener.java +++ b/native/src/main/java/io/ballerina/lib/ldap/CustomAsyncResultListener.java @@ -23,7 +23,8 @@ import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.LDAPResult; import com.unboundid.ldap.sdk.ResultCode; -import io.ballerina.runtime.api.Future; + +import java.util.concurrent.CompletableFuture; import static io.ballerina.lib.ldap.Client.generateLdapResponse; @@ -31,9 +32,9 @@ * Callback class to handle asynchronous operations. */ public class CustomAsyncResultListener implements AsyncResultListener { - private final Future future; + private final CompletableFuture future; - public CustomAsyncResultListener(Future future) { + public CustomAsyncResultListener(CompletableFuture future) { this.future = future; } diff --git a/native/src/main/java/io/ballerina/lib/ldap/CustomSearchEntryListener.java b/native/src/main/java/io/ballerina/lib/ldap/CustomSearchEntryListener.java index 33c3765..c92a863 100644 --- a/native/src/main/java/io/ballerina/lib/ldap/CustomSearchEntryListener.java +++ b/native/src/main/java/io/ballerina/lib/ldap/CustomSearchEntryListener.java @@ -26,7 +26,6 @@ import com.unboundid.ldap.sdk.SearchResult; import com.unboundid.ldap.sdk.SearchResultEntry; import com.unboundid.ldap.sdk.SearchResultReference; -import io.ballerina.runtime.api.Future; import io.ballerina.runtime.api.creators.ValueCreator; import io.ballerina.runtime.api.types.ArrayType; import io.ballerina.runtime.api.utils.ValueUtils; @@ -40,6 +39,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serial; +import java.util.concurrent.CompletableFuture; import static io.ballerina.lib.ldap.Client.processAttribute; import static io.ballerina.lib.ldap.Utils.ENTRY_NOT_FOUND; @@ -51,13 +51,13 @@ public class CustomSearchEntryListener implements AsyncSearchResultListener { @Serial private static final long serialVersionUID = 1L; - private transient Future future; + private transient CompletableFuture future; private transient BArray array; private transient BError error; private transient BTypedesc typeDesc; private final String dN; - public CustomSearchEntryListener(Future future, BTypedesc typeDesc, String dN) { + public CustomSearchEntryListener(CompletableFuture future, BTypedesc typeDesc, String dN) { this.future = future; this.array = ValueCreator.createArrayValue((ArrayType) typeDesc.getDescribingType()); this.dN = dN; @@ -113,7 +113,7 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound this.error = null; } - public void setFuture(Future future) { + public void setFuture(CompletableFuture future) { this.future = future; } diff --git a/native/src/main/java/io/ballerina/lib/ldap/CustomSearchResultListener.java b/native/src/main/java/io/ballerina/lib/ldap/CustomSearchResultListener.java index ee152ac..6d542f5 100644 --- a/native/src/main/java/io/ballerina/lib/ldap/CustomSearchResultListener.java +++ b/native/src/main/java/io/ballerina/lib/ldap/CustomSearchResultListener.java @@ -26,7 +26,6 @@ import com.unboundid.ldap.sdk.SearchResult; import com.unboundid.ldap.sdk.SearchResultEntry; import com.unboundid.ldap.sdk.SearchResultReference; -import io.ballerina.runtime.api.Future; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BString; @@ -36,6 +35,7 @@ import java.io.Serial; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; import static io.ballerina.lib.ldap.Client.processAttribute; import static io.ballerina.lib.ldap.Utils.ENTRY_NOT_FOUND; @@ -46,12 +46,12 @@ public class CustomSearchResultListener implements AsyncSearchResultListener { @Serial private static final long serialVersionUID = 1L; - private transient Future future; + private transient CompletableFuture future; private transient List> references; private transient List> entries; private final String dN; - public CustomSearchResultListener(Future future, String dN) { + public CustomSearchResultListener(CompletableFuture future, String dN) { this.dN = dN; this.future = future; this.references = new ArrayList<>(); @@ -100,7 +100,7 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound this.entries = new ArrayList<>(); } - public void setFuture(Future future) { + public void setFuture(CompletableFuture future) { this.future = future; } } diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml index b5d3519..7153752 100644 --- a/spotbugs-exclude.xml +++ b/spotbugs-exclude.xml @@ -19,4 +19,16 @@ + + + + + + + + + + + +