diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..097f9f9
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,9 @@
+#
+# https://help.github.com/articles/dealing-with-line-endings/
+#
+# Linux start script should use lf
+/gradlew text eol=lf
+
+# These are Windows script files and should use crlf
+*.bat text eol=crlf
+
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..7cf4a91
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,7 @@
+# Lines starting with '#' are comments.
+# Each line is a file pattern followed by one or more owners.
+
+# See: https://help.github.com/articles/about-codeowners/
+
+# These owners will be the default owners for everything in the repo.
+* @Nuvindu
diff --git a/.github/workflows/build-timestamped-master.yml b/.github/workflows/build-timestamped-master.yml
new file mode 100644
index 0000000..176bab1
--- /dev/null
+++ b/.github/workflows/build-timestamped-master.yml
@@ -0,0 +1,19 @@
+name: Build
+
+on:
+ push:
+ branches:
+ - main
+ paths-ignore:
+ - '*.md'
+ - 'docs/**'
+ - 'load-tests/**'
+
+ workflow_dispatch:
+
+jobs:
+ call_workflow:
+ name: Run Build Workflow
+ if: ${{ github.repository_owner == 'ballerina-platform' }}
+ uses: ballerina-platform/ballerina-library/.github/workflows/build-timestamp-master-template.yml@main
+ secrets: inherit
diff --git a/.github/workflows/build-with-bal-test-graalvm.yml b/.github/workflows/build-with-bal-test-graalvm.yml
new file mode 100644
index 0000000..d8736ac
--- /dev/null
+++ b/.github/workflows/build-with-bal-test-graalvm.yml
@@ -0,0 +1,37 @@
+name: GraalVM Check
+
+on:
+ workflow_dispatch:
+ inputs:
+ lang_tag:
+ description: Branch/Release Tag of the Ballerina Lang
+ required: true
+ default: main
+ lang_version:
+ description: Ballerina Lang Version (If given ballerina lang build will be skipped)
+ required: false
+ default: ''
+ native_image_options:
+ description: Default native-image options
+ required: false
+ default: ''
+ schedule:
+ - cron: '30 18 * * *'
+ pull_request:
+ branches:
+ - main
+ types: [ opened, synchronize, reopened, labeled, unlabeled ]
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
+ cancel-in-progress: true
+
+jobs:
+ call_stdlib_workflow:
+ name: Run StdLib Workflow
+ if: ${{ github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository_owner == 'ballerina-platform') }}
+ uses: ballerina-platform/ballerina-library/.github/workflows/build-with-bal-test-graalvm-template.yml@main
+ with:
+ lang_tag: ${{ inputs.lang_tag }}
+ lang_version: ${{ inputs.lang_version }}
+ native_image_options: '-J-Xmx7G ${{ inputs.native_image_options }}'
diff --git a/.github/workflows/central-publish.yml b/.github/workflows/central-publish.yml
new file mode 100644
index 0000000..cca0723
--- /dev/null
+++ b/.github/workflows/central-publish.yml
@@ -0,0 +1,21 @@
+name: Publish to the Ballerina central
+
+on:
+ workflow_dispatch:
+ inputs:
+ environment:
+ type: choice
+ description: Select Environment
+ required: true
+ options:
+ - DEV CENTRAL
+ - STAGE CENTRAL
+
+jobs:
+ call_workflow:
+ name: Run Central Publish Workflow
+ if: ${{ github.repository_owner == 'ballerina-platform' }}
+ uses: ballerina-platform/ballerina-library/.github/workflows/central-publish-template.yml@main
+ secrets: inherit
+ with:
+ environment: ${{ github.event.inputs.environment }}
diff --git a/.github/workflows/fossa_scan.yml b/.github/workflows/fossa_scan.yml
new file mode 100644
index 0000000..651f73a
--- /dev/null
+++ b/.github/workflows/fossa_scan.yml
@@ -0,0 +1,16 @@
+name: Fossa Scan
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: '30 18 * * *' # 00:00 in LK time (GMT+5:30)
+jobs:
+ fossa-scan:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: fossas/fossa-action@main
+ env:
+ packageUser: ${{ secrets.BALLERINA_BOT_USERNAME }}
+ packagePAT: ${{ secrets.BALLERINA_BOT_TOKEN }}
+ with:
+ api-key: ${{secrets.FOSSA_APIKEY}}
diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml
index b174594..d886096 100644
--- a/.github/workflows/publish-release.yml
+++ b/.github/workflows/publish-release.yml
@@ -1,59 +1,16 @@
-name: Publish release
+name: Publish Release
on:
- workflow_dispatch:
- repository_dispatch:
- types: [stdlib-release-pipeline]
+ workflow_dispatch:
+ repository_dispatch:
+ types: [ stdlib-release-pipeline ]
jobs:
- publish-release:
- runs-on: ubuntu-latest
- if: github.repository_owner == 'ballerina-platform'
-
- steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 11
- uses: actions/setup-java@v1
+ call_workflow:
+ name: Run Release Workflow
+ if: ${{ github.repository_owner == 'ballerina-platform' }}
+ uses: ballerina-platform/ballerina-library/.github/workflows/release-package-template.yml@main
+ secrets: inherit
with:
- java-version: 11
- - name: Set version env variable
- run: echo "VERSION=$((grep -w 'version' | cut -d= -f2) < gradle.properties | cut -d- -f1)" >> $GITHUB_ENV
- - name: Pre release depenency version update
- env:
- GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }}
- run: |
- echo "Version: ${VERSION}"
- git config user.name ${{ secrets.BALLERINA_BOT_USERNAME }}
- git config user.email ${{ secrets.BALLERINA_BOT_EMAIL }}
- git checkout -b release-${VERSION}
- sed -i 's/ballerinaLangVersion=\(.*\)-SNAPSHOT/ballerinaLangVersion=\1/g' gradle.properties
- sed -i 's/stdlib\(.*\)=\(.*\)-SNAPSHOT/stdlib\1=\2/g' gradle.properties
- git add gradle.properties
- git commit -m "Move dependencies to stable version" || echo "No changes to commit"
- - name: Grant execute permission for gradlew
- run: chmod +x gradlew
- - name: Publish artifact
- env:
- GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }}
- BALLERINA_CENTRAL_ACCESS_TOKEN: ${{ secrets.BALLERINA_CENTRAL_ACCESS_TOKEN }}
- packageUser: ${{ secrets.BALLERINA_BOT_USERNAME }}
- packagePAT: ${{ secrets.BALLERINA_BOT_TOKEN }}
- run: |
- ./gradlew release -Prelease.useAutomaticVersion=true
- ./gradlew -Pversion=${VERSION} publish -x test
- - name: Create Github release from the release tag
- run: |
- curl --request POST 'https://api.github.com/repos/ballerina-platform/module-ballerina-ldap/releases' \
- --header 'Accept: application/vnd.github.v3+json' \
- --header 'Authorization: Bearer ${{ secrets.BALLERINA_BOT_TOKEN }}' \
- --header 'Content-Type: application/json' \
- --data-raw '{
- "tag_name": "v'"$VERSION"'",
- "name": "module-ballerina-ldap-v'"$VERSION"'"
- }'
- - name: Post release PR
- env:
- GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }}
- run: |
- curl -fsSL https://github.com/github/hub/raw/master/script/get | bash -s 2.14.1
- bin/hub pull-request -m "[Automated] Sync master after "$VERSION" release"
+ package-name: ldap
+ package-org: ballerina
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 8ab26fa..d8c58cb 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -1,36 +1,14 @@
-name: PR build
+name: Pull Request
-on: [push, pull_request]
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
+ cancel-in-progress: true
-jobs:
- ubuntu-build:
-
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v1
- - name: Set up JDK 11
- uses: actions/setup-java@v1
- with:
- java-version: 11
- - name: Build with Gradle
- env:
- packageUser: ${{ github.actor }}
- packagePAT: ${{ secrets.GITHUB_TOKEN }}
- run: ./gradlew build
+on: pull_request
- windows-build:
-
- runs-on: windows-latest
-
- steps:
- - uses: actions/checkout@v1
- - name: Set up JDK 11
- uses: actions/setup-java@v1
- with:
- java-version: 11
- - name: Build with Gradle
- env:
- packageUser: ${{ github.actor }}
- packagePAT: ${{ secrets.GITHUB_TOKEN }}
- run: ./gradlew.bat build
+jobs:
+ call_workflow:
+ name: Run PR Build Workflow
+ if: ${{ github.repository_owner == 'ballerina-platform' }}
+ uses: ballerina-platform/ballerina-library/.github/workflows/pull-request-build-template.yml@main
+ secrets: inherit
diff --git a/.github/workflows/stale_check.yml b/.github/workflows/stale_check.yml
new file mode 100644
index 0000000..8763360
--- /dev/null
+++ b/.github/workflows/stale_check.yml
@@ -0,0 +1,19 @@
+name: 'Close stale pull requests'
+
+on:
+ schedule:
+ - cron: '30 19 * * *'
+ workflow_dispatch:
+
+jobs:
+ stale:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/stale@v3
+ with:
+ stale-pr-message: 'This PR has been open for more than 15 days with no activity. This will be closed in 3 days unless the `stale` label is removed or commented.'
+ close-pr-message: 'Closed PR due to inactivity for more than 18 days.'
+ days-before-pr-stale: 15
+ days-before-pr-close: 3
+ days-before-issue-stale: -1
+ days-before-issue-close: -1
diff --git a/.github/workflows/trivy-scan.yml b/.github/workflows/trivy-scan.yml
new file mode 100644
index 0000000..12c95cc
--- /dev/null
+++ b/.github/workflows/trivy-scan.yml
@@ -0,0 +1,13 @@
+name: Trivy
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: "30 20 * * *"
+
+jobs:
+ call_workflow:
+ name: Run Trivy Scan Workflow
+ if: ${{ github.repository_owner == 'ballerina-platform' }}
+ uses: ballerina-platform/ballerina-library/.github/workflows/trivy-scan-template.yml@main
+ secrets: inherit
diff --git a/.github/workflows/update-spec.yml b/.github/workflows/update-spec.yml
new file mode 100644
index 0000000..f9358ec
--- /dev/null
+++ b/.github/workflows/update-spec.yml
@@ -0,0 +1,48 @@
+name: Update Specifications
+
+env:
+ SPEC_FOLDER_PATH: 'docs/spec'
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - main
+ paths:
+ - 'docs/spec/**'
+
+jobs:
+ update_specs:
+ name: Update Specifications
+ if: github.repository_owner == 'ballerina-platform'
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@v3
+
+ - name: Get current date
+ id: date
+ run: echo "::set-output name=date::$(date +'%Y-%m-%d')"
+
+ - name: Get Repo Name
+ id: repo_name
+ run: |
+ MODULE=${{ github.event.repository.name }}
+ echo "::set-output name=short_name::${MODULE##*-}"
+
+ - name: Trigger Workflow
+ run: |
+ curl --request POST \
+ 'https://api.github.com/repos/ballerina-platform/ballerina-dev-website/dispatches' \
+ -H 'Accept: application/vnd.github.v3+json' \
+ -H 'Authorization: Bearer ${{ secrets.BALLERINA_BOT_TOKEN }}' \
+ --data "{
+ \"event_type\": \"update-stdlib-specs\",
+ \"client_payload\": {
+ \"module_name\": \"${{ github.event.repository.name }}\",
+ \"short_name\": \"${{ steps.repo_name.outputs.short_name }}\",
+ \"file_dir\": \"${{ github.event.repository.name }}/${{ env.SPEC_FOLDER_PATH }}\",
+ \"release_date\": \"${{ steps.date.outputs.date }}\"
+ }
+ }"
diff --git a/.gitignore b/.gitignore
index 85e001f..8b412be 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,9 @@
# Log file
*.log
+# Lock file
+*.lck
+
# BlueJ files
*.ctxt
@@ -11,6 +14,7 @@
.mtj.tmp/
# Package Files #
+!gradle/wrapper/gradle-wrapper.jar
*.jar
*.war
*.nar
@@ -19,21 +23,27 @@
*.tar.gz
*.rar
+# System files
+.DS_Store
+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
-build
-.gradle/
-target
-# IDEA Files
-.idea/
-*.iml
-*.ipr
-*.iws
+# IDE-related files
+.idea
+.code
+.project
+.settings
+.vscode
-# MacOS
-*.DS_Store
+# Build Files
+.gradle
+target
+build
+bin
# Ballerina
velocity.log*
*Ballerina.lock
+examples/**/Dependencies.toml
+Config.toml
diff --git a/README.md b/README.md
index 40f8e71..b3c4b89 100644
--- a/README.md
+++ b/README.md
@@ -1,69 +1,40 @@
-Ballerina LDAP Library
+Ballerina LDAP Connector
===================
- [![Build](https://github.com/ballerina-platform/module-ballerina-ldap/workflows/Build/badge.svg)](https://github.com/ballerina-platform/module-ballerina-ldap/actions?query=workflow%3ABuild)
- [![GitHub Last Commit](https://img.shields.io/github/last-commit/ballerina-platform/module-ballerina-ldap.svg?label=Last%20Commit)](https://github.com/ballerina-platform/module-ballerina-ldap/commits/master)
- [![Github issues](https://img.shields.io/github/issues/ballerina-platform/ballerina-standard-library/module/ldap.svg?label=Open%20Issues)](https://github.com/ballerina-platform/ballerina-standard-library/labels/module%2Fldap)
- [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
+LDAP (Lightweight Directory Access Protocol) is an vendor-neutral software protocol for accessing and maintaining distributed directory information services. It allows users to locate organizations, individuals, and other resources such as files and devices in a network. LDAP is used in various applications for directory-based authentication and authorization.
-The LDAP library is one of the standard library modules of the Ballerina language.
+The Ballerina LDAP module provides the capability to efficiently connect, authenticate, and interact with directory servers. It allows users to perform operations such as searching for entries, modifying entries in an LDAP directory, providing better support for directory-based operations.
-It provides an inbound LDAP authentication provider, which is used to authenticate using LDAP credentials.
+### APIs associated with LDAP
-For more information go to [The LDAP Module](https://ballerina.io/swan-lake/learn/api-docs/ballerina/ldap/index.html).
+- **modify**: Updates information of an entry in a directory server.
+- **getEntry**: Gets information of an entry in a directory server.
-For example demonstrations of the usage, go to [Ballerina By Examples](https://ballerina.io/swan-lake/learn/by-example/).
+#### `modify` API
-## Issues and Projects
+Updates information of an entry.
-Issues and Projects tabs are disabled for this repository as this is part of the Ballerina Standard Library. To report bugs, request new features, start new discussions, view project boards, etc. please visit Ballerina Standard Library [parent repository](https://github.com/ballerina-platform/ballerina-standard-library).
+```ballerina
+import ballerina/ldap;
-This repository only contains the source code for the module.
+public function main() returns error? {
+ anydata user = {
+ sn: "User",
+ givenName: "Updated User",
+ displayName: "Updated User"
+ };
+ _ = check ldapClient->modify(userDN, user);
+}
+```
-## Building from the Source
+#### `getEntry` API
-### Setting Up the Prerequisites
+Gets information of an entry
-1. Download and install Java SE Development Kit (JDK) version 11 (from one of the following locations).
+```ballerina
+import ballerina/ldap;
- * [Oracle](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html)
-
- * [OpenJDK](https://adoptopenjdk.net)
-
- > **Note:** Set the JAVA_HOME environment variable to the path name of the directory into which you installed JDK.
-
-### Building the Source
-
-Execute the commands below to build from the source.
-
-1. To build the library:
-
- ./gradlew clean build
-
-2. To run the tests:
-
- ./gradlew clean test
-
-3. To build the module without the tests:
-
- ./gradlew clean build -x test
-
-4. To debug the tests:
-
- ./gradlew clean test -Pdebug=
-
-## Contributing to Ballerina
-
-As an open source project, Ballerina welcomes contributions from the community.
-
-For more information, go to the [contribution guidelines](https://github.com/ballerina-platform/ballerina-lang/blob/master/CONTRIBUTING.md).
-
-## Code of Conduct
-
-All contributors are encouraged to read the [Ballerina Code of Conduct](https://ballerina.io/code-of-conduct).
-
-## Useful Links
-
-* Discuss about code changes of the Ballerina project in [ballerina-dev@googlegroups.com](mailto:ballerina-dev@googlegroups.com).
-* Chat live with us via our [Slack channel](https://ballerina.io/community/slack/).
-* Post all technical questions on Stack Overflow with the [#ballerina](https://stackoverflow.com/questions/tagged/ballerina) tag.
+public function main() returns error? {
+ anydata value = check ldapClient->getEntry(userDN);
+}
+```
diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml
new file mode 100644
index 0000000..99eab0c
--- /dev/null
+++ b/ballerina/Ballerina.toml
@@ -0,0 +1,25 @@
+[package]
+org = "ballerina"
+name = "ldap"
+version = "0.1.0"
+authors = ["Ballerina"]
+export=["ldap"]
+keywords = ["ldap"]
+repository = "https://github.com/ballerina-platform/module-ballerina-ldap"
+license = ["Apache-2.0"]
+distribution = "2201.8.6"
+
+[platform.java17]
+graalvmCompatible = true
+
+[[platform.java17.dependency]]
+groupId = "io.ballerina.lib"
+artifactId = "ldap-native"
+version = "0.1.0"
+path = "../native/build/libs/ldap-native-0.1.0-SNAPSHOT.jar"
+
+[[platform.java17.dependency]]
+groupId = "com.unboundid"
+artifactId = "unboundid-ldapsdk"
+version = "7.0.0"
+path = "./lib/unboundid-ldapsdk-7.0.0.jar"
diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml
new file mode 100644
index 0000000..4075832
--- /dev/null
+++ b/ballerina/Dependencies.toml
@@ -0,0 +1,51 @@
+# AUTO-GENERATED FILE. DO NOT MODIFY.
+
+# This file is auto-generated by Ballerina for managing dependency versions.
+# It should not be modified by hand.
+
+[ballerina]
+dependencies-toml-version = "2"
+distribution-version = "2201.8.6"
+
+[[package]]
+org = "ballerina"
+name = "jballerina.java"
+version = "0.0.0"
+modules = [
+ {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"}
+]
+
+[[package]]
+org = "ballerina"
+name = "lang.error"
+version = "0.0.0"
+scope = "testOnly"
+dependencies = [
+ {org = "ballerina", name = "jballerina.java"}
+]
+
+[[package]]
+org = "ballerina"
+name = "ldap"
+version = "0.1.0"
+dependencies = [
+ {org = "ballerina", name = "jballerina.java"},
+ {org = "ballerina", name = "test"}
+]
+modules = [
+ {org = "ballerina", packageName = "ldap", moduleName = "ldap"}
+]
+
+[[package]]
+org = "ballerina"
+name = "test"
+version = "0.0.0"
+scope = "testOnly"
+dependencies = [
+ {org = "ballerina", name = "jballerina.java"},
+ {org = "ballerina", name = "lang.error"}
+]
+modules = [
+ {org = "ballerina", packageName = "test", moduleName = "test"}
+]
+
diff --git a/ballerina/Module.md b/ballerina/Module.md
new file mode 100644
index 0000000..19c81eb
--- /dev/null
+++ b/ballerina/Module.md
@@ -0,0 +1,39 @@
+## Overview
+
+LDAP (Lightweight Directory Access Protocol) is an vendor-neutral software protocol for accessing and maintaining distributed directory information services. It allows users to locate organizations, individuals, and other resources such as files and devices in a network. LDAP is used in various applications for directory-based authentication and authorization.
+
+The Ballerina LDAP module provides the capability to efficiently connect, authenticate, and interact with directory servers. It allows users to perform operations such as searching for entries, modifying entries in an LDAP directory, providing better support for directory-based operations.
+
+### APIs associated with LDAP
+
+- **modify**: Updates information of an entry in a directory server.
+- **getEntry**: Gets information of an entry in a directory server.
+
+#### `modify` API
+
+Updates information of an entry.
+
+```ballerina
+import ballerina/ldap;
+
+public function main() returns error? {
+ anydata user = {
+ sn: "User",
+ givenName: "Updated User",
+ displayName: "Updated User"
+ };
+ _ = check ldapClient->modify(userDN, user);
+}
+```
+
+#### `getEntry` API
+
+Gets information of an entry
+
+```ballerina
+import ballerina/ldap;
+
+public function main() returns error? {
+ anydata value = check ldapClient->getEntry(userDN);
+}
+```
diff --git a/ballerina/Package.md b/ballerina/Package.md
new file mode 100644
index 0000000..19c81eb
--- /dev/null
+++ b/ballerina/Package.md
@@ -0,0 +1,39 @@
+## Overview
+
+LDAP (Lightweight Directory Access Protocol) is an vendor-neutral software protocol for accessing and maintaining distributed directory information services. It allows users to locate organizations, individuals, and other resources such as files and devices in a network. LDAP is used in various applications for directory-based authentication and authorization.
+
+The Ballerina LDAP module provides the capability to efficiently connect, authenticate, and interact with directory servers. It allows users to perform operations such as searching for entries, modifying entries in an LDAP directory, providing better support for directory-based operations.
+
+### APIs associated with LDAP
+
+- **modify**: Updates information of an entry in a directory server.
+- **getEntry**: Gets information of an entry in a directory server.
+
+#### `modify` API
+
+Updates information of an entry.
+
+```ballerina
+import ballerina/ldap;
+
+public function main() returns error? {
+ anydata user = {
+ sn: "User",
+ givenName: "Updated User",
+ displayName: "Updated User"
+ };
+ _ = check ldapClient->modify(userDN, user);
+}
+```
+
+#### `getEntry` API
+
+Gets information of an entry
+
+```ballerina
+import ballerina/ldap;
+
+public function main() returns error? {
+ anydata value = check ldapClient->getEntry(userDN);
+}
+```
diff --git a/ballerina/build.gradle b/ballerina/build.gradle
new file mode 100644
index 0000000..7415234
--- /dev/null
+++ b/ballerina/build.gradle
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 LLC. licenses this file to you 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.
+ */
+
+import org.apache.tools.ant.taskdefs.condition.Os
+
+plugins {
+ id 'io.ballerina.plugin'
+}
+
+description = 'LDAP - Ballerina'
+
+def packageName = "ldap"
+def packageOrg = "ballerina"
+def tomlVersion = stripBallerinaExtensionVersion("${project.version}")
+def ballerinaTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/Ballerina.toml")
+def ballerinaTomlFile = new File("$project.projectDir/Ballerina.toml")
+
+def stripBallerinaExtensionVersion(String extVersion) {
+ if (extVersion.matches(project.ext.timestampedVersionRegex)) {
+ def splitVersion = extVersion.split('-')
+ if (splitVersion.length > 3) {
+ def strippedValues = splitVersion[0..-4]
+ return strippedValues.join('-')
+ } else {
+ return extVersion
+ }
+ } else {
+ return extVersion.replace("${project.ext.snapshotVersion}", "")
+ }
+}
+
+ballerina {
+ packageOrganization = packageOrg
+ module = packageName
+ testCoverageParam = "--code-coverage --coverage-format=xml"
+ isConnector = true
+ langVersion = ballerinaLangVersion
+ platform = "java17"
+}
+
+configurations {
+ externalJars
+ jbalTools
+ ballerinaStdLibs
+}
+
+dependencies {
+ jbalTools("org.ballerinalang:jballerina-tools:${ballerinaLangVersion}") {
+ transitive = false
+ }
+ externalJars(group: 'com.unboundid', name: 'unboundid-ldapsdk', version: "${unboundIdLdapVersion}") {
+ transitive = false
+ }
+}
+
+task updateTomlFiles {
+ doLast {
+ def newBallerinaToml = ballerinaTomlFilePlaceHolder.text.replace("@project.version@", project.version)
+ newBallerinaToml = newBallerinaToml.replace("@toml.version@", tomlVersion)
+ ballerinaTomlFile.text = newBallerinaToml
+ }
+}
+
+task commitTomlFiles {
+ doLast {
+ project.exec {
+ ignoreExitValue true
+ if (Os.isFamily(Os.FAMILY_WINDOWS)) {
+ commandLine 'cmd', '/c', "git commit -m \"[Automated] Update the toml files\" Ballerina.toml Dependencies.toml"
+ } else {
+ commandLine 'sh', '-c', "git commit -m '[Automated] Update the toml files' Ballerina.toml Dependencies.toml"
+ }
+ }
+ }
+}
+
+clean {
+ delete 'build'
+}
+
+updateTomlFiles.dependsOn copyStdlibs
+build.dependsOn copyToLib
+
+test.dependsOn ":${packageName}-native:build"
+build.dependsOn ":${packageName}-native:build"
+
+publishToMavenLocal.dependsOn build
+publish.dependsOn build
diff --git a/ballerina/client.bal b/ballerina/client.bal
new file mode 100644
index 0000000..46a4369
--- /dev/null
+++ b/ballerina/client.bal
@@ -0,0 +1,53 @@
+// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
+//
+// WSO2 LLC. licenses this file to you 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.
+
+import ballerina/jballerina.java;
+
+# Consists of APIs to integrate with LDAP.
+public isolated client class Client {
+
+ # Gets invoked to initialize the LDAP client.
+ #
+ # + config - The configurations to be used when initializing the client
+ # + return - An error if client initialization failed
+ public isolated function init(*ConnectionConfig config) returns Error? {
+ check self.initLdapConnection(config);
+ }
+
+ private isolated function initLdapConnection(ConnectionConfig config) returns Error? = @java:Method {
+ 'class: "io.ballerina.lib.ldap.Ldap"
+ } external;
+
+ # Updates information of an entry.
+ #
+ # + distinguishedName - The distinguished name of the entry
+ # + entry - The information to update
+ # + return - `error` if the operation fails or `()` if successfully updated
+ remote isolated function modify(string distinguishedName, record {|anydata...;|} entry)
+ returns LDAPResponse|Error = @java:Method {
+ 'class: "io.ballerina.lib.ldap.Ldap"
+ } external;
+
+ # Gets information of an entry.
+ #
+ # + distinguishedName - The distinguished name of the entry
+ # + targetType - Default parameter use to infer the user specified type
+ # + return - An entry result with the given type or else an error
+ remote isolated function getEntry(string distinguishedName, typedesc targetType = <>)
+ returns targetType|Error = @java:Method {
+ 'class: "io.ballerina.lib.ldap.Ldap"
+ } external;
+}
diff --git a/ballerina/error.bal b/ballerina/error.bal
new file mode 100644
index 0000000..1bc0c1c
--- /dev/null
+++ b/ballerina/error.bal
@@ -0,0 +1,27 @@
+// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com).
+//
+// WSO2 LLC. licenses this file to you 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.
+
+# Represents any error related to Ballerina LDAP module
+public type Error distinct error;
+
+# The error details type for the Ballerina LDAP module.
+#
+# + resultStatus - The status of the error
+# + message - The error message
+public type ErrorDetails record {|
+ string resultStatus?;
+ string message?;
+|};
diff --git a/ballerina/init.bal b/ballerina/init.bal
new file mode 100644
index 0000000..48ef117
--- /dev/null
+++ b/ballerina/init.bal
@@ -0,0 +1,25 @@
+// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com).
+//
+// WSO2 LLC. licenses this file to you 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.
+
+import ballerina/jballerina.java;
+
+function init() {
+ setModule();
+}
+
+function setModule() = @java:Method {
+ 'class: "io.ballerina.lib.ldap.ModuleUtils"
+} external;
diff --git a/ballerina/tests/test.bal b/ballerina/tests/test.bal
new file mode 100644
index 0000000..4d40e6e
--- /dev/null
+++ b/ballerina/tests/test.bal
@@ -0,0 +1,87 @@
+// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
+//
+// WSO2 LLC. licenses this file to you 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.
+
+import ballerina/test;
+
+configurable string hostName = ?;
+configurable int port = ?;
+configurable string domainName = ?;
+configurable string password = ?;
+configurable string userDN = ?;
+
+Client ldapClient = check new ({
+ hostName: hostName,
+ port: port,
+ domainName: domainName,
+ password: password
+});
+
+@test:Config {}
+public function testUpdateUser() returns error? {
+ record {} user = {
+ "sn": "User",
+ "givenName": "Updated User",
+ "displayName": "Updated User"
+ };
+ LDAPResponse val = check ldapClient->modify(userDN, user);
+ test:assertEquals(val.resultStatus, SUCCESS);
+}
+
+@test:Config {
+ dependsOn: [testUpdateUser]
+}
+public function testGetUser() returns error? {
+ UserConfig value = check ldapClient->getEntry(userDN);
+ test:assertEquals(value?.givenName, "Updated User");
+}
+
+@test:Config {}
+public function testInvalidClient() returns error? {
+ Client|Error ldapClient = new ({
+ hostName: "111.111.11.111",
+ port: port,
+ domainName: domainName,
+ password: password
+ });
+ test:assertTrue(ldapClient is Error);
+}
+
+@test:Config {}
+public function testInvalidDomainInClient() returns error? {
+ Client|Error ldapClient = new ({
+ hostName: hostName,
+ port: port,
+ domainName: "invalid@ad.invalid",
+ password: password
+ });
+ test:assertTrue(ldapClient is Error);
+}
+
+@test:Config {}
+public function testGetInvalidUser() returns error? {
+ UserConfig|Error value = ldapClient->getEntry("CN=Invalid User,OU=People,DC=ad,DC=windows");
+ test:assertTrue(value is Error);
+}
+
+@test:Config {}
+public function testUpdateUserWithNullValues() returns error? {
+ string distinguishedName = "CN=John Doe,OU=People,DC=ad,DC=windows";
+ record {} user = {
+ "employeeId":"30896","givenName":"John","sn":"Doe","company":"Grocery Co. USA","co":null,"streetAddress":null,"mobile":null,"displayName":"John Doe","middleName":null,"mail":null,"l":null,"telephoneNumber":null,"department":"Produce","st":null,"title":"Clerk"
+ };
+ LDAPResponse val = check ldapClient->modify(distinguishedName, user);
+ test:assertEquals(val.resultStatus, SUCCESS);
+}
diff --git a/ballerina/tests/types.bal b/ballerina/tests/types.bal
new file mode 100644
index 0000000..506035f
--- /dev/null
+++ b/ballerina/tests/types.bal
@@ -0,0 +1,39 @@
+// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
+//
+// WSO2 LLC. licenses this file to you 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.
+
+type UserConfig record {
+ string userPrincipalName?;
+ string givenName?;
+ string sn?;
+ string company?;
+ string co?;
+ string streetAddress?;
+ string mobile?;
+ string displayName?;
+ string middleName?;
+ string employeeId?;
+ string extensionAttribute11?;
+ string extensionAttribute10?;
+ string postalCode?;
+ string mail?;
+ string l?;
+ string telephoneNumber?;
+ string department?;
+ string st?;
+ string title?;
+ string distinguishedName?;
+ string manager?;
+};
diff --git a/ballerina/types.bal b/ballerina/types.bal
new file mode 100644
index 0000000..7aa7b06
--- /dev/null
+++ b/ballerina/types.bal
@@ -0,0 +1,82 @@
+// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
+//
+// WSO2 LLC. licenses this file to you 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.
+
+# Provides a set of configurations to control the behaviours when communicating with a schema registry.
+#
+# + hostName - The host name of the Active Directory server
+# + port - The port of the Active Directory server
+# + domainName - The domain name of the Active Directory
+# + password - The password of the Active Directory
+public type ConnectionConfig record {|
+ string hostName;
+ int port;
+ string domainName;
+ string password;
+|};
+
+# LDAP response type.
+#
+# + matchedDN - The matched DN from the response
+# + resultStatus - The operation status of the response
+# + operationType - The protocol operation type
+public type LDAPResponse record {|
+ string matchedDN;
+ Status resultStatus;
+ string operationType;
+|};
+
+# Represents the status of the operation
+public enum Status {
+ SUCCESS,
+ OPERATIONS_ERROR,
+ PROTOCOL_ERROR,
+ TIME_LIMIT_EXCEEDED,
+ SIZE_LIMIT_EXCEEDED,
+ COMPARE_FALSE,
+ COMPARE_TRUE,
+ AUTH_METHOD_NOT_SUPPORTED,
+ STRONGER_AUTH_REQUIRED,
+ REFERRAL,
+ ADMIN_LIMIT_EXCEEDED,
+ UNAVAILABLE_CRITICAL_EXTENSION,
+ CONFIDENTIALITY_REQUIRED,
+ SASL_BIND_IN_PROGRESS,
+ NO_SUCH_ATTRIBUTE,
+ UNDEFINED_ATTRIBUTE_TYPE,
+ INAPPROPRIATE_MATCHING,
+ CONSTRAINT_VIOLATION,
+ ATTRIBUTE_OR_VALUE_EXISTS,
+ INVALID_ATTRIBUTE_SYNTAX,
+ NO_SUCH_OBJECT,
+ ALIAS_PROBLEM,
+ INVALID_DN_SYNTAX,
+ ALIAS_DEREFERENCING_PROBLEM,
+ INAPPROPRIATE_AUTHENTICATION,
+ INVALID_CREDENTIALS,
+ INSUFFICIENT_ACCESS_RIGHTS,
+ BUSY,
+ UNAVAILABLE,
+ UNWILLING_TO_PERFORM,
+ LOOP_DETECT,
+ NAMING_VIOLATION,
+ OBJECT_CLASS_VIOLATION,
+ NOT_ALLOWED_ON_NON_LEAF,
+ NOT_ALLOWED_ON_RDN,
+ ENTRY_ALREADY_EXISTS,
+ OBJECT_CLASS_MODS_PROHIBITED,
+ AFFECTS_MULTIPLE_DSAS,
+ OTHER
+};
diff --git a/build-config/checkstyle/build.gradle b/build-config/checkstyle/build.gradle
index 8295132..ac499db 100644
--- a/build-config/checkstyle/build.gradle
+++ b/build-config/checkstyle/build.gradle
@@ -1,28 +1,31 @@
/*
- * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
+ * WSO2 LLC. licenses this file to you 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.
+ * 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.
*/
plugins {
id "de.undercouch.download"
}
-task downloadMultipleFiles(type: Download) {
+apply plugin: 'java'
+
+task downloadCheckstyleRuleFiles(type: Download) {
src([
- 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.3/checkstyle/checkstyle.xml',
- 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.3/checkstyle/suppressions.xml'
+ 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/checkstyle.xml',
+ 'https://raw.githubusercontent.com/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/suppressions.xml'
])
overwrite false
onlyIfNewer true
@@ -38,9 +41,9 @@ clean {
}
artifacts.add('default', file("$project.buildDir/checkstyle.xml")) {
- builtBy('downloadMultipleFiles')
+ builtBy('downloadCheckstyleRuleFiles')
}
artifacts.add('default', file("$project.buildDir/suppressions.xml")) {
- builtBy('downloadMultipleFiles')
+ builtBy('downloadCheckstyleRuleFiles')
}
diff --git a/build-config/resources/Ballerina.toml b/build-config/resources/Ballerina.toml
new file mode 100644
index 0000000..7395042
--- /dev/null
+++ b/build-config/resources/Ballerina.toml
@@ -0,0 +1,25 @@
+[package]
+org = "ballerina"
+name = "ldap"
+version = "@toml.version@"
+authors = ["Ballerina"]
+export=["ldap"]
+keywords = ["ldap"]
+repository = "https://github.com/ballerina-platform/module-ballerina-ldap"
+license = ["Apache-2.0"]
+distribution = "2201.8.6"
+
+[platform.java17]
+graalvmCompatible = true
+
+[[platform.java17.dependency]]
+groupId = "io.ballerina.lib"
+artifactId = "ldap-native"
+version = "0.1.0"
+path = "../native/build/libs/ldap-native-0.1.0-SNAPSHOT.jar"
+
+[[platform.java17.dependency]]
+groupId = "com.unboundid"
+artifactId = "unboundid-ldapsdk"
+version = "7.0.0"
+path = "./lib/unboundid-ldapsdk-7.0.0.jar"
diff --git a/build.gradle b/build.gradle
index ad841f5..7391ae5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
*
- * WSO2 Inc. licenses this file to you under the Apache License,
+ * WSO2 LLC. licenses this file to you 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
@@ -16,27 +16,15 @@
* under the License.
*/
+import org.apache.tools.ant.taskdefs.condition.Os
+
plugins {
- id "com.github.spotbugs" version "4.0.5"
- id "com.github.johnrengelman.shadow" version "5.2.0"
- id "de.undercouch.download" version "4.0.4"
- id "net.researchgate.release" version "2.8.0"
+ id "com.github.johnrengelman.shadow"
+ id "de.undercouch.download"
+ id "net.researchgate.release"
}
-ext.puppycrawlCheckstyleVersion = project.puppycrawlCheckstyleVersion
-ext.slf4jVersion = project.slf4jVersion
-ext.ballerinaLangVersion = project.ballerinaLangVersion
-ext.stdlibAuthVersion = project.stdlibAuthVersion
-ext.stdlibCryptoVersion = project.stdlibCryptoVersion
-ext.stdlibLogVersion = project.stdlibLogVersion
-// Transitive dependencies
-ext.stdlibCacheVersion = project.stdlibCacheVersion
-ext.stdlibConfigVersion = project.stdlibConfigVersion
-ext.stdlibIoVersion = project.stdlibIoVersion
-ext.stdlibStringUtilsVersion = project.stdlibStringUtilsVersion
-ext.stdlibSystemVersion = project.stdlibSystemVersion
-ext.stdlibTaskVersion = project.stdlibTaskVersion
-ext.stdlibTimeVersion = project.stdlibTimeVersion
+description = 'Ballerina - Schema Registry'
allprojects {
group = project.group
@@ -47,15 +35,19 @@ allprojects {
repositories {
mavenLocal()
+ mavenCentral()
maven {
- url = 'https://maven.wso2.org/nexus/content/repositories/releases/'
+ url = 'https://maven.wso2.org/nexus/content/groups/wso2-public/'
}
+
maven {
- url = 'https://maven.wso2.org/nexus/content/groups/wso2-public/'
+ url = 'https://packages.confluent.io/maven/'
}
+
maven {
url = 'https://repo.maven.apache.org/maven2'
}
+
maven {
url = 'https://maven.pkg.github.com/ballerina-platform/ballerina-lang'
credentials {
@@ -63,141 +55,41 @@ allprojects {
password System.getenv("packagePAT")
}
}
- maven {
- url = 'https://maven.pkg.github.com/ballerina-platform/module-ballerina-auth'
- credentials {
- username System.getenv("packageUser")
- password System.getenv("packagePAT")
- }
- }
- maven {
- url = 'https://maven.pkg.github.com/ballerina-platform/module-ballerina-crypto'
- credentials {
- username System.getenv("packageUser")
- password System.getenv("packagePAT")
- }
- }
- maven {
- url = 'https://maven.pkg.github.com/ballerina-platform/module-ballerina-log'
- credentials {
- username System.getenv("packageUser")
- password System.getenv("packagePAT")
- }
- }
- // Transitive dependencies
- maven {
- url = 'https://maven.pkg.github.com/ballerina-platform/module-ballerina-cache'
- credentials {
- username System.getenv("packageUser")
- password System.getenv("packagePAT")
- }
- }
- maven {
- url = 'https://maven.pkg.github.com/ballerina-platform/module-ballerina-config'
- credentials {
- username System.getenv("packageUser")
- password System.getenv("packagePAT")
- }
- }
- maven {
- url = 'https://maven.pkg.github.com/ballerina-platform/module-ballerina-io'
- credentials {
- username System.getenv("packageUser")
- password System.getenv("packagePAT")
- }
- }
- maven {
- url = 'https://maven.pkg.github.com/ballerina-platform/module-ballerina-stringutils'
- credentials {
- username System.getenv("packageUser")
- password System.getenv("packagePAT")
- }
- }
- maven {
- url = 'https://maven.pkg.github.com/ballerina-platform/module-ballerina-system'
- credentials {
- username System.getenv("packageUser")
- password System.getenv("packagePAT")
- }
- }
- maven {
- url = 'https://maven.pkg.github.com/ballerina-platform/module-ballerina-task'
- credentials {
- username System.getenv("packageUser")
- password System.getenv("packagePAT")
- }
- }
- maven {
- url = 'https://maven.pkg.github.com/ballerina-platform/module-ballerina-time'
- credentials {
- username System.getenv("packageUser")
- password System.getenv("packagePAT")
- }
- }
+ }
+
+ ext {
+ snapshotVersion = '-SNAPSHOT'
+ timestampedVersionRegex = '.*-\\d{8}-\\d{6}-\\w.*\$'
}
}
subprojects {
- apply plugin: 'java'
-
configurations {
ballerinaStdLibs
+ jbalTools
}
dependencies {
- /* Standard libraries */
- ballerinaStdLibs "org.ballerinalang:auth-ballerina:${stdlibAuthVersion}"
- ballerinaStdLibs "org.ballerinalang:crypto-ballerina:${stdlibCryptoVersion}"
- ballerinaStdLibs "org.ballerinalang:log-ballerina:${stdlibLogVersion}"
- // Transitive dependencies
- ballerinaStdLibs "org.ballerinalang:cache-ballerina:${stdlibCacheVersion}"
- ballerinaStdLibs "org.ballerinalang:config-ballerina:${stdlibConfigVersion}"
- ballerinaStdLibs "org.ballerinalang:io-ballerina:${stdlibIoVersion}"
- ballerinaStdLibs "org.ballerinalang:stringutils-ballerina:${stdlibStringUtilsVersion}"
- ballerinaStdLibs "org.ballerinalang:system-ballerina:${stdlibSystemVersion}"
- ballerinaStdLibs "org.ballerinalang:task-ballerina:${stdlibTaskVersion}"
- ballerinaStdLibs "org.ballerinalang:time-ballerina:${stdlibTimeVersion}"
+ /* JBallerina Tools */
+ jbalTools ("org.ballerinalang:jballerina-tools:${ballerinaLangVersion}") {
+ transitive = false
+ }
}
}
-def moduleVersion = project.version
-if (moduleVersion.indexOf('-') != -1) {
- moduleVersion = moduleVersion.substring(0, moduleVersion.indexOf('-'))
+task build {
+ dependsOn(":ldap-native:build")
+ dependsOn(":ldap-ballerina:build")
}
-release {
- failOnPublishNeeded = false
+def moduleVersion = project.version.replace("-SNAPSHOT", "")
+release {
buildTasks = ['build']
+ failOnSnapshotDependencies = true
versionPropertyFile = 'gradle.properties'
- tagTemplate = 'v$version'
-
+ tagTemplate = 'v${version}'
git {
requireBranch = "release-${moduleVersion}"
pushToRemote = 'origin'
}
}
-
-task build {
- dependsOn('ldap-ballerina:build')
-}
-
-task codeCoverageReport(type: JacocoReport) {
- executionData fileTree(project.rootDir.absolutePath).include("**/build/coverage-reports/*.exec")
-
- subprojects.each {
- sourceSets it.sourceSets.main
- }
-
- reports {
- xml.enabled = true
- html.enabled = true
- csv.enabled = true
- xml.destination = new File("${buildDir}/reports/jacoco/report.xml")
- html.destination = new File("${buildDir}/reports/jacoco/report.html")
- csv.destination = new File("${buildDir}/reports/jacoco/report.csv")
- }
-
- onlyIf = {
- true
- }
-}
diff --git a/gradle.properties b/gradle.properties
index 77b7e6e..ca0d88d 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,17 +1,13 @@
org.gradle.caching=true
-group=org.ballerinalang
-version=1.0.5-SNAPSHOT
-puppycrawlCheckstyleVersion=8.18
-slf4jVersion=1.7.30
-ballerinaLangVersion=2.0.0-Preview9-SNAPSHOT
-stdlibAuthVersion=1.0.5-SNAPSHOT
-stdlibCryptoVersion=1.0.5-SNAPSHOT
-stdlibLogVersion=1.0.5-SNAPSHOT
-# Transitive dependencies
-stdlibCacheVersion=2.0.5-SNAPSHOT
-stdlibConfigVersion=1.0.5-SNAPSHOT
-stdlibIoVersion=0.5.5-SNAPSHOT
-stdlibStringUtilsVersion=0.5.5-SNAPSHOT
-stdlibSystemVersion=0.6.5-SNAPSHOT
-stdlibTaskVersion=1.1.5-SNAPSHOT
-stdlibTimeVersion=1.0.6-SNAPSHOT
+group=io.ballerina.lib
+version=0.1.0-SNAPSHOT
+ballerinaLangVersion=2201.8.6
+
+checkstylePluginVersion=10.12.0
+spotbugsPluginVersion=5.0.14
+shadowJarPluginVersion=8.1.1
+downloadPluginVersion=5.4.0
+releasePluginVersion=2.8.0
+ballerinaGradlePluginVersion=2.2.4
+
+unboundIdLdapVersion=7.0.0
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4c5803d..9f4197d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index af6708f..0adc8e1 100755
--- a/gradlew
+++ b/gradlew
@@ -1,78 +1,127 @@
-#!/usr/bin/env sh
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# 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
+#
+# https://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.
+#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m"'
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,92 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=$((i+1))
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
fi
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 6d57edc..93e3f59 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,4 +1,20 @@
-@if "%DEBUG%" == "" @echo off
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -9,19 +25,23 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m"
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +55,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,38 +65,26 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/issue_template.md b/issue_template.md
index f275c80..52a7563 100644
--- a/issue_template.md
+++ b/issue_template.md
@@ -15,4 +15,4 @@
**Related Issues:**
-
\ No newline at end of file
+
diff --git a/native/build.gradle b/native/build.gradle
new file mode 100644
index 0000000..43416ce
--- /dev/null
+++ b/native/build.gradle
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
+ *
+ * WSO2 LLC. licenses this file to you 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.
+ */
+
+plugins {
+ id 'java'
+ id 'checkstyle'
+ id 'com.github.spotbugs'
+}
+
+description = 'Ballerina - LDAP Native'
+
+configurations {
+ dist {
+ transitive true
+ }
+}
+
+dependencies {
+ checkstyle project(":checkstyle")
+ checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}"
+
+ implementation group: 'org.ballerinalang', name: 'ballerina-runtime', version: "${ballerinaLangVersion}"
+ implementation group: 'com.unboundid', name: 'unboundid-ldapsdk', version: "${unboundIdLdapVersion}"
+}
+
+tasks.withType(JavaCompile) {
+ options.encoding = 'UTF-8'
+}
+
+test {
+ testLogging {
+ showStackTraces = true
+ showStandardStreams = true
+ events "failed"
+ exceptionFormat "full"
+ }
+ jacoco {
+ enabled = true
+ destinationFile = file("$buildDir/coverage-reports/jacoco.exec")
+ includeNoLocationClasses = true
+ }
+}
+
+spotbugsMain {
+ ignoreFailures = true
+ effort = "max"
+ reportLevel = "low"
+ reportsDir = file("$project.buildDir/reports/spotbugs")
+ def excludeFile = file("${rootDir}/build-config/spotbugs-exclude.xml")
+ if (excludeFile.exists()) {
+ it.excludeFilter = excludeFile
+ }
+ reports {
+ text.enabled = true
+ }
+}
+
+spotbugsTest {
+ enabled = false
+}
+
+tasks.withType(Checkstyle) {
+ exclude '**/module-info.java'
+}
+
+checkstyle {
+ toolVersion "${checkstylePluginVersion}"
+ configFile file("${rootDir}/build-config/checkstyle/build/checkstyle.xml")
+ configProperties = ["suppressionFile": file("${rootDir}/build-config/checkstyle/build/suppressions.xml")]
+}
+
+checkstyleMain.dependsOn ':checkstyle:downloadCheckstyleRuleFiles'
+
+jar {
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+ dependsOn configurations.dist
+ from { configurations.dist.collect { it.isDirectory() ? it : zipTree(it) } } {
+ exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA'
+ }
+}
+
+compileJava {
+ doFirst {
+ options.compilerArgs = [
+ '--module-path', classpath.asPath,
+ ]
+ classpath = files()
+ }
+}
diff --git a/native/src/main/java/io/ballerina/lib/ldap/Ldap.java b/native/src/main/java/io/ballerina/lib/ldap/Ldap.java
new file mode 100644
index 0000000..b279d71
--- /dev/null
+++ b/native/src/main/java/io/ballerina/lib/ldap/Ldap.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
+ *
+ * WSO2 LLC. licenses this file to you 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 io.ballerina.lib.ldap;
+
+import com.unboundid.ldap.sdk.Attribute;
+import com.unboundid.ldap.sdk.LDAPConnection;
+import com.unboundid.ldap.sdk.LDAPException;
+import com.unboundid.ldap.sdk.LDAPResult;
+import com.unboundid.ldap.sdk.Modification;
+import com.unboundid.ldap.sdk.ModificationType;
+import com.unboundid.ldap.sdk.ModifyRequest;
+import com.unboundid.ldap.sdk.SearchResultEntry;
+import com.unboundid.util.Base64;
+import io.ballerina.runtime.api.creators.ValueCreator;
+import io.ballerina.runtime.api.utils.StringUtils;
+import io.ballerina.runtime.api.utils.ValueUtils;
+import io.ballerina.runtime.api.values.BError;
+import io.ballerina.runtime.api.values.BMap;
+import io.ballerina.runtime.api.values.BObject;
+import io.ballerina.runtime.api.values.BString;
+import io.ballerina.runtime.api.values.BTypedesc;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.unboundid.ldap.sdk.ResultCode.NO_SUCH_OBJECT;
+import static io.ballerina.lib.ldap.ModuleUtils.LDAP_RESPONSE;
+import static io.ballerina.lib.ldap.ModuleUtils.MATCHED_DN;
+import static io.ballerina.lib.ldap.ModuleUtils.OBJECT_GUID;
+import static io.ballerina.lib.ldap.ModuleUtils.OBJECT_SID;
+import static io.ballerina.lib.ldap.ModuleUtils.OPERATION_TYPE;
+import static io.ballerina.lib.ldap.ModuleUtils.RESULT_STATUS;
+import static io.ballerina.lib.ldap.Utils.ENTRY_NOT_FOUND;
+
+/**
+ * This class handles APIs of the LDAP client.
+ */
+public class Ldap {
+ private Ldap() {
+ }
+
+ public static BError initLdapConnection(BObject ldapClient, BMap config) {
+ String hostName = ((BString) config.get(ModuleUtils.HOST_NAME)).getValue();
+ int port = Math.toIntExact(config.getIntValue(ModuleUtils.PORT));
+ String domainName = ((BString) config.get(ModuleUtils.DOMAIN_NAME)).getValue();
+ String password = ((BString) config.get(ModuleUtils.PASSWORD)).getValue();
+ try {
+ LDAPConnection ldapConnection = new LDAPConnection(hostName, port, domainName, password);
+ ldapClient.addNativeData(ModuleUtils.NATIVE_CLIENT, ldapConnection);
+ } catch (LDAPException e) {
+ return Utils.createError(e.getMessage(), e);
+ }
+ return null;
+ }
+
+ public static Object modify(BObject ldapClient, BString distinguishedName, BMap entry) {
+ try {
+ LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(ModuleUtils.NATIVE_CLIENT);
+ List modificationList = entry.entrySet().stream()
+ .filter(e -> e.getValue() != null)
+ .map(e -> new Modification(ModificationType.REPLACE,
+ e.getKey().getValue(), e.getValue().getValue()))
+ .collect(Collectors.toList());
+ ModifyRequest modifyRequest = new ModifyRequest(distinguishedName.getValue(), modificationList);
+ LDAPResult ldapResult = ldapConnection.modify(modifyRequest);
+ return generateLdapResponse(ldapResult);
+ } catch (LDAPException e) {
+ return Utils.createError(e.getMessage(), e);
+ }
+ }
+
+ public static Object getEntry(BObject ldapClient, BString distinguishedName, BTypedesc typeParam) {
+ BMap entry = ValueCreator.createMapValue();
+ try {
+ LDAPConnection ldapConnection = (LDAPConnection) ldapClient.getNativeData(ModuleUtils.NATIVE_CLIENT);
+ SearchResultEntry userEntry = ldapConnection.getEntry(distinguishedName.getValue());
+ if (userEntry == null) {
+ return Utils.createError(ENTRY_NOT_FOUND + distinguishedName, new LDAPException(NO_SUCH_OBJECT));
+ }
+ for (Attribute attribute : userEntry.getAttributes()) {
+ processAttribute(attribute, entry);
+ }
+ return ValueUtils.convert(entry, typeParam.getDescribingType());
+ } catch (LDAPException e) {
+ return Utils.createError(e.getMessage(), e);
+ }
+ }
+
+ private static void processAttribute(Attribute attribute, BMap entry) {
+ BString attributeName = StringUtils.fromString(attribute.getName());
+ if (attribute.needsBase64Encoding()) {
+ String readableString = encodeAttributeValue(attribute);
+ entry.put(attributeName, StringUtils.fromString(readableString));
+ } else {
+ entry.put(attributeName, StringUtils.fromString(attribute.getValue()));
+ }
+ }
+
+ private static String encodeAttributeValue(Attribute attribute) {
+ byte[] valueBytes = attribute.getValueByteArray();
+ return switch (attribute.getName()) {
+ case OBJECT_GUID -> convertObjectGUIDToString(valueBytes);
+ case OBJECT_SID -> convertObjectSidToString(valueBytes);
+ default -> Base64.encode(valueBytes);
+ };
+ }
+
+ private static BMap generateLdapResponse(LDAPResult ldapResult) {
+ BMap response = ValueCreator.createRecordValue(ModuleUtils.getModule(), LDAP_RESPONSE);
+ response.put(StringUtils.fromString(MATCHED_DN), StringUtils.fromString(ldapResult.getMatchedDN()));
+ response.put(StringUtils.fromString(RESULT_STATUS),
+ StringUtils.fromString(ldapResult.getResultCode().getName().toUpperCase()));
+ response.put(StringUtils.fromString(OPERATION_TYPE),
+ StringUtils.fromString(ldapResult.getOperationType().name()));
+ return response;
+ }
+
+ public static String convertObjectSidToString(byte[] objectSid) {
+ int offset, size;
+ if (objectSid[0] != 1) {
+ throw new IllegalArgumentException("objectSid revision must be 1");
+ }
+ StringBuilder stringSidBuilder = new StringBuilder("S-1-");
+ int subAuthorityCount = objectSid[1] & 0xFF;
+ long identifierAuthority = 0;
+ offset = 2;
+ size = 6;
+ for (int i = 0; i < size; i++) {
+ identifierAuthority |= (long) (objectSid[offset + i] & 0xFF) << (8 * (size - 1 - i));
+ }
+ if (identifierAuthority < Math.pow(2, 32)) {
+ stringSidBuilder.append(identifierAuthority);
+ } else {
+ stringSidBuilder.append("0x").append(
+ Long.toHexString(identifierAuthority).toUpperCase());
+ }
+ offset = 8;
+ size = 4;
+ for (int i = 0; i < subAuthorityCount; i++, offset += size) {
+ long subAuthority = 0;
+ for (int j = 0; j < size; j++) {
+ subAuthority |= (long) (objectSid[offset + j] & 0xFF) << (8 * j);
+ }
+ stringSidBuilder.append("-").append(subAuthority);
+ }
+
+ return stringSidBuilder.toString();
+ }
+
+ public static String convertObjectGUIDToString(byte[] objectGUID) {
+ StringBuilder displayStr = new StringBuilder();
+ displayStr.append(prefixZeros((int) objectGUID[3] & 0xFF));
+ displayStr.append(prefixZeros((int) objectGUID[2] & 0xFF));
+ displayStr.append(prefixZeros((int) objectGUID[1] & 0xFF));
+ displayStr.append(prefixZeros((int) objectGUID[0] & 0xFF));
+ displayStr.append("-");
+ displayStr.append(prefixZeros((int) objectGUID[5] & 0xFF));
+ displayStr.append(prefixZeros((int) objectGUID[4] & 0xFF));
+ displayStr.append("-");
+ displayStr.append(prefixZeros((int) objectGUID[7] & 0xFF));
+ displayStr.append(prefixZeros((int) objectGUID[6] & 0xFF));
+ displayStr.append("-");
+ displayStr.append(prefixZeros((int) objectGUID[8] & 0xFF));
+ displayStr.append(prefixZeros((int) objectGUID[9] & 0xFF));
+ displayStr.append("-");
+ displayStr.append(prefixZeros((int) objectGUID[10] & 0xFF));
+ displayStr.append(prefixZeros((int) objectGUID[11] & 0xFF));
+ displayStr.append(prefixZeros((int) objectGUID[12] & 0xFF));
+ displayStr.append(prefixZeros((int) objectGUID[13] & 0xFF));
+ displayStr.append(prefixZeros((int) objectGUID[14] & 0xFF));
+ displayStr.append(prefixZeros((int) objectGUID[15] & 0xFF));
+ return displayStr.toString();
+ }
+
+
+ private static String prefixZeros(int value) {
+ if (value <= 0xF) {
+ StringBuilder sb = new StringBuilder("0");
+ sb.append(Integer.toHexString(value));
+
+ return sb.toString();
+
+ } else {
+ return Integer.toHexString(value);
+ }
+ }
+}
diff --git a/native/src/main/java/io/ballerina/lib/ldap/ModuleUtils.java b/native/src/main/java/io/ballerina/lib/ldap/ModuleUtils.java
new file mode 100644
index 0000000..1c566fd
--- /dev/null
+++ b/native/src/main/java/io/ballerina/lib/ldap/ModuleUtils.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
+ *
+ * WSO2 LLC. licenses this file to you 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 io.ballerina.lib.ldap;
+
+import io.ballerina.runtime.api.Environment;
+import io.ballerina.runtime.api.Module;
+import io.ballerina.runtime.api.utils.StringUtils;
+import io.ballerina.runtime.api.values.BString;
+
+/**
+ * Utility functions of the LDAP module.
+ *
+ * @since 0.1.0
+ */
+public final class ModuleUtils {
+
+ public static final BString HOST_NAME = StringUtils.fromString("hostName");
+ public static final BString PORT = StringUtils.fromString("port");
+ public static final BString DOMAIN_NAME = StringUtils.fromString("domainName");
+ public static final BString PASSWORD = StringUtils.fromString("password");
+
+ public static final String NATIVE_CLIENT = "client";
+ public static final String LDAP_RESPONSE = "LDAPResponse";
+ public static final String RESULT_STATUS = "resultStatus";
+ public static final String MATCHED_DN = "matchedDN";
+ public static final String OPERATION_TYPE = "operationType";
+
+ public static final String OBJECT_GUID = "objectGUID";
+ public static final String OBJECT_SID = "objectSid";
+
+ private ModuleUtils() {}
+
+ private static Module ldapModule = null;
+
+ public static Module getModule() {
+ return ldapModule;
+ }
+
+ public static void setModule(Environment env) {
+ ldapModule = env.getCurrentModule();
+ }
+}
diff --git a/native/src/main/java/io/ballerina/lib/ldap/Utils.java b/native/src/main/java/io/ballerina/lib/ldap/Utils.java
new file mode 100644
index 0000000..da72dea
--- /dev/null
+++ b/native/src/main/java/io/ballerina/lib/ldap/Utils.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
+ *
+ * WSO2 LLC. licenses this file to you 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 io.ballerina.lib.ldap;
+
+import com.unboundid.ldap.sdk.LDAPException;
+import io.ballerina.runtime.api.creators.ErrorCreator;
+import io.ballerina.runtime.api.creators.ValueCreator;
+import io.ballerina.runtime.api.values.BError;
+import io.ballerina.runtime.api.values.BMap;
+import io.ballerina.runtime.api.values.BString;
+
+import java.util.Map;
+
+import static io.ballerina.lib.ldap.ModuleUtils.getModule;
+import static io.ballerina.runtime.api.utils.StringUtils.fromString;
+
+/**
+ * This class contains utility methods for the Ballerina LDAP module.
+ */
+public final class Utils {
+
+ private Utils() {
+ }
+
+ public static final String ERROR_TYPE = "Error";
+ public static final String ERROR_DETAILS = "ErrorDetails";
+ public static final String RESULT_STATUS = "resultStatus";
+ public static final String ERROR_MESSAGE = "message";
+ public static final String ENTRY_NOT_FOUND = "LDAP entry is not found for DN: ";
+
+ public static BError createError(String message, Throwable throwable) {
+ BError cause = (throwable == null) ? null : ErrorCreator.createError(throwable);
+ BMap errorDetails = getErrorDetails(throwable);
+ return ErrorCreator.createError(getModule(), ERROR_TYPE, fromString(message), cause, errorDetails);
+ }
+
+ private static BMap getErrorDetails(Throwable throwable) {
+ if (throwable instanceof LDAPException) {
+ String resultStatus = ((LDAPException) throwable).getResultCode().getName();
+ String message = ((LDAPException) throwable).getExceptionMessage();
+ return ValueCreator.createRecordValue(getModule(), ERROR_DETAILS,
+ Map.of(RESULT_STATUS, resultStatus, ERROR_MESSAGE, message));
+ }
+ return ValueCreator.createRecordValue(getModule(), ERROR_DETAILS);
+ }
+}
diff --git a/native/src/main/java/module-info.java b/native/src/main/java/module-info.java
new file mode 100644
index 0000000..c59cbf2
--- /dev/null
+++ b/native/src/main/java/module-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
+ *
+ * WSO2 LLC. licenses this file to you 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.
+ */
+
+ module io.ballerina.lib.ldap {
+ requires io.ballerina.runtime;
+ requires unboundid.ldapsdk;
+}
diff --git a/pull_request_template.md b/pull_request_template.md
index 2b99160..731e098 100644
--- a/pull_request_template.md
+++ b/pull_request_template.md
@@ -1,52 +1,39 @@
-## Purpose
-> Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc.
+# Description
-## Goals
-> Describe the solutions that this feature/fix will introduce to resolve the problems described above
+Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
-## Approach
-> Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.
+Fixes # (issue)
-## User stories
-> Summary of user stories addressed by this change>
+Related Pull Requests (remove if not relevant)
+- Pull request 1
+- Pull request 2
-## Release note
-> Brief description of the new feature or bug fix as it will appear in the release notes
+One line release note:
+- One line describing the feature/improvement/fix made by this PR
-## Documentation
-> Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter “N/A” plus brief explanation of why there’s no doc impact
+## Type of change
-## Training
-> Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable
+Please delete options that are not relevant.
-## Certification
-> Type “Sent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type “N/A” and explain why.
+- [ ] Bug fix (non-breaking change which fixes an issue)
+- [ ] New feature (non-breaking change which adds functionality)
+- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
+- [ ] This change requires a documentation update
-## Marketing
-> Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable
+# How Has This Been Tested?
-## Automation tests
- - Unit tests
- > Code coverage information
- - Integration tests
- > Details about the test cases and coverage
+Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
-## Security checks
- - Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines? yes/no
- - Ran FindSecurityBugs plugin and verified report? yes/no
- - Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets? yes/no
+- [ ] Test A
+- [ ] Test B
-## Samples
-> Provide high-level details about the samples related to this feature
+**Test Configuration**:
+* Ballerina Version:
+* Operating System:
+* Java SDK:
-## Related PRs
-> List any other related PRs
+# Checklist:
-## Migrations (if applicable)
-> Describe migration steps and platforms on which migration has been tested
-
-## Test environment
-> List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested
-
-## Learning
-> Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem.
\ No newline at end of file
+### Security checks
+ - [ ] Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines?
+ - [ ] Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets?
diff --git a/settings.gradle b/settings.gradle
index 9ab5eec..87a72f2 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -2,18 +2,44 @@
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
- *
- * Detailed information about configuring a multi-project build in Gradle can be found
- * in the user manual at https://docs.gradle.org/6.3/userguide/multi_project_builds.html
+ * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.3/userguide/building_swift_projects.html in the Gradle documentation.
*/
+pluginManagement {
+ plugins {
+ id "com.github.spotbugs" version "${spotbugsPluginVersion}"
+ id "com.github.johnrengelman.shadow" version "${shadowJarPluginVersion}"
+ id "de.undercouch.download" version "${downloadPluginVersion}"
+ id "net.researchgate.release" version "${releasePluginVersion}"
+ id "io.ballerina.plugin" version "${ballerinaGradlePluginVersion}"
+ }
+
+ repositories {
+ gradlePluginPortal()
+ maven {
+ url = 'https://maven.pkg.github.com/ballerina-platform/*'
+ credentials {
+ username System.getenv("packageUser")
+ password System.getenv("packagePAT")
+ }
+ }
+ }
+}
+
plugins {
- id "com.gradle.enterprise" version "3.2"
+ id "com.gradle.enterprise" version "3.13.2"
}
-rootProject.name = 'ldap'
-include(':build-config:checkstyle')
-include ':ldap-native', ':ldap-ballerina'
+def projectName = 'ldap'
+rootProject.name = 'module-ballerina-ldap'
+
+include ":checkstyle"
+include ":${projectName}-native"
+include ":${projectName}-ballerina"
+
+project(':checkstyle').projectDir = file("build-config${File.separator}checkstyle")
+project(":${projectName}-native").projectDir = file('native')
+project(":${projectName}-ballerina").projectDir = file('ballerina')
gradleEnterprise {
buildScan {